Overview
The typed SDK is the fastest way to read and write Dyrected content from JavaScript and TypeScript.
The Dyrected SDK (@dyrected/sdk) is a small typed client for talking to your Dyrected API. It gives you fully typed collection and global access, query building, uploads, and workflow transitions without hand-writing fetch calls.
If you are working in JavaScript or TypeScript, reach for the SDK first. Drop down to the REST API only when you need a language the SDK does not cover.
Creating a client
Create one client and reuse it. Point it at the origin of your Dyrected app — the SDK adds the /api prefix itself.
There are two normal ways to type that client:
- use
InferSchemawhen the app can import exported collection and global constants directly fromdyrected.config.ts - use generated
DyrectedSchemawhen the app should read fromdyrected-types.tsinstead of importing schema code
If you already generated dyrected-types.ts, you do not need to infer the schema again by hand. Use DyrectedSchema directly:
import { createClient } from "@dyrected/sdk";
import type { DyrectedSchema } from "./dyrected-types";
const client = createClient<DyrectedSchema>({
baseUrl: "https://example.com",
apiKey: process.env.DYRECTED_API_KEY,
});
const { docs: posts } = await client.collection("posts").find({
where: { status: { equals: "published" } },
sort: "-createdAt",
depth: 1,
});Because the client is generic over your schema, find, create, and update return typed documents and reject unknown fields at compile time.
If your app and schema live in the same codebase and you prefer not to generate a file, the TypeScript docs show the InferSchema path in TypeScript Overview and InferSchema.
What you can do
- Read and write collections through
client.collection('slug'). - Read and update singletons through
client.global('slug'). - Shape reads with sort, filter, depth, pagination, and free-text
search. - Compute fast statistics and counts with aggregate.
- Upload files and run workflow transitions on documents that support them.
For example, collection search is now first-class in the SDK:
const { docs } = await client.collection("posts").find({
search: "grace hopper",
where: { status: { equals: "published" } },
})Use search when you want the collection's configured backend search behavior. The server merges it with your where clause using AND, so free-text search and structured filters work together.
Managing media & folders
Organize upload collections, manipulate folders, and replace asset files in-place:
// 1. Create a media folder
const folder = await client.createFolder("media", {
name: "Summer Campaign",
color: "#3b82f6",
});
// 2. List all folders in a collection
const { docs: folders } = await client.listFolders("media");
// 3. Upload a file directly into a folder
const asset = await client.collection("media").upload(myFile, {
folderId: folder.id,
alt: "Summer campaign banner",
});
// 4. Replace an existing file in-place (keeps the same document ID)
const updatedAsset = await client.replaceMedia(asset.id, newFile);
// 5. Delete multiple assets in batch
await client.deleteMany("media", {
ids: ["asset-1", "asset-2"],
});Managing authentication & invitations
When a collection has auth: true or an auth config, client.collection(slug) exposes full auth lifecycle methods:
// 1. Invite a user with initial role data and custom action URL
const invite = await client.collection("users").invite("[email protected]", {
inviteUrl: "https://myapp.com/accept-invite",
data: { roles: ["editor"], name: "Alex" },
});
console.log(`Invite sent: ${invite.emailSent}, token: ${invite.token}`);
// 2. Mint a headless invite token without sending an email (for SMS, custom delivery)
const headless = await client.collection("users").createInviteToken({
email: "[email protected]",
inviteUrl: "https://myapp.com/onboarding",
});
// 3. Verify an invite or reset token when your frontend component mounts
const check = await client.collection("users").verifyToken(tokenFromUrl, "invite");
if (check.valid) {
console.log(`Token verified for ${check.email}`);
} else {
console.error(`Token invalid or expired: ${check.error}`);
}
// 4. Complete invite acceptance with a user-chosen password
const { token, user } = await client.collection("users").acceptInvite(
tokenFromUrl,
"secure-password-123",
{ department: "Design" },
);
client.setToken(token);
// 5. Send a password reset or mint a headless reset token
await client.collection("users").sendPasswordReset("[email protected]", {
resetUrl: "https://myapp.com/reset-password",
});
const resetToken = await client.collection("users").createPasswordResetToken("[email protected]");For the endpoint-by-endpoint details and server behavior, read Authentication Operations.
Handling errors
SDK calls throw a typed DyrectedError when the API returns a non-success status, so you can branch on status codes and surface server validation messages safely.
Generated reference
The contracts below are generated from the public @dyrected/sdk exports by @dyrected/knowledge, so the client, factory, options, and error types stay in sync with the package. Query-shaping details live on the sort, filter, depth, and pagination pages.
AuditEntry
A single audit entry returned by client.audit() or client.collection(slug).audit().
export interface AuditEntry {
id: string;
collection: string;
documentId: string | null;
operation: string;
user: string | null;
timestamp: string;
changes?: string | Record<string, unknown> | null;
}| Option | Description |
|---|---|
id (required) | |
collection (required) | |
documentId (required) | |
operation (required) | |
user (required) | |
timestamp (required) | |
changes (optional) |
BaseSchema
Exported interface from @dyrected/sdk.
export interface BaseSchema {
collections: Record<string, UnknownRecord>;
globals: Record<string, UnknownRecord>;
}| Option | Description |
|---|---|
collections (required) | |
globals (required) |
createClient
Exported function from @dyrected/sdk.
export function createClient<TSchema extends SchemaShape = RegisteredSchema>(
config: DyrectedClientConfig,
): DyrectedClient<TSchema>DyrectedClient
Exported class from @dyrected/sdk.
export class DyrectedClient<TSchema extends SchemaShape = RegisteredSchema> {
}| Option | Description |
|---|---|
setToken (required) | Update the Authorization header with a Bearer token. Call this after a successful login. |
clearToken (required) | Remove the Authorization header. Call this after logout. |
getAuthHeaders (required) | Returns the headers needed to authenticate raw `fetch()` calls made outside the SDK client (e.g. streaming endpoints, dynamic options). Includes the Authorization bearer token (if set), x-api-key, and x-site-id. |
getBaseUrl (required) | |
getSchemas (required) | |
getAdminAuthConfig (required) | |
exchangeAdminAuth (required) | |
getPreference (optional) | |
setPreference (optional) | |
deletePreference (optional) | |
getNavigation (required) | Fetches the dynamic runtime navigation tree compiled for the current user. |
getNavigationBadges (optional) | Fetches real-time badge counts and status for navigation items. |
getPreviewData (required) | Fetch draft data for a specific preview token. Used in "token" preview mode. |
createPreviewToken (optional) | Mint a short-lived preview token that carries the current (unsaved) draft data. Used by the Admin in `previewMode: "token"` to hand draft content to a server-rendered frontend that cannot receive it over `postMessage`. Requires an authenticated request (the Admin is logged in). |
ai (optional) | AI Assistant methods for managing threads, messaging, human-in-the-loop action approvals, semantic RAG search, and AI chat. |
find (required) | |
collection (required) | Returns a fluent query builder for a collection. |
global (required) | Access a global by its slug with a fluent builder. |
trash (optional) | Access trash operations, either collection-scoped or globally. |
findOne (optional) | |
create (required) | |
update (required) | |
delete (optional) | |
transition (required) | Perform a workflow transition on a document. Sends `POST /api/collections/:collection/:id/transitions/:transition`. Requires the client to have a valid bearer token set via `setToken()`. |
workflowHistory (optional) | Fetch the workflow history for a document. Sends `GET /api/collections/:collection/:id/workflow-history`. |
audit (required) | Fetch audit entries across every audited collection the current caller can read. Sends `GET /api/audit`. |
collectionAudit (required) | Fetch audit entries for a single collection. Sends `GET /api/collections/:collection/__audit`. |
deleteMany (optional) | |
getGlobal (optional) | |
updateGlobal (required) | |
listMedia (required) | |
listFolders (required) | List all media folders in an upload-enabled collection. |
createFolder (optional) | Create a new media folder in an upload-enabled collection. |
updateFolder (optional) | Update an existing media folder in an upload-enabled collection. |
deleteFolder (required) | Delete a media folder from an upload-enabled collection. |
uploadMedia (required) | |
replaceMedia (required) | Replace the underlying file of an existing media document in-place without creating a duplicate record. |
deleteMedia (required) |
DyrectedClientConfig
Exported interface from @dyrected/sdk.
export interface DyrectedClientConfig {
baseUrl: string;
apiKey?: string;
siteId?: string;
headers?: Record<string, string>;
fetch?: typeof fetch;
/**
* Callback invoked when a 401 Unauthorized response is returned from an authenticated endpoint.
*/
onAuthError?: (error: DyrectedError) => void;
/**
* Default relationship population depth applied to document reads
* (`find`, `findOne`, `global().get()`, and media listing) when a call
* does not pass its own `depth`. Defaults to `1`.
*/
defaultDepth?: number;
}| Option | Description |
|---|---|
baseUrl (required) | |
apiKey (optional) | |
siteId (optional) | |
headers (optional) | |
fetch (optional) | |
onAuthError (optional) | Callback invoked when a 401 Unauthorized response is returned from an authenticated endpoint. |
defaultDepth (optional) | Default relationship population depth applied to document reads (`find`, `findOne`, `global().get()`, and media listing) when a call does not pass its own `depth`. Defaults to `1`. |
DyrectedError
Structured error thrown by the SDK when the server returns a non-2xx response.
export class DyrectedError extends Error {
}| Option | Description |
|---|---|
statusCode (required) | |
errors (optional) |
getPreviewToken
Extract the preview token from a request's query string. Accepts a raw query
string, a URLSearchParams, or a plain params object (e.g. Nuxt's
route.query or Next's searchParams). Returns null when absent.
export function getPreviewToken(
search: string | URLSearchParams | Record<string, unknown> | undefined | null,
): string | nullInferSchema
Derives a typed TSchema from your exported collection and global config constants.
Pass it to createClient<Schema>() so every find, findOne, create,
update, global().get() call returns the inferred document shape — no
manual interfaces required.
export type InferSchema<
TCollections extends Record<string, CollectionConfig<UnknownRecord>>,
TGlobals extends Record<string, GlobalConfig<UnknownRecord>> = Record<
never,
never
>,
> = {
collections: { [K in keyof TCollections]: ExtractDoc<TCollections[K]> };
globals: { [K in keyof TGlobals]: ExtractDoc<TGlobals[K]> };
};InviteOptions
Exported interface from @dyrected/sdk.
export interface InviteOptions {
inviteUrl?: string;
sendEmail?: boolean;
data?: UnknownRecord;
[key: string]: unknown;
}| Option | Description |
|---|---|
inviteUrl (optional) | |
sendEmail (optional) | |
data (optional) |
InviteResult
Exported interface from @dyrected/sdk.
export interface InviteResult {
success: boolean;
message: string;
token: string;
inviteUrl: string;
emailSent: boolean;
emailError?: string;
}| Option | Description |
|---|---|
success (required) | |
message (required) | |
token (required) | |
inviteUrl (required) | |
emailSent (required) | |
emailError (optional) |
MediaFolder
Shape of a media folder document in the DAM system.
export interface MediaFolder {
id: string;
name: string;
slug: string;
collection: string;
parentId: string | null;
path: string;
color?: string | null;
createdAt?: string;
updatedAt?: string;
}| Option | Description |
|---|---|
id (required) | |
name (required) | |
slug (required) | |
collection (required) | |
parentId (required) | |
path (required) | |
color (optional) | |
createdAt (optional) | |
updatedAt (optional) |
PasswordResetOptions
Exported interface from @dyrected/sdk.
export interface PasswordResetOptions {
resetUrl?: string;
sendEmail?: boolean;
}| Option | Description |
|---|---|
resetUrl (optional) | |
sendEmail (optional) |
PasswordResetResult
Exported interface from @dyrected/sdk.
export interface PasswordResetResult {
success: boolean;
message: string;
emailSent: boolean;
emailError?: string;
token?: string;
resetUrl?: string;
}| Option | Description |
|---|---|
success (required) | |
message (required) | |
emailSent (required) | |
emailError (optional) | |
token (optional) | |
resetUrl (optional) |
PREVIEW_TOKEN_PARAM
The query-string parameter the Admin appends to a preview URL in
previewMode: "token". Read it on your frontend to decide whether to fetch
draft data instead of published content.
export const PREVIEW_TOKEN_PARAM = "dyPreview";Register
Exported interface from @dyrected/sdk.
export interface Register {}RegisteredComponentKeys
Component keys registered via CLI type generation on Register['componentKeys'].
Falls back to loose string records when types have not been generated.
export type RegisteredComponentKeys = Register extends { componentKeys: infer K }
? K
: {
fields?: string;
dashboard?: string;
collectionList?: string;
collectionView?: string;
forms?: string;
viewLayouts?: string;
pages?: string;
customComponents?: string;
};RegisteredSchema
Exported type from @dyrected/sdk.
export type RegisteredSchema = Register extends { schema: infer S }
? S extends SchemaShape
? S
: BaseSchema
: BaseSchema;RunActionArgs
Arguments accepted by client.collection(slug).runAction().
export interface RunActionArgs {
/** Target a single document (row action). */
id?: string;
/** Target multiple documents (bulk action). */
ids?: string[];
/** Values collected from the action's input form dialog. */
input?: Record<string, unknown>;
}| Option | Description |
|---|---|
id (optional) | Target a single document (row action). |
ids (optional) | Target multiple documents (bulk action). |
input (optional) | Values collected from the action's input form dialog. |
SchemaResponse
Exported interface from @dyrected/sdk.
export interface SchemaResponse {
blocks?: Block[];
collections: CollectionConfig[];
globals: GlobalConfig[];
admin?: AdminConfig;
adminAuth?: PublicAdminAuthConfig;
hasStorage?: boolean;
configDiagnostics?: ConfigDiagnostic[];
ai?: SerializedSchemaAIConfig;
trash?: {
enabled?: boolean;
retentionDays?: number | null;
allowPermanentDelete?: boolean;
};
adminHealth?: {
emailConfigured?: boolean;
secureAuthSecretConfigured?: boolean;
authCollectionConfigured?: boolean;
uploadCollectionConfigured?: boolean;
trashPurgeOverdue?: boolean;
};
}| Option | Description |
|---|---|
blocks (optional) | |
collections (required) | |
globals (required) | |
admin (optional) | |
adminAuth (optional) | |
hasStorage (optional) | |
configDiagnostics (optional) | |
ai (optional) | |
trash (optional) | |
adminHealth (optional) |
SchemaShape
Exported interface from @dyrected/sdk.
export interface SchemaShape {
collections: Record<string, object>;
globals: Record<string, object>;
}| Option | Description |
|---|---|
collections (required) | |
globals (required) |
SerializedCollectionConfig
Exported interface from @dyrected/sdk.
export interface SerializedCollectionConfig {
slug: string;
labels?: { singular?: string; plural?: string };
shared?: boolean;
siteId?: string;
ai?: unknown;
access?: {
read?: boolean | string;
create?: boolean | string;
update?: boolean | string;
delete?: boolean | string;
};
fields: SerializedField[];
upload?: boolean;
auth?: boolean;
audit?: boolean;
drafts?: boolean;
defaultView?: string;
views?: unknown[];
admin?: Record<string, unknown>;
detail?: unknown;
workflow?: unknown;
}| Option | Description |
|---|---|
slug (required) | |
labels (optional) | |
shared (optional) | |
siteId (optional) | |
ai (optional) | |
access (optional) | |
fields (required) | |
upload (optional) | |
auth (optional) | |
audit (optional) | |
drafts (optional) | |
defaultView (optional) | |
views (optional) | |
admin (optional) | |
detail (optional) | |
workflow (optional) |
SerializedField
Exported interface from @dyrected/sdk.
export interface SerializedField {
name: string;
type: string;
label?: string;
required?: boolean;
unique?: boolean;
min?: number;
max?: number;
step?: number;
minLength?: number;
maxLength?: number;
pattern?: string;
allowedTypes?: string[];
maxSize?: number;
virtual?: boolean;
promoted?: boolean;
ai?: {
exclude?: boolean;
redact?: boolean | "mask";
allowRaw?: boolean;
};
defaultValue?: unknown;
options?: unknown;
relationTo?: string;
hasMany?: boolean;
fields?: SerializedField[];
blocks?: unknown[];
blockReferences?: string[];
collection?: string;
on?: string;
limit?: number;
admin?: Record<string, unknown>;
access?: {
read?: boolean | string;
create?: boolean | string;
update?: boolean | string;
};
}| Option | Description |
|---|---|
name (required) | |
type (required) | |
label (optional) | |
required (optional) | |
unique (optional) | |
min (optional) | |
max (optional) | |
step (optional) | |
minLength (optional) | |
maxLength (optional) | |
pattern (optional) | |
allowedTypes (optional) | |
maxSize (optional) | |
virtual (optional) | |
promoted (optional) | |
ai (optional) | |
defaultValue (optional) | |
options (optional) | |
relationTo (optional) | |
hasMany (optional) | |
fields (optional) | |
blocks (optional) | |
blockReferences (optional) | |
collection (optional) | |
on (optional) | |
limit (optional) | |
admin (optional) | |
access (optional) |
SerializedGlobalConfig
Exported interface from @dyrected/sdk.
export interface SerializedGlobalConfig {
slug: string;
label?: string;
shared?: boolean;
siteId?: string;
access?: {
read?: boolean | string;
update?: boolean | string;
};
fields: SerializedField[];
admin?: Record<string, unknown>;
detail?: unknown;
}| Option | Description |
|---|---|
slug (required) | |
label (optional) | |
shared (optional) | |
siteId (optional) | |
access (optional) | |
fields (required) | |
admin (optional) | |
detail (optional) |
SerializedSchemaAIConfig
Exported interface from @dyrected/sdk.
export interface SerializedSchemaAIConfig {
enabled: boolean;
provider?: string;
model?: string;
}| Option | Description |
|---|---|
enabled (required) | |
provider (optional) | |
model (optional) |
TokenVerificationResult
Exported interface from @dyrected/sdk.
export interface TokenVerificationResult {
valid: boolean;
email?: string;
collection?: string;
code?: string;
message?: string;
}| Option | Description |
|---|---|
valid (required) | |
email (optional) | |
collection (optional) | |
code (optional) | |
message (optional) |
TransitionOptions
Options accepted by client.transition().
export interface TransitionOptions {
/**
* The revision number currently shown to the user. When provided, the server
* rejects the transition if the document has changed since it was loaded,
* preventing lost-update races.
*/
expectedRevision?: number;
/** Required for transitions that have `requireComment: true` (e.g. `reject`). */
comment?: string;
/**
* Extra data passed to the transition's server-side `onTransition` handler,
* for example an amount the handler needs to act on.
*/
input?: Record<string, unknown>;
}| Option | Description |
|---|---|
expectedRevision (optional) | The revision number currently shown to the user. When provided, the server rejects the transition if the document has changed since it was loaded, preventing lost-update races. |
comment (optional) | Required for transitions that have `requireComment: true` (e.g. `reject`). |
input (optional) | Extra data passed to the transition's server-side `onTransition` handler, for example an amount the handler needs to act on. |
TrashClient
Exported type from @dyrected/sdk.
export type TrashClient = ((collectionSlug?: string) => TrashOperations) & TrashOperations;TrashEmptyOptions
Exported interface from @dyrected/sdk.
export interface TrashEmptyOptions {
confirm?: string;
}| Option | Description |
|---|---|
confirm (optional) |
TrashEntry
A single trash entry representing a soft-deleted document snapshot.
export interface TrashEntry {
id: string;
collection: string;
docId: string;
deletedAt: number;
purgeAt: number | null;
deletedBy?: string;
title?: string;
snapshot: Record<string, unknown>;
createdAt?: string;
updatedAt?: string;
}| Option | Description |
|---|---|
id (required) | |
collection (required) | |
docId (required) | |
deletedAt (required) | |
purgeAt (required) | |
deletedBy (optional) | |
title (optional) | |
snapshot (required) | |
createdAt (optional) | |
updatedAt (optional) |
TrashKeepOptions
Exported interface from @dyrected/sdk.
export interface TrashKeepOptions {
purgeAt?: Date | string | number | null;
}| Option | Description |
|---|---|
purgeAt (optional) |
TrashListArgs
Exported interface from @dyrected/sdk.
export interface TrashListArgs {
page?: number;
limit?: number;
search?: string;
[key: string]: unknown;
}| Option | Description |
|---|---|
page (optional) | |
limit (optional) | |
search (optional) |
TrashOperations
Exported interface from @dyrected/sdk.
export interface TrashOperations {
list: (args?: TrashListArgs) => Promise<PaginatedResult<TrashEntry>>;
get: (trashId: string) => Promise<TrashEntry>;
restore: (trashId: string, options?: TrashRestoreOptions) => Promise<UnknownRecord>;
restoreMany: (trashIds: string[]) => Promise<{ restored: string[]; failed: unknown[]; count: number }>;
keep: (trashId: string, options?: TrashKeepOptions | boolean) => Promise<{ message: string; purgeAt: number | null }>;
purge: (trashId: string) => Promise<{ message: string }>;
empty: (options?: TrashEmptyOptions | string) => Promise<{ message: string; count: number }>;
}| Option | Description |
|---|---|
list (optional) | |
get (required) | |
restore (optional) | |
restoreMany (required) | |
keep (optional) | |
purge (required) | |
empty (optional) |
TrashRestoreOptions
Exported interface from @dyrected/sdk.
export interface TrashRestoreOptions {
overrides?: Record<string, unknown>;
}| Option | Description |
|---|---|
overrides (optional) |
UploadOptions
Options for file uploads.
When onProgress is provided and the runtime supports XMLHttpRequest (browsers),
the upload reports real byte-level progress. In other environments (SSR, custom
fetch) the callback is ignored and the standard fetch path is used.
export interface UploadOptions {
/** Called with an integer 0–100 as the file bytes are sent. */
onProgress?: (percent: number) => void;
/** Abort the in-flight upload. */
signal?: AbortSignal;
}| Option | Description |
|---|---|
onProgress (optional) | Called with an integer 0–100 as the file bytes are sent. |
signal (optional) | Abort the in-flight upload. |
WorkflowDocument
Shape of a document returned from a workflow-enabled collection.
export interface WorkflowDocument {
id: string;
_workflow: WorkflowMetadata;
[key: string]: unknown;
}| Option | Description |
|---|---|
id (required) | |
_workflow (required) |
WorkflowHistoryEntry
A single workflow history entry returned by client.workflowHistory().
export interface WorkflowHistoryEntry {
id: string;
collection: string;
documentId: string;
transition: string;
from: string;
to: string;
revision: number;
comment: string | null;
actorId: string | null;
createdAt: string;
}| Option | Description |
|---|---|
id (required) | |
collection (required) | |
documentId (required) | |
transition (required) | |
from (required) | |
to (required) | |
revision (required) | |
comment (required) | |
actorId (required) | |
createdAt (required) |