dominus-sdk-nodejs 11.0.2 → 11.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +351 -371
  2. package/dist/contract/index.d.ts +3 -0
  3. package/dist/contract/index.d.ts.map +1 -0
  4. package/dist/contract/index.js +3 -0
  5. package/dist/contract/index.js.map +1 -0
  6. package/dist/contract/node-envelope.d.ts +12 -0
  7. package/dist/contract/node-envelope.d.ts.map +1 -0
  8. package/dist/contract/node-envelope.js +16 -0
  9. package/dist/contract/node-envelope.js.map +1 -0
  10. package/dist/contract/node-projections.d.ts +15 -0
  11. package/dist/contract/node-projections.d.ts.map +1 -0
  12. package/dist/contract/node-projections.js +4 -0
  13. package/dist/contract/node-projections.js.map +1 -0
  14. package/dist/lib/config.d.ts +3 -2
  15. package/dist/lib/config.d.ts.map +1 -1
  16. package/dist/lib/config.js +4 -3
  17. package/dist/lib/config.js.map +1 -1
  18. package/dist/lib/errors.d.ts +7 -0
  19. package/dist/lib/errors.d.ts.map +1 -1
  20. package/dist/lib/errors.js +53 -0
  21. package/dist/lib/errors.js.map +1 -1
  22. package/dist/lib/recovery-action.d.ts +4 -0
  23. package/dist/lib/recovery-action.d.ts.map +1 -0
  24. package/dist/lib/recovery-action.js +29 -0
  25. package/dist/lib/recovery-action.js.map +1 -0
  26. package/dist/namespaces/portal.d.ts +10 -0
  27. package/dist/namespaces/portal.d.ts.map +1 -1
  28. package/dist/namespaces/portal.js +11 -0
  29. package/dist/namespaces/portal.js.map +1 -1
  30. package/dist/namespaces/secrets.d.ts +5 -1
  31. package/dist/namespaces/secrets.d.ts.map +1 -1
  32. package/dist/namespaces/secrets.js +15 -1
  33. package/dist/namespaces/secrets.js.map +1 -1
  34. package/docs/agent-guide/2026-06-27-0849-sdk-orient/00-reading-order.md +35 -35
  35. package/docs/agent-guide/2026-06-27-0849-sdk-orient/01-purpose-and-boundaries.md +48 -48
  36. package/docs/agent-guide/2026-06-27-0849-sdk-orient/02-repo-map-and-entrypoints.md +46 -46
  37. package/docs/agent-guide/2026-06-27-0849-sdk-orient/03-api-surface.md +59 -59
  38. package/docs/agent-guide/2026-06-27-0849-sdk-orient/04-data-state-and-storage.md +36 -36
  39. package/docs/agent-guide/2026-06-27-0849-sdk-orient/05-integrations-and-runtime.md +40 -40
  40. package/docs/agent-guide/2026-06-27-0849-sdk-orient/06-workflows-commands-and-ci.md +58 -58
  41. package/docs/agent-guide/2026-06-27-0849-sdk-orient/07-operations-release-and-live-proof.md +40 -40
  42. package/docs/agent-guide/2026-06-27-0849-sdk-orient/08-security-privacy-and-secrets.md +38 -38
  43. package/docs/agent-guide/2026-06-27-0849-sdk-orient/09-known-risks-and-debt.md +34 -34
  44. package/docs/agent-guide/2026-06-27-0849-sdk-orient/10-agent-playbook.md +48 -48
  45. package/docs/agent-guide/2026-08-04-sdk-nodejs/00-reading-order.md +11 -11
  46. package/docs/agent-guide/2026-08-04-sdk-nodejs/01-purpose-and-boundaries.md +14 -14
  47. package/docs/agent-guide/2026-08-04-sdk-nodejs/03-api-surface.md +16 -16
  48. package/docs/agent-guide/2026-08-04-sdk-nodejs/10-agent-playbook.md +14 -14
  49. package/docs/agent-guide/INDEX.md +14 -14
  50. package/docs/agent-guide/current.md +22 -22
  51. package/docs/architecture.md +119 -119
  52. package/docs/atlas/2026-07-24-1231-sdk-nodejs-blockers.md +15 -15
  53. package/docs/atlas/2026-07-24-1231-sdk-nodejs-proof-ladder.md +25 -25
  54. package/docs/atlas/2026-07-24-1231-sdk-nodejs-truthmap.md +43 -43
  55. package/docs/atlas/2026-08-04-sdk-nodejs-blockers.md +12 -12
  56. package/docs/atlas/2026-08-04-sdk-nodejs-proof-ladder.md +9 -9
  57. package/docs/atlas/2026-08-04-sdk-nodejs-truthmap.md +21 -21
  58. package/docs/atlas/INDEX.md +26 -26
  59. package/docs/janitor/2026-06-27-0849-sdk-orient-cleanup-audit.md +102 -102
  60. package/docs/janitor/2026-08-04-sdk-nodejs-cleanup-audit.md +14 -14
  61. package/docs/migration-error-base.md +115 -0
  62. package/docs/plans/2026-08-04-pending-work-fruition-summary.md +46 -46
  63. package/docs/routes-services.md +80 -80
  64. package/docs/usage-reference.md +698 -698
  65. package/docs/workflow-hard-cut-release.md +24 -24
  66. package/package.json +55 -55
