dominus-sdk-nodejs
v8.0.0
Published
Node.js SDK for the Dominus gateway-first platform
Maintainers
Readme
Dominus SDK for Node.js
TypeScript/ESM SDK for Dominus platform services. The SDK exposes a singleton (dominus) with namespace-based APIs for auth, data, storage, AI/runtime, workflow execution, job processing, and platform administration.
Package surface: a single export entry (package.json → exports["."] → dist/index.js / dist/index.d.ts). Import from 'dominus-sdk-nodejs' only; there are no subpath exports.
Agent Guide
Coding agents: start with docs/agent-guide/INDEX.md. The current snapshot is
docs/agent-guide/2026-06-27-0849-sdk-orient/00-reading-order.md; the latest
cleanup audit is docs/janitor/2026-06-27-0849-sdk-orient-cleanup-audit.md.
Install
npm install dominus-sdk-nodejsQuick Start
import { dominus, normalizeSchemaBuilderMigration } from 'dominus-sdk-nodejs';
// Service auth (PSK from DOMINUS_TOKEN)
const tables = await dominus.db.tables('public');
// User auth flow
const session = await dominus.portal.login('[email protected]', 'password');
const me = await dominus.portal.me(session.access_token as string);
// AI runtime
const result = await dominus.ai.runAgent({
conversationId: 'conv-1',
systemPrompt: 'You are concise.',
userPrompt: 'Summarize current task status.'
});
// Courier send
await dominus.courier.sendWelcome('[email protected]', '[email protected]', {
name: 'John',
productName: 'MyApp',
});
// Courier admin
const mailConfig = await dominus.courier.getMailConfig('project-id');
const templates = await dominus.courier.listTemplates('project-id');
// Files
const uploaded = await dominus.files.upload(Buffer.from('hello'), 'hello.txt');
// Schema builder request normalization
const migration = normalizeSchemaBuilderMigration({
operation: 'create_table',
migrationName: 'create_reports',
tableName: 'reports',
columns: [{ name: 'id', type: 'UUID', primaryKey: true }],
});
await dominus.ddl.previewMigration('tenant_secure_backend', migration.operation, migration.params, migration.migrationName);Workflow Lifecycle
Use the Authority-backed one-call lifecycle for normal application code. The legacy saved-workflow run chain is retired.
const execution = await dominus.workflow.ensure({
workflowRecipeRef: 'recipe://workflow-recipe-v1/report-cycle@v3',
subject: 'PCM47474562',
company: 'summit-radiology',
inputs: {
report_snapshot: 'ar://carebridge/summit-radiology/production/snapshot/report-1',
},
});
const runState = await dominus.workflow.getRunState(execution.run_id);
const timeline = await dominus.authority.getRunTimeline(execution.run_id, {
since: '2026-04-11T08:33:00Z',
until: '2026-04-11T09:33:00Z',
});
const timelineArchive = await dominus.authority.getTimelineArchiveStatus({
appSlug: 'carebridge-summit',
env: 'production',
});
const logsArchive = await dominus.logs.getArchiveStatus({
all_scopes: true,
include_buffer: true,
limit: 5,
});
const machineLogs = await dominus.logs.tail({
machine_id: 'mach-abc-123',
since: '2026-04-11T08:33:00Z',
level: 'error',
});
const policy = await dominus.platform.ensurePolicyDecision({
group: 'dominus',
repository: 'carebridgesystems/dominus-platform-worker',
}, { type: 'user', id: 'operator-1' });
const coderRun = await dominus.coder.ensureRun({
policyDecisionId: String(policy.data.policy_decision.decision_id),
workflowRecipeRef: 'recipe://workflow-recipe-v1/coder-feature@head',
repository: 'carebridgesystems/dominus-platform-worker',
instructions: 'Fix failing tests',
actorContext: { type: 'user', id: 'operator-1' },
});
const verifyArchive = await dominus.authority.verifyTimelineArchiveManifests({
since: '2026-04-01T00:00:00Z',
until: '2026-04-02T00:00:00Z',
});
const pruneDryRun = await dominus.logs.pruneArchiveRetention({
retention_days: 90,
dry_run: true,
});
const bufferResidueProof = await dominus.logs.dryRunArchiveBufferMaintenance({
sample_limit: 100,
});
const bufferResidueCleanup = await dominus.logs.runArchiveBufferMaintenance({
dry_run: false,
confirm: 'DELETE_ARCHIVE_BUFFER_RESIDUE',
salvage_missing_archive: true,
sample_limit: 500,
max_archive_buckets: 24,
batch_runs: 5,
max_runtime_ms: 8000,
});
const pipeline = await dominus.workflow.executePipeline('pipeline-uuid', {
mode: 'async',
context: { reportRef, workstationId },
});dominus.workflow.ensure(...)is the preferred one-call run lifecycle for Authority-backed recipe execution.dominus.authority.getRunTimeline(and related Authority run APIs) are the preferred namespace for lifecycle truth;dominus.workflow.getRunTimelinecalls the same route for backward compatibility.- Observability archive helpers now live directly in the SDK: use
dominus.authority.getTimelineArchiveStatus(...)for lifecycle backlog state,dominus.authority.archiveTimelines({ maxHours, maxRuntimeMs })for bounded Authority ledger archive batches,dominus.logs.tail({ machine_id })for workstation-scoped log reads,dominus.logs.getArchiveStatus({ include_buffer: true })for operational log backlog plus Redis residue counters, and the repair/verify/prune/archive-buffer helpers for explicit proof-first maintenance. Confirmed archive-buffer cleanup stays bounded bysample_limit,max_archive_buckets, optionalbatch_runs,max_runtime_ms, andconfirm='DELETE_ARCHIVE_BUFFER_RESIDUE'. - Authority scheduled routes are first-class SDK surface area: use
dominus.authority.listSchedules/createSchedule/updateSchedule/pauseSchedule/resumeSchedule/claimDueSchedules/completeScheduleRun/failScheduleRunwhen integrating with the Authority-owned schedule truth plane. Project-facing route schedules should be treated as bounded route calls, not central maintenance packages. dominus.workflow.*is the saved-workflow facade over workflow-manager.dominus.ai.workflow.*is raw orchestration for inline workflow definitions only.dominus.workflow.executePipeline()runs stored pipelines through workflow-manager's native orchestration-backed runner.
Browser Automation
dominus.browser exposes the first-class Dominus browser automation primitive through the authenticated gateway route family /svc/browser/*. SDK methods use /api/browser/* internally and rely on the client gateway transform; worker-local routes are not /api/browser/*.
const health = await dominus.browser.getHealth();
const run = await dominus.browser.ensureRun({
idempotencyKey: 'route-check-1',
target: { url: 'https://example.com/dashboard' },
provider: 'auto',
mode: 'playwright',
capturePolicy: {
screenshots: 'never',
trace: 'never',
har: 'never',
video: 'never',
domSnapshot: 'never',
rawResponseBodies: 'never',
phiRisk: 'possible',
},
assertions: [{ kind: 'status_code', expected: 200 }],
});
await dominus.browser.startRun(run.run_id);
const status = await dominus.browser.getRunStatus(run.run_id);
const dossier = await dominus.browser.getRunDossier(run.run_id);Cloudflare Browser Run is the default provider. Browserbase is the fallback provider for future persistent authenticated/HITL work. Secret-backed browser auth refs may be passed as references only; the worker sanitizes them and currently defers authenticated execution to waiting_for_human. Browser run metadata is runtime state owned by the browser worker; Artifact V2 is only for sanitized result/capture payloads.
Configuration
Required in most environments:
DOMINUS_TOKEN: service PSK used to mint internal JWTs.
Optional:
DOMINUS_GATEWAY_URL(default:https://gateway.getdominus.app). Defaults always use the production gateway; they do not depend on your app’s git branch or which npm distribution you installed. Override only for local or custom routing.DOMINUS_JWT_URL(defaults to the same host as the gateway),DOMINUS_LOGS_URLDOMINUS_HTTP_PROXY,DOMINUS_HTTPS_PROXYDOMINUS_CAPTURE_CONSOLE=trueto auto-forwardconsole.*intodominus.logs
Per-call timeouts and service-JWT refresh
The default request timeout is 30 seconds (transport cap: 300000 ms). Long-running
admin operations accept a per-call timeout (milliseconds) in their options bag, including
dominus.workflow.seed({ timeout }) and
dominus.authority.bootstrapProvisioningTarget(slug, { timeout }) (server-side
budgets for both are 60s). A timed-out call rejects with TimeoutError; the
operation may still complete server-side, so treat timeouts as "unknown outcome",
not "failed".
Operator/orchestration callers that hold the service JWT directly can bypass the 55-minute mint cache when the backend rejects a token before its local expiry (e.g. after signing-key rotation):
import { getClient } from 'dominus-sdk-nodejs';
const jwt = await getClient().mintServiceJwt(); // cached
const fresh = await getClient().mintServiceJwt({ forceRefresh: true }); // re-mints, replaces the cacheArchitecture Summary
- Primary source is
src/(notdist/). - All namespaces call through
DominusClient(src/lib/client.ts). - Requests use Dominus wire format where required (base64 request wrapping and legacy base64 response envelopes); the client also decodes raw JSON success responses from JSON-first workers.
- Finite workflow/orchestration replay routes may return
text/event-stream; the client normalizes those responses into event arrays forevents()helpers. - Gateway route transform: SDK
/api/*calls can be routed to gateway/svc/*whenuseGatewayis enabled. - Auth model:
- service-to-service: PSK -> minted JWT cache
- user calls: pass
userTokento namespace methods when required
- Retry + circuit-breaker behavior is implemented in client/cache libraries.
Storage: which namespace do I use?
dominus.stash.* is the primary storage surface. Store named-kind data through Stash and let the kind registry pick the backend — you address data by what it is (kind + scope + key), not by which primitive holds it. The primitive namespaces remain as building blocks; they are rarely targeted directly for application data and exist so the backend behind a kind can change (or a new kernel backend can be built) without callers rewriting their calls.
This is the Two-Layer Storage Rule: applications store named-kind data via Stash; primitives are used directly only for ephemera (locks, queues, cache) or when building a kernel backend.
| Your data | Use | Why |
|---|---|---|
| Named, durable data of a registered kind (artifacts, conversations, configs, recipes, secrets) | dominus.stash.* | Primary surface; the kind registry routes to the right backend and policy. |
| A direct ar://-addressed artifact workflow (you already hold a canonical ref) | dominus.artifacts.* | Escape hatch for explicit Artifact V2 addressing; prefer a Stash artifact-v2-backed kind for new code. |
| Locks, queues, rate counters, short-lived cache — ephemera | dominus.redis.* | Building block for ephemeral state; named data belongs in Stash. |
| Building a new kernel backend or a documented migration fallback | primitives (redis, db, files) | The lowest layer; not the place for ordinary application data. |
import { dominus } from 'dominus-sdk-nodejs';
// Named-kind data -> stash (primary surface).
await dominus.stash.put({
env: 'production',
kind: 'artifact-v1',
scope: 'self',
key: 'reports/2026/summary.json',
value: { status: 'final' },
});
// Direct ar:// addressed artifact workflow -> artifacts (escape hatch).
await dominus.artifacts.storeV2({
group: 'acme',
owner: 'project:00000000-0000-0000-0000-000000000000',
environment: 'production',
kind: 'artifact-v1',
artifactKey: 'reports/2026/summary.json',
data: Buffer.from(JSON.stringify({ status: 'final' })).toString('base64'),
});
// Locks / queues / cache / ephemera -> redis (building block).
await dominus.redis.set('lock:report-job-42', '1', 60);The primitive namespaces are not deprecated and are never removed — they are the layer Stash is built on. This is positioning guidance, not an API change.
Namespaces
SDK singleton namespaces available on dominus:
secrets,db,secure,redis,files,auth,ddl,logs,portal,courier,open,health,admin,ai,workflow,sync,jobs,processor,artifacts,authority,browser,deployer,warden,platform,coder
The platform and coder namespaces are the policy-to-execution pair for controlled Coder work. Use dominus.platform.ensurePolicyDecision(...) to obtain a policy decision, then dominus.coder.ensureRun(...) with exactly one workflowRecipeRef or pipelineRecipeRef. Pass actorContext: { type, id } on Platform/Coder calls that mutate or read operator-scoped state so the SDK forwards X-Actor-Type / X-Actor-Id for attribution.
The admin namespace now covers both admin-category maintenance and the operator maintenance surface (exportApps, exportTokens, seedKV, listKvKeys, getKvValue, putKvValue, deleteKvKey), so Mothership and other operator tools do not need bespoke raw gateway glue for those routes.
Guardian navigation helpers expose nav-row path on createNavItem() and updateNavItem(). Use that field when a sidebar item must route to a concrete URL independent of, or more specific than, the linked Guardian page row.
The deployer and warden namespaces are the thin operator request surfaces for the remaining control-plane routes that are not yet modeled as higher-level typed methods. The deployer namespace is execution-only — deploy lifecycle reads come from dominus.authority.* (listDeploys, getDeploy, getDeployVerdict), not from the deployer. Use the deployer namespace for narrow execution concerns (configs CRUD, manual smoke-check probes, repo/installation management) and use the warden namespace for portal user management:
await dominus.authority.listDeploys();
await dominus.deployer.request('/configs', { method: 'GET' });
await dominus.warden.request('/users', {
method: 'POST',
body: { email: '[email protected]' },
});Artifact storage now exposes both legacy helpers and addressed V2 surfaces. Use storeV2(), headV2(), compareV2(), bookmark helpers, and watcher helpers with canonical ar://{group}/{owner}/{environment}/{kind}/{artifact_key} refs for new code; legacy projectSlug / target_project_id concepts remain for migration compatibility only.
Schema-builder operator surfaces should normalize frontend MigrationInput payloads through normalizeSchemaBuilderMigration(...) before calling dominus.ddl.previewMigration(...) or dominus.ddl.applyBuilderMigration(...). That helper is the canonical bridge from UI field names like tableName / columnType to the kernel builder params table / column / type / index_name / primary_key.
Root shortcuts are also exposed for common secrets/db/ddl methods (get, upsert, listTables, queryTable, etc.).
Courier is provider-agnostic. The namespace supports both the legacy send helpers and the courier admin plane used by Mothership:
- project mail config
- sender identities
- template CRUD and render preview
- delivery history
Documentation
- Architecture
- Routes/Services/Endpoints Assessment
- Comprehensive Usage Reference (all namespaced commands)
- Workflow hard-cut release notes
Development
npm ci
npm run build
npm run lint
npm testCI publish workflows exist for development, staging, and production branches under .github/workflows/.
Notes
- Speech-to-text and text-to-speech live under
dominus.ai(ai.stt,ai.tts) through agent-runtime. - Contract tests cover the saved-workflow facade and the addressed artifact V2 helper surface.
