Packages

SDK

@dnax/[email protected] — Client-side SDK for the dnax REST API.

A lightweight, typed HTTP client for consuming the dnax REST API from any JavaScript or TypeScript environment (browser, Node.js, Bun, etc.).

Installation

bun add @dnax/[email protected]

Quick Start

import { Rest } from '@dnax/sdk';

const api = new Rest({
  server: 'http://localhost:5000',
  tenant: 'v1',
});

const users = await api.find('users');

Constructor

const api = new Rest(options: RestClientOptions);
OptionTypeDefaultDescription
serverstringBase URL of the dnax server (required)
tenantstringTenant ID (required)
headersRecord<string, string>{}Custom headers sent with every request
token{ persist?: boolean; storageKey?: string }JWT persistence in localStorage
token.persistbooleantrueSave the JWT token in localStorage after login
token.storageKeystring"dnax_token"Key used in localStorage for the token
const api = new Rest({
  server: 'https://api.example.com',
  tenant: 'v1',
  headers: {
    'X-Custom-Header': 'value',
  },
  token: {
    persist: true,
    storageKey: 'my_app_token',
  },
});
When token.persist is true (default) and a token is found in localStorage at construction, it is automatically loaded into the Authorization header.

Authentication

login

Authenticate a user and store the JWT token. The token is automatically attached to all subsequent requests.

const { token, data } = await api.login('users', {
  email: '[email protected]',
  password: 'secret',
});
ParameterTypeDescription
collectionstringCollection with auth enabled
payloadRecord<string, unknown>Login credentials
options?RestRequestOptionsRequest options

Returns: { token: string, data: any }

logout

await api.logout('users');
ParameterTypeDescription
collectionstringCollection with auth enabled
payload?Record<string, unknown>Optional payload
options?RestRequestOptionsRequest options

getToken

Retrieve the current JWT token:

const token = api.getToken(); // string | undefined

clearToken

Remove the token from memory and localStorage:

api.clearToken();

setHeader

Set or remove a custom header:

api.setHeader('X-Custom', 'value');
api.setHeader('X-Custom', undefined); // removes it

CRUD Methods

All CRUD methods target a collection and send a POST request to the dnax unified API.

find

Retrieve multiple documents.

const users = await api.find('users', {
  $match: { activated: true },
  $sort: { createdAt: -1 },
  $limit: 20,
});
ParameterTypeDescription
collectionstringCollection name
paramsRecord<string, unknown>Query parameters ($match, $sort, $limit, $skip, $include, etc.)
options?RestRequestOptionsRequest options

Returns: T[]

findOne

Retrieve a single document by ID.

const user = await api.findOne('users', '64f1a2b3c4d5e6f7a8b9c0d1');
ParameterTypeDescription
collectionstringCollection name
idstringDocument ID
paramsRecord<string, unknown>Query parameters
options?RestRequestOptionsRequest options

Returns: T | null

insertOne

Create a single document.

const newUser = await api.insertOne('users', {
  name: 'Jane Doe',
  email: '[email protected]',
});
// newUser._id is available
ParameterTypeDescription
collectionstringCollection name
dataTBodyDocument data
options?RestRequestOptionsRequest options

Returns: T & { _id: string }

insertMany

Create multiple documents at once.

const products = await api.insertMany('products', [
  { name: 'Widget A', price: 9.99 },
  { name: 'Widget B', price: 14.99 },
]);
ParameterTypeDescription
collectionstringCollection name
dataTBody[]Array of documents
options?RestRequestOptionsRequest options

Returns: (T & { _id: string })[]

updateOne

Update a single document by ID.

await api.updateOne('users', '64f1a2b3c4d5e6f7a8b9c0d1', {
  $set: { name: 'Jane Smith' },
});
ParameterTypeDescription
collectionstringCollection name
idstringDocument ID
updateTUpdateUpdate payload
options?RestRequestOptionsRequest options

updateMany

Update multiple documents by IDs.

await api.updateMany('users', ['id1', 'id2', 'id3'], {
  $set: { activated: true },
});
ParameterTypeDescription
collectionstringCollection name
idsstring[]Document IDs
updateTUpdateUpdate payload
options?RestRequestOptionsRequest options

deleteOne

Delete a single document by ID.