package/README.md CHANGED
@@ -1,371 +1,351 @@
1
- # Dominus SDK for Node.js
2
-
3
- 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.
4
-
5
- **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.
6
-
7
- ## Agent Guide
8
-
9
- Coding agents: start with `docs/agent-guide/INDEX.md`. The current snapshot is
10
- `docs/agent-guide/2026-08-04-sdk-nodejs/00-reading-order.md`; the latest
11
- cleanup audit is `docs/janitor/2026-08-04-sdk-nodejs-cleanup-audit.md`.
12
-
13
- ## Install
14
-
15
- ```bash
16
- npm install dominus-sdk-nodejs
17
- ```
18
-
19
- ## Quick Start
20
-
21
- Token-required hello using only the developer-stable catalog verbs. Set project
22
- scope with `DOMINUS_PROJECT` or CLI `select_project`. Other SDK namespaces exist
23
- for operators and advanced use; this path is the stable teaching surface. The
24
- catalog publishes the same lower-camel method names used by TypeScript callers.
25
-
26
- Set both values before the Node.js process imports the SDK singleton:
27
-
28
- ```bash
29
- export DOMINUS_TOKEN="your-psk-token"
30
- export DOMINUS_PROJECT="your-project-slug"
31
- ```
32
-
33
- ```ts
34
- import { dominus } from 'dominus-sdk-nodejs';
35
-
36
- // Use the stable identifier of the person performing the write.
37
- const actorContext = { type: 'user', id: 'your-actor-id' };
38
-
39
- const run = await dominus.workflow.ensure({
40
- workflowRecipeRef: 'recipe://workflow-recipe-v1/hello@v1',
41
- });
42
-
43
- await dominus.artifacts.storeV2({
44
- group: 'your-group',
45
- owner: 'your-project-slug',
46
- environment: 'production',
47
- kind: 'blob',
48
- artifactKey: 'hello',
49
- data: Buffer.from('hello dominus').toString('base64'),
50
- actorContext,
51
- });
52
- const artifact = await dominus.artifacts.retrieveV2({
53
- group: 'your-group',
54
- owner: 'your-project-slug',
55
- environment: 'production',
56
- kind: 'blob',
57
- artifactKey: 'hello',
58
- });
59
-
60
- await dominus.stash.put({
61
- env: 'production',
62
- kind: 'config',
63
- scope: 'self',
64
- key: 'hello',
65
- value: { greeting: 'hello' },
66
- });
67
- await dominus.stash.getItem({
68
- env: 'production',
69
- kind: 'config',
70
- scope: 'self',
71
- key: 'hello',
72
- });
73
-
74
- const runId = String((run as { run_id?: string }).run_id ?? '');
75
- const timeline = await dominus.authority.getRunTimeline(runId);
76
- const verdict = await dominus.authority.getRunVerdict(runId);
77
- ```
78
-
79
- ## Workflow Lifecycle
80
-
81
- Use the Authority-backed one-call lifecycle for normal application code. The legacy saved-workflow run chain is retired.
82
-
83
- ```ts
84
- const execution = await dominus.workflow.ensure({
85
- workflowRecipeRef: 'recipe://workflow-recipe-v1/report-cycle@v3',
86
- subject: 'PCM47474562',
87
- company: 'summit-radiology',
88
- inputs: {
89
- report_snapshot: 'ar://carebridge/summit-radiology/production/snapshot/report-1',
90
- },
91
- });
92
- const runState = await dominus.workflow.getRunState(execution.run_id);
93
- const timeline = await dominus.authority.getRunTimeline(execution.run_id, {
94
- since: '2026-04-11T08:33:00Z',
95
- until: '2026-04-11T09:33:00Z',
96
- });
97
- const timelineArchive = await dominus.authority.getTimelineArchiveStatus({
98
- appSlug: 'carebridge-summit',
99
- env: 'production',
100
- });
101
- const logsArchive = await dominus.logs.getArchiveStatus({
102
- all_scopes: true,
103
- include_buffer: true,
104
- limit: 5,
105
- });
106
- const machineLogs = await dominus.logs.tail({
107
- machine_id: 'mach-abc-123',
108
- since: '2026-04-11T08:33:00Z',
109
- level: 'error',
110
- });
111
- const policy = await dominus.platform.ensurePolicyDecision({
112
- group: 'dominus',
113
- repository: 'carebridgesystems/dominus-platform-worker',
114
- }, { type: 'user', id: 'operator-1' });
115
- const coderRun = await dominus.coder.ensureRun({
116
- policyDecisionId: String(policy.data.policy_decision.decision_id),
117
- workflowRecipeRef: 'recipe://workflow-recipe-v1/coder-feature@head',
118
- repository: 'carebridgesystems/dominus-platform-worker',
119
- instructions: 'Fix failing tests',
120
- actorContext: { type: 'user', id: 'operator-1' },
121
- });
122
- const verifyArchive = await dominus.authority.verifyTimelineArchiveManifests({
123
- since: '2026-04-01T00:00:00Z',
124
- until: '2026-04-02T00:00:00Z',
125
- });
126
- const pruneDryRun = await dominus.logs.pruneArchiveRetention({
127
- retention_days: 90,
128
- dry_run: true,
129
- });
130
- const bufferResidueProof = await dominus.logs.dryRunArchiveBufferMaintenance({
131
- sample_limit: 100,
132
- });
133
- const bufferResidueCleanup = await dominus.logs.runArchiveBufferMaintenance({
134
- dry_run: false,
135
- confirm: 'DELETE_ARCHIVE_BUFFER_RESIDUE',
136
- salvage_missing_archive: true,
137
- sample_limit: 500,
138
- max_archive_buckets: 24,
139
- batch_runs: 5,
140
- max_runtime_ms: 8000,
141
- });
142
-
143
- const pipeline = await dominus.workflow.executePipeline('pipeline-uuid', {
144
- mode: 'async',
145
- context: { reportRef, workstationId },
146
- });
147
- ```
148
-
149
- - `dominus.workflow.ensure(...)` is the preferred one-call run lifecycle for Authority-backed recipe execution.
150
- - `dominus.authority.getRunTimeline` (and related Authority run APIs) are the preferred namespace for lifecycle truth; `dominus.workflow.getRunTimeline` calls the same route for backward compatibility.
151
- - 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 by `sample_limit`, `max_archive_buckets`, optional `batch_runs`, `max_runtime_ms`, and `confirm='DELETE_ARCHIVE_BUFFER_RESIDUE'`.
152
- - Authority scheduled routes are first-class SDK surface area: use `dominus.authority.listSchedules/createSchedule/updateSchedule/pauseSchedule/resumeSchedule/claimDueSchedules/completeScheduleRun/failScheduleRun` when integrating with the Authority-owned schedule truth plane. Project-facing route schedules should be treated as bounded route calls, not central maintenance packages.
153
- - `dominus.workflow.*` is the saved-workflow facade over workflow-manager.
154
- - `dominus.ai.workflow.*` is raw orchestration for inline workflow definitions only.
155
- - `dominus.workflow.executePipeline()` runs stored pipelines through workflow-manager's native orchestration-backed runner.
156
-
157
- ## Browser Automation
158
-
159
- `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/*`.
160
-
161
- ```ts
162
- const health = await dominus.browser.getHealth();
163
- const run = await dominus.browser.ensureRun({
164
- idempotencyKey: 'route-check-1',
165
- target: { url: 'https://example.com/dashboard' },
166
- provider: 'auto',
167
- mode: 'playwright',
168
- capturePolicy: {
169
- screenshots: 'never',
170
- trace: 'never',
171
- har: 'never',
172
- video: 'never',
173
- domSnapshot: 'never',
174
- rawResponseBodies: 'never',
175
- phiRisk: 'possible',
176
- },
177
- assertions: [{ kind: 'status_code', expected: 200 }],
178
- });
179
- await dominus.browser.startRun(run.run_id);
180
- const status = await dominus.browser.getRunStatus(run.run_id);
181
- const dossier = await dominus.browser.getRunDossier(run.run_id);
182
- ```
183
-
184
- 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.
185
-
186
- ## Configuration
187
-
188
- Required in most environments:
189
-
190
- - `DOMINUS_TOKEN`: service PSK used to mint internal JWTs.
191
-
192
- Optional:
193
-
194
- - `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.
195
- - `DOMINUS_JWT_URL` (defaults to the same host as the gateway), `DOMINUS_LOGS_URL`
196
- - `DOMINUS_HTTP_PROXY`, `DOMINUS_HTTPS_PROXY`
197
- - `DOMINUS_CAPTURE_CONSOLE=true` to auto-forward `console.*` into `dominus.logs`
198
-
199
- ## Per-call timeouts and service-JWT refresh
200
-
201
- The default request timeout is 30 seconds (transport cap: 300000 ms). Long-running
202
- admin operations accept a per-call `timeout` (milliseconds) in their options bag, including
203
- `dominus.workflow.seed({ timeout })` and
204
- `dominus.authority.bootstrapProvisioningTarget(slug, { timeout })` (server-side
205
- budgets for both are 60s). A timed-out call rejects with `TimeoutError`; the
206
- operation may still complete server-side, so treat timeouts as "unknown outcome",
207
- not "failed".
208
-
209
- Operator/orchestration callers that hold the service JWT directly can bypass the
210
- 55-minute mint cache when the backend rejects a token before its local expiry
211
- (e.g. after signing-key rotation):
212
-
213
- ```ts
214
- import { getClient } from 'dominus-sdk-nodejs';
215
-
216
- const jwt = await getClient().mintServiceJwt(); // cached
217
- const fresh = await getClient().mintServiceJwt({ forceRefresh: true }); // re-mints, replaces the cache
218
- ```
219
-
220
- ## Architecture Summary
221
-
222
- - Primary source is `src/` (not `dist/`).
223
- - All namespaces call through `DominusClient` (`src/lib/client.ts`).
224
- - 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.
225
- - Finite workflow/orchestration replay routes may return `text/event-stream`; the client normalizes those responses into event arrays for `events()` helpers.
226
- - Gateway route transform: SDK `/api/*` calls can be routed to gateway `/svc/*` when `useGateway` is enabled.
227
- - Auth model:
228
- - service-to-service: PSK -> minted JWT cache
229
- - user calls: pass `userToken` to namespace methods when required
230
- - Retry + circuit-breaker behavior is implemented in client/cache libraries.
231
-
232
- ## Storage: which namespace do I use?
233
-
234
- `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.
235
-
236
- 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.
237
-
238
- | Your data | Use | Why |
239
- |---|---|---|
240
- | 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. |
241
- | Small independent rows that need a declared schema, typed filters, and bounded updates | `dominus.stash.tables.*` | Managed JSON rows in the resolved self or group database, without raw SQL or a product-owned relational model. |
242
- | 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. |
243
- | Locks, queues, rate counters, short-lived cache — ephemera | `dominus.redis.*` | Building block for ephemeral state; named data belongs in Stash. |
244
- | Building a new kernel backend or a documented migration fallback | primitives (`redis`, `db`, `files`) | The lowest layer; not the place for ordinary application data. |
245
-
246
- ```ts
247
- import { dominus } from 'dominus-sdk-nodejs';
248
-
249
- // Named-kind data -> stash (primary surface).
250
- await dominus.stash.put({
251
- env: 'production',
252
- kind: 'artifact-v1',
253
- scope: 'self',
254
- key: 'reports/2026/summary.json',
255
- value: { status: 'final' },
256
- });
257
-
258
- // One-off structured rows -> managed Stash table.
259
- await dominus.stash.tables.define({
260
- env: 'production',
261
- scope: 'self',
262
- table: 'work_queue',
263
- if_revision: 0,
264
- primary_key: { field: 'id', generate: 'uuid' },
265
- fields: {
266
- id: { type: 'uuid', required: true },
267
- status: { type: 'string', required: true, enum: ['ready', 'running', 'done'] },
268
- priority: { type: 'integer', min: 0, max: 100 },
269
- },
270
- });
271
- const row = await dominus.stash.tables.putRow({
272
- env: 'production',
273
- scope: 'self',
274
- table: 'work_queue',
275
- if_revision: 0,
276
- row: { status: 'ready', priority: 10 },
277
- });
278
- const page = await dominus.stash.tables.select({
279
- env: 'production',
280
- scope: 'self',
281
- table: 'work_queue',
282
- where: {
283
- and: [
284
- { field: 'status', op: 'eq', value: 'ready' },
285
- { field: 'priority', op: 'gte', value: 5 },
286
- ],
287
- },
288
- page_size: 50,
289
- });
290
-
291
- // Direct ar:// addressed artifact workflow -> artifacts (escape hatch).
292
- await dominus.artifacts.storeV2({
293
- group: 'acme',
294
- owner: 'project:00000000-0000-0000-0000-000000000000',
295
- environment: 'production',
296
- kind: 'artifact-v1',
297
- artifactKey: 'reports/2026/summary.json',
298
- data: Buffer.from(JSON.stringify({ status: 'final' })).toString('base64'),
299
- });
300
-
301
- // Locks / queues / cache / ephemera -> redis (building block).
302
- await dominus.redis.set('lock:report-job-42', '1', 60);
303
- ```
304
-
305
- Managed tables intentionally stop before joins, foreign keys, secondary
306
- uniqueness, aggregates, nested JSON querying, or raw SQL. Use a product-owned
307
- relational table when those behaviors are part of correctness. `scope: 'self'`
308
- uses the caller project's database; `scope: 'group'` uses its configured shared
309
- database, with no implicit fallback or union between them. Selection is bounded
310
- and keyset-paginated; pass `next_cursor` back as `cursor` without inspecting it.
311
-
312
- 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.
313
-
314
- ## Namespaces
315
-
316
- SDK singleton namespaces available on `dominus`:
317
-
318
- - `secrets`, `db`, `secure`, `redis`, `files`, `auth`, `ddl`, `logs`, `portal`, `courier`, `open`, `health`, `admin`, `ai`, `workflow`, `sync`, `jobs`, `processor`, `artifacts`, `authority`, `browser`, `deployer`, `warden`, `stash` (including `stash.tables`), `platform`, `coder`
319
-
320
- 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.
321
-
322
- 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.
323
-
324
- 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.
325
-
326
- 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:
327
-
328
- ```ts
329
- await dominus.authority.listDeploys();
330
- await dominus.deployer.request('/configs', { method: 'GET' });
331
- await dominus.warden.request('/users', {
332
- method: 'POST',
333
- body: { email: 'operator@example.com' },
334
- });
335
- ```
336
-
337
- 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.
338
-
339
- 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`.
340
-
341
- Root shortcuts are also exposed for common secrets/db/ddl methods (`get`, `upsert`, `listTables`, `queryTable`, etc.).
342
-
343
- Courier is provider-agnostic. The namespace supports both the legacy send helpers and the courier admin plane used by Mothership:
344
-
345
- - project mail config
346
- - sender identities
347
- - template CRUD and render preview
348
- - delivery history
349
-
350
- ## Documentation
351
-
352
- - [Architecture](./docs/architecture.md)
353
- - [Routes/Services/Endpoints Assessment](./docs/routes-services.md)
354
- - [Comprehensive Usage Reference (all namespaced commands)](./docs/usage-reference.md)
355
- - [Workflow hard-cut release notes](./docs/workflow-hard-cut-release.md)
356
-
357
- ## Development
358
-
359
- ```bash
360
- npm ci
361
- npm run build
362
- npm run lint
363
- npm test
364
- ```
365
-
366
- CI publish workflows exist for `development`, `staging`, and `production` branches under `.github/workflows/`.
367
-
368
- ## Notes
369
-
370
- - Speech-to-text and text-to-speech live under `dominus.ai` (`ai.stt`, `ai.tts`) through agent-runtime.
371
- - Contract tests cover the saved-workflow facade and the addressed artifact V2 helper surface.
1
+ # Dominus SDK for Node.js
2
+
3
+ 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.
4
+
5
+ **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.
6
+
7
+ ## Agent Guide
8
+
9
+ Coding agents: start with `docs/agent-guide/INDEX.md`. The current snapshot is
10
+ `docs/agent-guide/2026-08-04-sdk-nodejs/00-reading-order.md`; the latest
11
+ cleanup audit is `docs/janitor/2026-08-04-sdk-nodejs-cleanup-audit.md`.
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ npm install dominus-sdk-nodejs
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ Token-required hello using only the developer-stable catalog verbs. Set project
22
+ scope with `DOMINUS_PROJECT` or CLI `select_project`. Other SDK namespaces exist
23
+ for operators and advanced use; this path is the stable teaching surface. The
24
+ catalog publishes the same lower-camel method names used by TypeScript callers.
25
+
26
+ Set both values before the Node.js process imports the SDK singleton:
27
+
28
+ ```bash
29
+ export DOMINUS_USER_TOKEN="your-user-token"
30
+ export DOMINUS_PROJECT="your-project-slug"
31
+ ```
32
+
33
+ ```ts
34
+ import { dominus } from 'dominus-sdk-nodejs';
35
+
36
+ const run = await dominus.workflow.ensure({
37
+ workflowRecipeRef: 'recipe://workflow-recipe-v1/hello@v1',
38
+ });
39
+
40
+ await dominus.stash.put({
41
+ env: 'production',
42
+ kind: 'config',
43
+ scope: 'self',
44
+ key: 'hello',
45
+ value: { greeting: 'hello' },
46
+ });
47
+ await dominus.stash.getItem({
48
+ env: 'production',
49
+ kind: 'config',
50
+ scope: 'self',
51
+ key: 'hello',
52
+ });
53
+
54
+ const runId = String((run as { run_id?: string }).run_id ?? '');
55
+ const timeline = await dominus.authority.getRunTimeline(runId);
56
+ const verdict = await dominus.authority.getRunVerdict(runId);
57
+ ```
58
+
59
+ ## Workflow Lifecycle
60
+
61
+ Use the Authority-backed one-call lifecycle for normal application code. The legacy saved-workflow run chain is retired.
62
+
63
+ ```ts
64
+ const execution = await dominus.workflow.ensure({
65
+ workflowRecipeRef: 'recipe://workflow-recipe-v1/report-cycle@v3',
66
+ subject: 'PCM47474562',
67
+ company: 'summit-radiology',
68
+ inputs: {
69
+ report_snapshot: 'ar://carebridge/summit-radiology/production/snapshot/report-1',
70
+ },
71
+ });
72
+ const runState = await dominus.workflow.getRunState(execution.run_id);
73
+ const timeline = await dominus.authority.getRunTimeline(execution.run_id, {
74
+ since: '2026-04-11T08:33:00Z',
75
+ until: '2026-04-11T09:33:00Z',
76
+ });
77
+ const timelineArchive = await dominus.authority.getTimelineArchiveStatus({
78
+ appSlug: 'carebridge-summit',
79
+ env: 'production',
80
+ });
81
+ const logsArchive = await dominus.logs.getArchiveStatus({
82
+ all_scopes: true,
83
+ include_buffer: true,
84
+ limit: 5,
85
+ });
86
+ const machineLogs = await dominus.logs.tail({
87
+ machine_id: 'mach-abc-123',
88
+ since: '2026-04-11T08:33:00Z',
89
+ level: 'error',
90
+ });
91
+ const policy = await dominus.platform.ensurePolicyDecision({
92
+ group: 'dominus',
93
+ repository: 'carebridgesystems/dominus-platform-worker',
94
+ }, { type: 'user', id: 'operator-1' });
95
+ const coderRun = await dominus.coder.ensureRun({
96
+ policyDecisionId: String(policy.data.policy_decision.decision_id),
97
+ workflowRecipeRef: 'recipe://workflow-recipe-v1/coder-feature@head',
98
+ repository: 'carebridgesystems/dominus-platform-worker',
99
+ instructions: 'Fix failing tests',
100
+ actorContext: { type: 'user', id: 'operator-1' },
101
+ });
102
+ const verifyArchive = await dominus.authority.verifyTimelineArchiveManifests({
103
+ since: '2026-04-01T00:00:00Z',
104
+ until: '2026-04-02T00:00:00Z',
105
+ });
106
+ const pruneDryRun = await dominus.logs.pruneArchiveRetention({
107
+ retention_days: 90,
108
+ dry_run: true,
109
+ });
110
+ const bufferResidueProof = await dominus.logs.dryRunArchiveBufferMaintenance({
111
+ sample_limit: 100,
112
+ });
113
+ const bufferResidueCleanup = await dominus.logs.runArchiveBufferMaintenance({
114
+ dry_run: false,
115
+ confirm: 'DELETE_ARCHIVE_BUFFER_RESIDUE',
116
+ salvage_missing_archive: true,
117
+ sample_limit: 500,
118
+ max_archive_buckets: 24,
119
+ batch_runs: 5,
120
+ max_runtime_ms: 8000,
121
+ });
122
+
123
+ const pipeline = await dominus.workflow.executePipeline('pipeline-uuid', {
124
+ mode: 'async',
125
+ context: { reportRef, workstationId },
126
+ });
127
+ ```
128
+
129
+ - `dominus.workflow.ensure(...)` is the preferred one-call run lifecycle for Authority-backed recipe execution.
130
+ - `dominus.authority.getRunTimeline` (and related Authority run APIs) are the preferred namespace for lifecycle truth; `dominus.workflow.getRunTimeline` calls the same route for backward compatibility.
131
+ - 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 by `sample_limit`, `max_archive_buckets`, optional `batch_runs`, `max_runtime_ms`, and `confirm='DELETE_ARCHIVE_BUFFER_RESIDUE'`.
132
+ - Authority scheduled routes are first-class SDK surface area: use `dominus.authority.listSchedules/createSchedule/updateSchedule/pauseSchedule/resumeSchedule/claimDueSchedules/completeScheduleRun/failScheduleRun` when integrating with the Authority-owned schedule truth plane. Project-facing route schedules should be treated as bounded route calls, not central maintenance packages.
133
+ - `dominus.workflow.*` is the saved-workflow facade over workflow-manager.
134
+ - `dominus.ai.workflow.*` is raw orchestration for inline workflow definitions only.
135
+ - `dominus.workflow.executePipeline()` runs stored pipelines through workflow-manager's native orchestration-backed runner.
136
+
137
+ ## Browser Automation
138
+
139
+ `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/*`.
140
+
141
+ ```ts
142
+ const health = await dominus.browser.getHealth();
143
+ const run = await dominus.browser.ensureRun({
144
+ idempotencyKey: 'route-check-1',
145
+ target: { url: 'https://example.com/dashboard' },
146
+ provider: 'auto',
147
+ mode: 'playwright',
148
+ capturePolicy: {
149
+ screenshots: 'never',
150
+ trace: 'never',
151
+ har: 'never',
152
+ video: 'never',
153
+ domSnapshot: 'never',
154
+ rawResponseBodies: 'never',
155
+ phiRisk: 'possible',
156
+ },
157
+ assertions: [{ kind: 'status_code', expected: 200 }],
158
+ });
159
+ await dominus.browser.startRun(run.run_id);
160
+ const status = await dominus.browser.getRunStatus(run.run_id);
161
+ const dossier = await dominus.browser.getRunDossier(run.run_id);
162
+ ```
163
+
164
+ 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.
165
+
166
+ ## Configuration
167
+
168
+ Required in most environments:
169
+
170
+ - `DOMINUS_TOKEN`: service PSK used to mint internal JWTs.
171
+
172
+ Optional:
173
+
174
+ - `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.
175
+ - `DOMINUS_JWT_URL` (defaults to the same host as the gateway), `DOMINUS_LOGS_URL`
176
+ - `DOMINUS_HTTP_PROXY`, `DOMINUS_HTTPS_PROXY`
177
+ - `DOMINUS_CAPTURE_CONSOLE=true` to auto-forward `console.*` into `dominus.logs`
178
+
179
+ ## Per-call timeouts and service-JWT refresh
180
+
181
+ The default request timeout is 30 seconds (transport cap: 300000 ms). Long-running
182
+ admin operations accept a per-call `timeout` (milliseconds) in their options bag, including
183
+ `dominus.workflow.seed({ timeout })` and
184
+ `dominus.authority.bootstrapProvisioningTarget(slug, { timeout })` (server-side
185
+ budgets for both are 60s). A timed-out call rejects with `TimeoutError`; the
186
+ operation may still complete server-side, so treat timeouts as "unknown outcome",
187
+ not "failed".
188
+
189
+ Operator/orchestration callers that hold the service JWT directly can bypass the
190
+ 55-minute mint cache when the backend rejects a token before its local expiry
191
+ (e.g. after signing-key rotation):
192
+
193
+ ```ts
194
+ import { getClient } from 'dominus-sdk-nodejs';
195
+
196
+ const jwt = await getClient().mintServiceJwt(); // cached
197
+ const fresh = await getClient().mintServiceJwt({ forceRefresh: true }); // re-mints, replaces the cache
198
+ ```
199
+
200
+ ## Architecture Summary
201
+
202
+ - Primary source is `src/` (not `dist/`).
203
+ - All namespaces call through `DominusClient` (`src/lib/client.ts`).
204
+ - 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.
205
+ - Finite workflow/orchestration replay routes may return `text/event-stream`; the client normalizes those responses into event arrays for `events()` helpers.
206
+ - Gateway route transform: SDK `/api/*` calls can be routed to gateway `/svc/*` when `useGateway` is enabled.
207
+ - Auth model:
208
+ - service-to-service: PSK -> minted JWT cache
209
+ - user calls: pass `userToken` to namespace methods when required
210
+ - Retry + circuit-breaker behavior is implemented in client/cache libraries.
211
+
212
+ ## Storage: which namespace do I use?
213
+
214
+ `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.
215
+
216
+ 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.
217
+
218
+ | Your data | Use | Why |
219
+ |---|---|---|
220
+ | 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. |
221
+ | Small independent rows that need a declared schema, typed filters, and bounded updates | `dominus.stash.tables.*` | Managed JSON rows in the resolved self or group database, without raw SQL or a product-owned relational model. |
222
+ | 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. |
223
+ | Locks, queues, rate counters, short-lived cache ephemera | `dominus.redis.*` | Building block for ephemeral state; named data belongs in Stash. |
224
+ | Building a new kernel backend or a documented migration fallback | primitives (`redis`, `db`, `files`) | The lowest layer; not the place for ordinary application data. |
225
+
226
+ ```ts
227
+ import { dominus } from 'dominus-sdk-nodejs';
228
+
229
+ // Named-kind data -> stash (primary surface).
230
+ await dominus.stash.put({
231
+ env: 'production',
232
+ kind: 'artifact-v1',
233
+ scope: 'self',
234
+ key: 'reports/2026/summary.json',
235
+ value: { status: 'final' },
236
+ });
237
+
238
+ // One-off structured rows -> managed Stash table.
239
+ await dominus.stash.tables.define({
240
+ env: 'production',
241
+ scope: 'self',
242
+ table: 'work_queue',
243
+ if_revision: 0,
244
+ primary_key: { field: 'id', generate: 'uuid' },
245
+ fields: {
246
+ id: { type: 'uuid', required: true },
247
+ status: { type: 'string', required: true, enum: ['ready', 'running', 'done'] },
248
+ priority: { type: 'integer', min: 0, max: 100 },
249
+ },
250
+ });
251
+ const row = await dominus.stash.tables.putRow({
252
+ env: 'production',
253
+ scope: 'self',
254
+ table: 'work_queue',
255
+ if_revision: 0,
256
+ row: { status: 'ready', priority: 10 },
257
+ });
258
+ const page = await dominus.stash.tables.select({
259
+ env: 'production',
260
+ scope: 'self',
261
+ table: 'work_queue',
262
+ where: {
263
+ and: [
264
+ { field: 'status', op: 'eq', value: 'ready' },
265
+ { field: 'priority', op: 'gte', value: 5 },
266
+ ],
267
+ },
268
+ page_size: 50,
269
+ });
270
+
271
+ // Direct ar:// addressed artifact workflow -> artifacts (escape hatch).
272
+ await dominus.artifacts.storeV2({
273
+ group: 'acme',
274
+ owner: 'project:00000000-0000-0000-0000-000000000000',
275
+ environment: 'production',
276
+ kind: 'artifact-v1',
277
+ artifactKey: 'reports/2026/summary.json',
278
+ data: Buffer.from(JSON.stringify({ status: 'final' })).toString('base64'),
279
+ });
280
+
281
+ // Locks / queues / cache / ephemera -> redis (building block).
282
+ await dominus.redis.set('lock:report-job-42', '1', 60);
283
+ ```
284
+
285
+ Managed tables intentionally stop before joins, foreign keys, secondary
286
+ uniqueness, aggregates, nested JSON querying, or raw SQL. Use a product-owned
287
+ relational table when those behaviors are part of correctness. `scope: 'self'`
288
+ uses the caller project's database; `scope: 'group'` uses its configured shared
289
+ database, with no implicit fallback or union between them. Selection is bounded
290
+ and keyset-paginated; pass `next_cursor` back as `cursor` without inspecting it.
291
+
292
+ 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.
293
+
294
+ ## Namespaces
295
+
296
+ SDK singleton namespaces available on `dominus`:
297
+
298
+ - `secrets`, `db`, `secure`, `redis`, `files`, `auth`, `ddl`, `logs`, `portal`, `courier`, `open`, `health`, `admin`, `ai`, `workflow`, `sync`, `jobs`, `processor`, `artifacts`, `authority`, `browser`, `deployer`, `warden`, `stash` (including `stash.tables`), `platform`, `coder`
299
+
300
+ 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.
301
+
302
+ 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.
303
+
304
+ 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.
305
+
306
+ 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:
307
+
308
+ ```ts
309
+ await dominus.authority.listDeploys();
310
+ await dominus.deployer.request('/configs', { method: 'GET' });
311
+ await dominus.warden.request('/users', {
312
+ method: 'POST',
313
+ body: { email: 'operator@example.com' },
314
+ });
315
+ ```
316
+
317
+ 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.
318
+
319
+ 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`.
320
+
321
+ Root shortcuts are also exposed for common secrets/db/ddl methods (`get`, `upsert`, `listTables`, `queryTable`, etc.).
322
+
323
+ Courier is provider-agnostic. The namespace supports both the legacy send helpers and the courier admin plane used by Mothership:
324
+
325
+ - project mail config
326
+ - sender identities
327
+ - template CRUD and render preview
328
+ - delivery history
329
+
330
+ ## Documentation
331
+
332
+ - [Architecture](./docs/architecture.md)
333
+ - [Routes/Services/Endpoints Assessment](./docs/routes-services.md)
334
+ - [Comprehensive Usage Reference (all namespaced commands)](./docs/usage-reference.md)
335
+ - [Workflow hard-cut release notes](./docs/workflow-hard-cut-release.md)
336
+
337
+ ## Development
338
+
339
+ ```bash
340
+ npm ci
341
+ npm run build
342
+ npm run lint
343
+ npm test
344
+ ```
345
+
346
+ CI publish workflows exist for `development`, `staging`, and `production` branches under `.github/workflows/`.
347
+
348
+ ## Notes
349
+
350
+ - Speech-to-text and text-to-speech live under `dominus.ai` (`ai.stt`, `ai.tts`) through agent-runtime.
351
+ - Contract tests cover the saved-workflow facade and the addressed artifact V2 helper surface.