await api.deleteOne('users', '64f1a2b3c4d5e6f7a8b9c0d1');
ParameterTypeDescription
collectionstringCollection name
idstringDocument ID
options?RestRequestOptionsRequest options

deleteMany

Delete multiple documents by IDs.

await api.deleteMany('users', ['id1', 'id2', 'id3']);
ParameterTypeDescription
collectionstringCollection name
idsstring[]Document IDs
options?RestRequestOptionsRequest options

Advanced Methods

aggregate

Run a MongoDB aggregation pipeline.

const stats = await api.aggregate('orders', [
  { $match: { status: 'completed' } },
  { $group: { _id: '$customerId', total: { $sum: '$amount' } } },
  { $sort: { total: -1 } },
]);
ParameterTypeDescription
collectionstringCollection name
pipelineunknown[]Aggregation pipeline stages
options?RestRequestOptionsRequest options

Returns: T[]

runAction

Call a custom action defined on a collection.

const result = await api.runAction('orders', 'processOrder', {
  orderId: '64f1a2b3c4d5e6f7a8b9c0d1',
});
ParameterTypeDescription
collectionstringCollection name
actionstringCustom action name
data?unknownPayload passed to the action
options?RestRequestOptionsRequest options

runService

Appelle un service enregistré dans la config serveur (cfg.services), sur la route POST /services/:tenant/:service/:action (pas sur /api/...).

const report = await api.runService('analytics', 'generateReport', {
  from: '2025-01-01',
  to: '2025-12-31',
});
ParameterTypeDescription
servicestringNom du service (ex. analytics, comme Service.name côté config)
actionstringNom de l’action exposée dans service.actions
data?unknownCorps envoyé dans { data: … } (accessible côté handler via body.data)
options?RestRequestOptionsEn-têtes, signal, query, cleanDeep, etc.

Tenant : celui passé au constructeur new Rest({ server, tenant, ... }) ; il apparaît dans l’URL après /services/.

Request Options

Every method accepts an optional RestRequestOptions object as its last parameter.

type RestRequestOptions = {
  headers?: Record<string, string>;
  signal?: AbortSignal;
  query?: RestQueryOptions;
  cleanDeep?: boolean;
};
OptionTypeDescription
headersRecord<string, string>Extra headers for this request only
signalAbortSignalAbort signal to cancel the request
queryRestQueryOptionsURL query parameters
cleanDeepbooleanStrip null, undefined, empty arrays, and empty objects from the body before sending

AbortSignal

Cancel a long-running request:

const controller = new AbortController();

api.find('users', {}, { signal: controller.signal });

setTimeout(() => controller.abort(), 5000);

cleanDeep

Automatically remove empty values from the request body:

await api.insertOne('users', {
  name: 'Jane',
  nickname: null,
  tags: [],
  meta: {},
}, { cleanDeep: true });
// Body sent: { name: 'Jane' }

Error Handling

When the server returns a non-2xx response, the SDK throws an Error with extra properties:

try {
  await api.findOne('users', 'invalid-id');
} catch (err) {
  console.log(err.message); // "Document not found"
  console.log(err.status);  // 404
  console.log(err.code);    // "DOCUMENT_NOT_FOUND"
  console.log(err.meta);    // additional info from server
}
PropertyTypeDescription
messagestringError message from the server
statusnumberHTTP status code
codestringApplication error code
metaanyOptional metadata

Full Example

import { Rest } from '@dnax/sdk';

const api = new Rest({
  server: 'http://localhost:5000',
  tenant: 'v1',
});

// Login
const { token } = await api.login('users', {
  email: '[email protected]',
  password: 'secret',
});

// Create
const product = await api.insertOne('products', {
  name: 'T-Shirt',
  price: 29.99,
  category: 'clothing',
});

// Read
const products = await api.find('products', {
  $match: { category: 'clothing' },
  $sort: { price: 1 },
  $limit: 10,
});

// Update
await api.updateOne('products', product._id, {
  $set: { price: 24.99 },
});

// Delete
await api.deleteOne('products', product._id);

// Custom action
await api.runAction('orders', 'processOrder', { orderId: '...' });

// Aggregate
const stats = await api.aggregate('orders', [
  { $group: { _id: '$status', count: { $sum: 1 } } },
]);

// Logout
await api.logout('users');
Copyright © 2026