verdifax 0.3.0 → 1.0.0

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.
package/README.md CHANGED
@@ -49,17 +49,131 @@ if (v.verified) {
49
49
  | --- | --- | --- |
50
50
  | `client.health()` | `GET /health` | none |
51
51
  | `client.version()` | `GET /version` | none |
52
+ | `client.getOpenAPI()` | `GET /openapi.json` | none |
53
+ | `client.getStats()` | `GET /stats` | required |
52
54
  | `client.execute(req)` | `POST /execute` | required |
55
+ | `client.attest(req)` | `POST /execute` | required |
56
+ | `client.attestClaudeResponse(args)` | `POST /execute` | required |
57
+ | `client.attestOpenAIResponse(args)` | `POST /execute` | required |
58
+ | `client.executeBatch(runs)` | `POST /execute/batch` | required |
59
+ | `client.verifyDeterminism(req)` | `POST /execute/verify-determinism` | required |
53
60
  | `client.getRun(id)` | `GET /runs/{id}` | required |
54
61
  | `client.verifyRun(id)` | `GET /runs/{id}/verify` | required |
62
+ | `client.listRuns(params)` | `GET /runs` | required |
63
+ | `client.searchRuns(params)` | `GET /runs/search` | required |
64
+ | `client.exportRuns(params)` | `GET /runs/export` | required |
65
+ | `client.exportRunsCSV(params)` | `GET /runs/export?format=csv` | required |
66
+ | `client.getRunArtifacts(id)` | `GET /runs/{id}/artifacts` | required |
67
+ | `client.getRunReport(id)` | `GET /runs/{id}/report` | required |
68
+ | `client.downloadAuditPDF(id, format)` | `GET /runs/{id}/report.pdf` | required |
69
+ | `client.getAllowToken(id)` | `GET /runs/{id}/allow-token` | required |
70
+ | `client.getDenyReceipt(id)` | `GET /runs/{id}/deny-receipt` | required |
71
+ | `client.getCCVHaltReceipt(id)` | `GET /runs/{id}/ccv-halt-receipt` | required |
72
+ | `client.getMACCHaltReceipt(id)` | `GET /runs/{id}/macc-halt-receipt` | required |
73
+ | `client.getAivpT4HaltReceipt(id)` | `GET /runs/{id}/aivp-t4-halt-receipt` | required |
74
+ | `client.getAttestationGapReceipt(id)` | `GET /runs/{id}/attestation-gap-receipt` | required |
75
+ | `client.getCESAuditRecord(id)` | `GET /runs/{id}/ces-audit-record` | required |
76
+ | `client.listDeletionReceipts(id)` | `GET /runs/{id}/deletion-receipts` | required |
77
+ | `client.listAttestations(params)` | `GET /attestations` | required |
78
+ | `client.getAttestation(id)` | `GET /attestations/{id}` | required |
79
+ | `client.getPublicBundle(id)` | `GET /runs/{id}/bundle.json` | none |
80
+ | `client.getPublicBundleByToken(token)` | `GET /public/runs/{token}/bundle.json` | none |
81
+ | `client.dcaeVerify(bundle)` | `POST /dcae/verify` | none |
55
82
  | `client.registerRequestKey()` | `POST /keys/request-key` | required |
56
83
  | `client.clearRequestKey()` | `DELETE /keys/request-key` | required |
84
+ | `client.adminCreateKey(name)` | `POST /admin/keys` | admin |
85
+ | `client.adminListKeys()` | `GET /admin/keys` | admin |
86
+ | `client.adminRevokeKey(id)` | `DELETE /admin/keys/{id}` | admin |
87
+ | `client.adminErase(req)` | `POST /admin/erase` | admin |
57
88
 
58
- The full HTTP surface (every endpoint, deletion-receipt list,
59
- DCAE verify, admin endpoints) is documented in the
60
- [OpenAPI spec](https://github.com/Verdifax/verdifax-orchestrator/blob/main/openapi/verdifax.yaml).
61
- This SDK ships the canonical operations; broader coverage lands
62
- as integrators ask.
89
+ These functions make no request: `captureEnvironment`, `formatProviderPayload`, `signRequest`, `requestKeyRegistrationBody`, `requestSignaturePreimage`, `generateRequestKeyPair`, `validateHex64`, `validateRouteId`, `dseDispatchHash`, `dcaeClosureHash` and `cresReceiptHash`. `RUN_STATUSES` lists every run status the server uses.
90
+
91
+ `getRunArtifacts`, `getPublicBundle` and `getPublicBundleByToken` return the exact JSON text the server sent, so you can save it and check it with `verdifax-verify`.
92
+
93
+ ## Versioning
94
+
95
+ From 1.0, a breaking change needs a new major version.
96
+
97
+ ## Settings
98
+
99
+ `new VerdifaxClient(config)` takes these options. `fromEnv()` reads the same settings from the environment.
100
+
101
+ | Setting | Option | Environment variable | Default |
102
+ | --- | --- | --- | --- |
103
+ | Base URL | `baseURL` | `VERDIFAX_BASE_URL`, then `VERDIFAX_API_URL` | `https://api.verdifax.com` |
104
+ | API key | `apiKey` | `VERDIFAX_API_KEY` | none |
105
+ | Timeout | `timeoutMs` | `VERDIFAX_TIMEOUT_MS` | 90 seconds |
106
+ | User agent | `userAgent` | `VERDIFAX_USER_AGENT` | `verdifax-sdk-node/<version>` |
107
+ | Retries | `maxRetries` | `VERDIFAX_MAX_RETRIES` | 3 |
108
+ | First retry delay | `retryBaseDelayMs` | none | 200 ms |
109
+
110
+ GET, HEAD and OPTIONS requests are retried after a network failure or an HTTP 429, 502, 503 or 504, with exponential backoff and full jitter. POST is never retried.
111
+
112
+ ## Batch runs
113
+
114
+ `executeBatch(runs)` sends up to 1,000 runs in one request and refuses more before sending anything. A row that fails comes back in `results` with `ok: false`, so the call does not throw for it.
115
+
116
+ ```typescript
117
+ const batch = await client.executeBatch([
118
+ { program_id, route_id, registry_record_hash, payload_text: "first" },
119
+ { program_id, route_id, registry_record_hash, payload_text: "second" },
120
+ ]);
121
+
122
+ for (const row of batch.results) {
123
+ console.log(row.index, row.ok, row.ok ? row.run_id : row.error);
124
+ }
125
+ ```
126
+
127
+ The client's timeout covers the whole batch, so raise `timeoutMs` for a large one. A batch is one POST and it is never retried. After a timeout the server may have run some or all of the rows, so list your runs before you send them again.
128
+
129
+ ## Evidence export
130
+
131
+ `exportRuns` lists the runs the server holds for your key in a period, failures included, with up to 10,000 rows per export. `exportRunsCSV` returns the same rows as raw CSV text.
132
+
133
+ ```typescript
134
+ const period = { from: "2026-11-01T00:00:00Z", to: "2026-12-01T00:00:00Z" };
135
+
136
+ const evidence = await client.exportRuns(period);
137
+ console.log(evidence.total, evidence.truncated, evidence.by_status);
138
+
139
+ const { csv, total, truncated } = await client.exportRunsCSV(period);
140
+ if (truncated) {
141
+ console.log(`The CSV holds part of ${total} runs. Use a narrower period.`);
142
+ }
143
+ ```
144
+
145
+ The export states what the server stored, not a verdict. A call that never reached Verdifax cannot appear in it. Both forms say when a period holds more rows than the export returned: check `truncated`. `exportRunsCSV` reads `total` and `truncated` from the `X-Verdifax-Total` and `X-Verdifax-Truncated` response headers, and throws if the server does not send them. In the CSV, a `route_id` that a spreadsheet could read as a formula gets a leading `'`.
146
+
147
+ ## Provider helpers
148
+
149
+ `attestClaudeResponse` and `attestOpenAIResponse` attest a prompt and response as one payload: canonical JSON, exactly `{"prompt":...,"provider":...,"response":...}` with sorted keys and no extra whitespace, UTF-8, with `provider` set to `anthropic` or `openai`. `formatProviderPayload` builds that text. All four Verdifax SDKs produce the same bytes. A helper call from an earlier version used a different payload, so it gave a different hash for the same text; records already stored are not touched.
150
+
151
+ ```typescript
152
+ await client.attestClaudeResponse({
153
+ program_id,
154
+ route_id,
155
+ registry_record_hash,
156
+ prompt: "What is the boiling point of water?",
157
+ response: "100 C at sea level.",
158
+ govern: true,
159
+ });
160
+ ```
161
+
162
+ `govern` is false by default, which changes earlier behavior. Set `govern: true` to also send the response text as `ai_output_text` for the AIVP review, which runs on Anthropic in production. Without it, the AI output text is not sent for review.
163
+
164
+ ## Optional execute fields
165
+
166
+ `execute`, `attest`, `executeBatch` and `verifyDeterminism` accept `attested_context`, `reproducibility_context`, `request_substance`, `authorization_chain`, `regulatory_scaffolding` and `causal_graph`. Each is recorded as supplied and Verdifax does not check it. The client derives `attested` and `declared` from the fields you provide. Leave out `request_substance.origin.source_ip_hash` and `user_agent_hash`: the server computes them. `execute`, `attest` and `verifyDeterminism` refuse them before sending, and a batch row that sets them fails in `results`.
167
+
168
+ `execute`, `attest` and `verifyDeterminism` check that `program_id` and `registry_record_hash` are 64 lowercase hex characters and that `route_id` is 1 to 256 printable ASCII characters.
169
+
170
+ ## Environment capture
171
+
172
+ `captureEnvironment()` records the Node version, the platform, the packages under `node_modules`, the git commit and any seeds you declare. Pass the result as `reproducibility_context` on `execute`, `attest`, `executeBatch` or `verifyDeterminism`. Detection is best effort, and a value it cannot read is left out. The server records these values as given and does not check them.
173
+
174
+ ## Determinism check
175
+
176
+ `verifyDeterminism(req)` runs one payload twice on the server and compares the manifest hashes. `deterministic` is true when both runs ended `ok` and the two hashes match. Both runs are recorded, with the status `probe`.
63
177
 
64
178
  ## Authentication
65
179
 
@@ -117,7 +231,8 @@ const client = new VerdifaxClient({
117
231
 
118
232
  await client.registerRequestKey(); // sends the public key with its proof
119
233
 
120
- // execute, attest, attestClaudeResponse and attestOpenAIResponse now sign.
234
+ // execute, attest, attestClaudeResponse, attestOpenAIResponse, executeBatch
235
+ // and verifyDeterminism now sign.
121
236
  await client.execute({
122
237
  program_id: "1111111111111111111111111111111111111111111111111111111111111111",
123
238
  route_id: "demo-attestation",
@@ -130,6 +245,8 @@ await client.clearRequestKey(); // stops requiring signatures on this API key
130
245
 
131
246
  Registering a key changes that API key for every client that uses it: the server then refuses a run without a valid signature, so every caller on the key needs the private key. Each request carries the time and a fresh random nonce. The server refuses a repeated nonce and a time more than five minutes from its own clock.
132
247
 
248
+ In a batch each row carries its own signature and nonce, and the server checks them as it reaches that row. A row refused for its signature comes back in `results`, so a repeated batch returns HTTP 200 with failed rows, and a row reached more than five minutes after it was signed fails the same way. A determinism check uses one signature for the request, and repeating it returns HTTP 403.
249
+
133
250
  The signature shows the holder of the key requested the run. It does not show the key holder accepted the outcome.
134
251
 
135
252
  ## Trust model
package/dist/index.d.mts CHANGED
@@ -48,11 +48,46 @@ interface ExecuteRequest {
48
48
  registry_record_hash: Hex64;
49
49
  /** When non-empty, opts the request into the AIVP governance pipeline. */
50
50
  ai_output_text?: string;
51
- /** Caller-attested actor + decision metadata; open schema. */
51
+ /** Caller-attested actor + decision metadata; open schema. The client
52
+ * derives `attested` from whether any other field is provided. */
52
53
  attested_context?: Record<string, unknown>;
54
+ /** Caller-declared runtime fingerprint, recorded in the audit bundle.
55
+ * Build it with {@link captureEnvironment}. */
56
+ reproducibility_context?: ReproducibilityContext;
57
+ /** Caller-supplied substance of the request: prompt, output, cost,
58
+ * latency and origin metadata. Recorded as supplied. Leave out
59
+ * `origin.source_ip_hash` and `origin.user_agent_hash`: the server
60
+ * computes those and refuses them. */
61
+ request_substance?: Record<string, unknown>;
62
+ /** Caller-supplied approval chain. Recorded as supplied, not verified
63
+ * by Verdifax. */
64
+ authorization_chain?: Record<string, unknown>;
65
+ /** Caller-supplied regulatory metadata. Recorded as supplied, not an
66
+ * assessment by Verdifax. */
67
+ regulatory_scaffolding?: Record<string, unknown>;
68
+ /** Caller-supplied record of what led to this run. Recorded as
69
+ * supplied. */
70
+ causal_graph?: Record<string, unknown>;
53
71
  /** Filled in by the client when the `signingKey` option is set. */
54
72
  request_signature?: RequestSignature;
55
73
  }
74
+ /** The runtime a caller declares for a run. Every field is optional.
75
+ * The server records these values as given and does not check them. */
76
+ interface ReproducibilityContext {
77
+ /** True when any other field has a value. The client derives this. */
78
+ declared?: boolean;
79
+ /** 64 hex characters, without the `sha256:` prefix. */
80
+ container_image_hash?: string;
81
+ runtime_name?: string;
82
+ runtime_version?: string;
83
+ /** `name==version` strings, sorted. */
84
+ pinned_dependencies?: string[];
85
+ git_commit_sha?: string;
86
+ /** `library=seed` strings, sorted. */
87
+ random_seeds?: string[];
88
+ /** GOOS/GOARCH style, for example `linux/amd64`. */
89
+ platform?: string;
90
+ }
56
91
  /** The signature an API key with a registered request key must carry.
57
92
  * The public key comes from the registration, never from the request. */
58
93
  interface RequestSignature {
@@ -88,6 +123,60 @@ interface ExecuteResponse {
88
123
  manifest: ExecutionManifest;
89
124
  duration_ms: number;
90
125
  }
126
+ /** One row of {@link ExecuteBatchResponse}. A successful row has
127
+ * `manifest`. A failed row has `error`, and `error_stage` and a typed
128
+ * receipt when the pipeline halted. A row refused before it ran has
129
+ * no `run_id`. */
130
+ interface ExecuteBatchResult {
131
+ index: number;
132
+ ok: boolean;
133
+ run_id?: number;
134
+ manifest_hash?: Hex64;
135
+ manifest?: ExecutionManifest;
136
+ error?: string;
137
+ error_stage?: string;
138
+ duration_ms: number;
139
+ partial_manifest?: ExecutionManifest;
140
+ deny_receipt?: Record<string, unknown>;
141
+ ccv_halt_receipt?: Record<string, unknown>;
142
+ macc_halt_receipt?: Record<string, unknown>;
143
+ aivp_t4_halt_receipt?: Record<string, unknown>;
144
+ attestation_gap_receipt?: Record<string, unknown>;
145
+ }
146
+ /** Body returned by POST /execute/batch. */
147
+ interface ExecuteBatchResponse {
148
+ ok: boolean;
149
+ total: number;
150
+ successful: number;
151
+ failed: number;
152
+ duration_ms: number;
153
+ results: ExecuteBatchResult[];
154
+ }
155
+ /** One of the two runs of a determinism check. */
156
+ interface DeterminismRun {
157
+ run_id: number;
158
+ manifest_hash: string;
159
+ bundle_hash: string;
160
+ duration_ms: number;
161
+ status: string;
162
+ error?: string;
163
+ }
164
+ /** How the two runs of a determinism check compared. */
165
+ interface DeterminismDiff {
166
+ differs: boolean;
167
+ manifest_hash_differs: boolean;
168
+ bundle_hash_differs: boolean;
169
+ differing_fields?: string[];
170
+ }
171
+ /** Body returned by POST /execute/verify-determinism. `deterministic`
172
+ * means both runs ended ok with equal manifest hashes. */
173
+ interface VerifyDeterminismResponse {
174
+ ok: boolean;
175
+ deterministic: boolean;
176
+ first: DeterminismRun;
177
+ second: DeterminismRun;
178
+ diff: DeterminismDiff;
179
+ }
91
180
  /**
92
181
  * Sealed manifest. Field names match the orchestrator's Go-default
93
182
  * JSON encoding (CapitalCamelCase).
@@ -121,6 +210,12 @@ interface ExecutionManifest {
121
210
  LedgerProofHash?: Hex64;
122
211
  LogEntryID?: string;
123
212
  }
213
+ /** Every status the server gives a run. */
214
+ declare const RUN_STATUSES: readonly ["ok", "probe", "pepg_deny", "ccv_halt", "macc_halt", "aivp_t4_halt", "attestation_gap", "stage_error"];
215
+ /** A run's status: one of {@link RUN_STATUSES}, or a value a newer server
216
+ * adds. Written with `string & {}` so editors still offer the known
217
+ * values and any string can be compared. */
218
+ type RunStatus = (typeof RUN_STATUSES)[number] | (string & {});
124
219
  interface Run {
125
220
  ok: boolean;
126
221
  id: number;
@@ -130,7 +225,7 @@ interface Run {
130
225
  route_id: string;
131
226
  manifest_hash: Hex64;
132
227
  duration_ms: number;
133
- status: "ok" | "pepg_deny" | "ccv_halt" | "macc_halt" | "stage_error";
228
+ status: RunStatus;
134
229
  error_stage?: string;
135
230
  error_message?: string;
136
231
  manifest: ExecutionManifest;
@@ -184,6 +279,11 @@ interface AttestRequest {
184
279
  registry_record_hash: Hex64;
185
280
  ai_output_text?: string;
186
281
  attested_context?: Record<string, unknown>;
282
+ reproducibility_context?: ReproducibilityContext;
283
+ request_substance?: Record<string, unknown>;
284
+ authorization_chain?: Record<string, unknown>;
285
+ regulatory_scaffolding?: Record<string, unknown>;
286
+ causal_graph?: Record<string, unknown>;
187
287
  }
188
288
  /** Optional filters for {@link VerdifaxClient.listRuns}. */
189
289
  interface ListRunsParams {
@@ -199,8 +299,94 @@ interface RunSummary {
199
299
  program_id: Hex64;
200
300
  route_id: string;
201
301
  manifest_hash: Hex64;
202
- status: "ok" | "pepg_deny" | "ccv_halt" | "macc_halt" | "stage_error";
302
+ status: RunStatus;
203
303
  outcome_kind?: string;
304
+ duration_ms?: number;
305
+ error_stage?: string;
306
+ execution_region?: string;
307
+ }
308
+ /** Optional filters for {@link VerdifaxClient.searchRuns}. `from` and
309
+ * `to` are RFC 3339 times. */
310
+ interface SearchRunsParams {
311
+ /** Matches manifest hashes that start with this value. */
312
+ manifest_hash?: string;
313
+ program_id?: Hex64;
314
+ route_id?: string;
315
+ status?: string;
316
+ from?: string;
317
+ to?: string;
318
+ limit?: number;
319
+ offset?: number;
320
+ }
321
+ /** Period for {@link VerdifaxClient.exportRuns} and
322
+ * {@link VerdifaxClient.exportRunsCSV}, as RFC 3339 times. `from` is
323
+ * inclusive and `to` is exclusive. `to` defaults to the time of the
324
+ * request. */
325
+ interface ExportRunsParams {
326
+ from?: string;
327
+ to?: string;
328
+ }
329
+ /** One run in an evidence export: what the server stored, not a verdict. */
330
+ interface ExportRow {
331
+ run_id: number;
332
+ created_at: string;
333
+ status: RunStatus;
334
+ error_stage: string;
335
+ route_id: string;
336
+ manifest_hash: string;
337
+ log_entry_id: string;
338
+ leaf_hash: string;
339
+ complete_record_entry_id: string;
340
+ complete_record_leaf_hash: string;
341
+ }
342
+ /** Body returned by GET /runs/export in JSON form. */
343
+ interface RunsExport {
344
+ ok: boolean;
345
+ /** The upper bound the server used for this export. */
346
+ to: string;
347
+ /** Runs held for the period. */
348
+ total: number;
349
+ /** Rows in this response. */
350
+ returned: number;
351
+ /** True when the period holds more rows than this response. */
352
+ truncated: boolean;
353
+ /** Rows returned, counted by status. */
354
+ by_status: Record<string, number>;
355
+ runs: ExportRow[];
356
+ }
357
+ /** Returned by {@link VerdifaxClient.exportRunsCSV}. */
358
+ interface RunsExportCSV {
359
+ /** The CSV text, unparsed. */
360
+ csv: string;
361
+ /** Runs held for the period. */
362
+ total: number;
363
+ /** True when the period holds more rows than `csv`. */
364
+ truncated: boolean;
365
+ }
366
+ /** Optional paging for {@link VerdifaxClient.listAttestations}. */
367
+ interface ListAttestationsParams {
368
+ limit?: number;
369
+ offset?: number;
370
+ }
371
+ /** Body returned by GET /attestations. Each row is a receipt as the
372
+ * server sends it, without its inclusion proof. */
373
+ interface AttestationList {
374
+ ok: boolean;
375
+ count: number;
376
+ limit: number;
377
+ offset: number;
378
+ attestations: Record<string, unknown>[];
379
+ }
380
+ /** Body returned by GET /stats. */
381
+ interface RunStats {
382
+ ok: boolean;
383
+ total_runs: number;
384
+ runs_today: number;
385
+ runs_last_24h: number;
386
+ pass_rate: number;
387
+ avg_duration_ms: number;
388
+ last_run_at: string;
389
+ runs_by_program: Record<string, number>;
204
390
  }
205
391
  /** Audit-PDF format selector. */
206
392
  type PDFFormat = "brief" | "auditor" | "legal" | "comprehensive";
@@ -267,6 +453,8 @@ interface AdminAPIKey {
267
453
  revoked: boolean;
268
454
  }
269
455
 
456
+ /** The most rows POST /execute/batch accepts in one request. */
457
+ declare const MAX_BATCH_ROWS = 1000;
270
458
  /**
271
459
  * The Verdifax SDK client.
272
460
  *
@@ -276,17 +464,32 @@ interface AdminAPIKey {
276
464
  * | --- | --- | --- |
277
465
  * | `health()` | GET /health | none |
278
466
  * | `version()` | GET /version | none |
467
+ * | `getOpenAPI()` | GET /openapi.json | none |
468
+ * | `getStats()` | GET /stats | required |
279
469
  * | `execute(req)` | POST /execute | required |
280
470
  * | `attest(req)` | POST /execute (helper) | required |
281
471
  * | `getRun(id)` | GET /runs/{id} | required |
282
472
  * | `verifyRun(id)` | GET /runs/{id}/verify | required |
283
473
  * | `listRuns(params)` | GET /runs | required |
474
+ * | `searchRuns(params)` | GET /runs/search | required |
475
+ * | `exportRuns(params)` | GET /runs/export | required |
476
+ * | `exportRunsCSV(params)` | GET /runs/export?format=csv | required |
477
+ * | `listAttestations(params)` | GET /attestations | required |
478
+ * | `getAttestation(id)` | GET /attestations/{id} | required |
479
+ * | `getRunArtifacts(id)` | GET /runs/{id}/artifacts | required |
480
+ * | `getRunReport(id)` | GET /runs/{id}/report | required |
481
+ * | `getPublicBundle(id)` | GET /runs/{id}/bundle.json | none |
482
+ * | `getPublicBundleByToken(token)` | GET /public/runs/{token}/bundle.json | none |
483
+ * | `executeBatch(runs)` | POST /execute/batch | required |
484
+ * | `verifyDeterminism(req)` | POST /execute/verify-determinism | required |
284
485
  * | `downloadAuditPDF(id, format)` | GET /runs/{id}/report.pdf | required |
285
486
  * | `getAllowToken(id)` | GET /runs/{id}/allow-token | required |
286
487
  * | `getDenyReceipt(id)` | GET /runs/{id}/deny-receipt | required |
287
488
  * | `getCCVHaltReceipt(id)` | GET /runs/{id}/ccv-halt-receipt | required |
288
489
  * | `getMACCHaltReceipt(id)` | GET /runs/{id}/macc-halt-receipt | required |
289
490
  * | `getAivpT4HaltReceipt(id)` | GET /runs/{id}/aivp-t4-halt-receipt | required |
491
+ * | `getAttestationGapReceipt(id)` | GET /runs/{id}/attestation-gap-receipt | required |
492
+ * | `getCESAuditRecord(id)` | GET /runs/{id}/ces-audit-record | required |
290
493
  * | `listDeletionReceipts(id)` | GET /runs/{id}/deletion-receipts | required |
291
494
  * | `adminErase(req)` | POST /admin/erase | required |
292
495
  * | `dcaeVerify(bundle)` | POST /dcae/verify | none |
@@ -299,7 +502,8 @@ interface AdminAPIKey {
299
502
  * | `clearRequestKey()` | DELETE /keys/request-key | required |
300
503
  *
301
504
  * With the `signingKey` option set, every path to POST /execute carries
302
- * a fresh request signature. Without it, requests are unsigned.
505
+ * a fresh request signature, each row of a batch carries its own, and a
506
+ * determinism check carries one. Without it, requests are unsigned.
303
507
  *
304
508
  * Idempotent GETs that hit a transient failure (502/503/504/429)
305
509
  * are retried with exponential backoff + full jitter. Non-
@@ -317,7 +521,24 @@ declare class VerdifaxClient {
317
521
  constructor(config?: ClientConfig);
318
522
  health(): Promise<Health>;
319
523
  version(): Promise<VerdifaxVersion>;
524
+ /** The server's own API description. */
525
+ getOpenAPI(): Promise<Record<string, unknown>>;
526
+ /** Run counts for this API key. */
527
+ getStats(): Promise<RunStats>;
320
528
  execute(req: ExecuteRequest): Promise<ExecuteResponse>;
529
+ /** Runs one payload twice on the server and compares the manifest
530
+ * hashes. One signature covers the request, and the server claims
531
+ * its nonce once. Both runs are recorded. */
532
+ verifyDeterminism(req: ExecuteRequest): Promise<VerifyDeterminismResponse>;
533
+ /** Sends up to {@link MAX_BATCH_ROWS} runs in one request. With a
534
+ * signing key each row carries its own signature and nonce. A row
535
+ * that fails comes back in `results` with `ok: false`, so the call
536
+ * does not throw for it. The rows are not checked here: the server
537
+ * reports a bad row in that row's result.
538
+ *
539
+ * This is one POST and it is never retried. After a timeout the
540
+ * server may have run some or all of the rows. */
541
+ executeBatch(runs: ExecuteRequest[]): Promise<ExecuteBatchResponse>;
321
542
  /** High-level convenience wrapper around `execute()`. Accepts
322
543
  * either a Buffer (for binary payloads, auto-base64) or a
323
544
  * string (for plain text). Validates the hex fields and
@@ -336,11 +557,47 @@ declare class VerdifaxClient {
336
557
  runs: RunSummary[];
337
558
  total: number;
338
559
  }>;
560
+ /** Searches this key's runs. `manifest_hash` matches a prefix. The
561
+ * server ignores a `from` or `to` it cannot parse here, unlike
562
+ * {@link exportRuns}, which refuses one. */
563
+ searchRuns(params?: SearchRunsParams): Promise<{
564
+ runs: RunSummary[];
565
+ total: number;
566
+ }>;
567
+ /** Lists what the server holds for this key in a period, failures
568
+ * included, up to 10,000 rows. `truncated` is true when the period
569
+ * holds more. The list states what was stored, not a verdict, and a
570
+ * call that never reached Verdifax cannot appear in it. */
571
+ exportRuns(params?: ExportRunsParams): Promise<RunsExport>;
572
+ /** The same rows as {@link exportRuns}: the raw CSV text with `total`
573
+ * and `truncated` from the response headers. Check `truncated`: when
574
+ * true, the CSV is missing rows for the period. Throws when the server
575
+ * does not send those headers, so that a cut-off export cannot pass
576
+ * for a complete one. */
577
+ exportRunsCSV(params?: ExportRunsParams): Promise<RunsExportCSV>;
578
+ private exportPath;
579
+ listAttestations(params?: ListAttestationsParams): Promise<AttestationList>;
580
+ getAttestation(attestationId: number): Promise<Record<string, unknown>>;
339
581
  getAllowToken(runId: number): Promise<Record<string, unknown>>;
340
582
  getDenyReceipt(runId: number): Promise<Record<string, unknown>>;
341
583
  getCCVHaltReceipt(runId: number): Promise<Record<string, unknown>>;
342
584
  getMACCHaltReceipt(runId: number): Promise<Record<string, unknown>>;
343
585
  getAivpT4HaltReceipt(runId: number): Promise<Record<string, unknown>>;
586
+ getAttestationGapReceipt(runId: number): Promise<Record<string, unknown>>;
587
+ getCESAuditRecord(runId: number): Promise<Record<string, unknown>>;
588
+ /** The audit report for a run, as JSON. */
589
+ getRunReport(runId: number): Promise<Record<string, unknown>>;
590
+ /** The run's sealed audit bundle as the exact JSON text the server
591
+ * sent, to save and check with `verdifax-verify`. It is not parsed:
592
+ * JSON.parse would round a number above 2^53 and the recomputed hash
593
+ * would stop matching. */
594
+ getRunArtifacts(runId: number): Promise<string>;
595
+ /** The public audit bundle of a record published by run id, as the
596
+ * exact JSON text the server sent. Needs no API key. */
597
+ getPublicBundle(runId: number): Promise<string>;
598
+ /** The public audit bundle a share token points to, as the exact JSON
599
+ * text the server sent. Needs no API key. */
600
+ getPublicBundleByToken(token: string): Promise<string>;
344
601
  private getRunArtifact;
345
602
  /** Streams the audit PDF bytes as a Buffer. Format defaults to
346
603
  * "comprehensive" when not specified. */
@@ -351,27 +608,37 @@ declare class VerdifaxClient {
351
608
  adminCreateKey(name: string): Promise<AdminCreateKeyResponse>;
352
609
  adminListKeys(): Promise<AdminAPIKey[]>;
353
610
  adminRevokeKey(keyId: number): Promise<void>;
354
- /** Convenience for attesting an Anthropic Claude API response.
355
- * Wires the response text into the AIVP governance pipeline
356
- * by setting `ai_output_text`. */
611
+ /** Convenience for attesting an Anthropic Claude API response. With
612
+ * `govern: true` the response text also goes to the AIVP review as
613
+ * `ai_output_text`; that is off by default, so the text leaves your
614
+ * machine for review only when you ask. */
357
615
  attestClaudeResponse(args: {
358
616
  program_id: Hex64;
359
617
  route_id: string;
360
618
  registry_record_hash: Hex64;
361
619
  prompt: string;
362
620
  response: string;
621
+ govern?: boolean;
363
622
  }): Promise<ExecuteResponse>;
364
- /** Convenience for attesting an OpenAI API response. */
623
+ /** Convenience for attesting an OpenAI API response. `govern` works as
624
+ * in {@link attestClaudeResponse}. */
365
625
  attestOpenAIResponse(args: {
366
626
  program_id: Hex64;
367
627
  route_id: string;
368
628
  registry_record_hash: Hex64;
369
629
  prompt: string;
370
630
  response: string;
631
+ govern?: boolean;
371
632
  }): Promise<ExecuteResponse>;
372
633
  private attestProviderResponse;
373
634
  private request;
635
+ /** A GET whose body is kept as sent, retried like any other GET. */
636
+ private requestRaw;
374
637
  private requireAPIKey;
638
+ private requireExecuteFields;
639
+ /** The request with its derived flags and, with a signing key, a fresh
640
+ * signature and nonce, on a copy. */
641
+ private prepared;
375
642
  }
376
643
 
377
644
  /**
@@ -380,7 +647,9 @@ declare class VerdifaxClient {
380
647
  *
381
648
  * Variables consumed (identical names across SDKs):
382
649
  *
383
- * VERDIFAX_BASE_URL base URL (defaults to https://api.verdifax.com)
650
+ * VERDIFAX_BASE_URL base URL, read first
651
+ * VERDIFAX_API_URL base URL, read when VERDIFAX_BASE_URL is unset
652
+ * (defaults to https://api.verdifax.com)
384
653
  * VERDIFAX_API_KEY X-Verdifax-Key value
385
654
  * VERDIFAX_TIMEOUT_MS per-request timeout in ms (defaults to 90000)
386
655
  * VERDIFAX_USER_AGENT override the default User-Agent
@@ -389,6 +658,84 @@ declare class VerdifaxClient {
389
658
 
390
659
  declare function fromEnv(): VerdifaxClient;
391
660
 
661
+ /**
662
+ * Best-effort detection of the running Node environment, for the
663
+ * `reproducibility_context` of a run. A value that cannot be read is
664
+ * left out, and the server records it as not declared.
665
+ */
666
+
667
+ interface CaptureEnvironmentOptions {
668
+ /** Library name to seed value. Recorded as declared; the caller still
669
+ * has to apply the seeds. */
670
+ declaredSeeds?: Record<string, string | number>;
671
+ /** List the packages under `node_modules` in the working directory.
672
+ * Defaults to true. */
673
+ includeDependencies?: boolean;
674
+ /** Read the commit with `git rev-parse HEAD`. Defaults to true. */
675
+ includeGit?: boolean;
676
+ /** Read the container id from `/proc/self/cgroup` on Linux. Defaults
677
+ * to true. */
678
+ includeContainer?: boolean;
679
+ }
680
+ /** Auto-detects the running Node environment. */
681
+ declare function captureEnvironment(options?: CaptureEnvironmentOptions): ReproducibilityContext;
682
+
683
+ /**
684
+ * Request-body rules shared by every path to POST /execute.
685
+ */
686
+
687
+ /**
688
+ * The payload the provider helpers attest: canonical JSON with sorted keys,
689
+ * no extra whitespace and UTF-8 text, exactly
690
+ * `{"prompt":...,"provider":...,"response":...}`. All four SDKs produce the
691
+ * same bytes, and a shared test vector holds them to it.
692
+ *
693
+ * Text with an unpaired surrogate has no UTF-8 form and is refused.
694
+ */
695
+ declare function formatProviderPayload(provider: string, prompt: string, response: string): string;
696
+
697
+ /**
698
+ * The three canonical hash formulas from the Verdifax orchestrator, so a
699
+ * caller can recompute a DSE dispatch hash, a DCAE closure hash or a CRES
700
+ * receipt hash without calling the server.
701
+ *
702
+ * These match the Python SDK's `verdifax.section0` and pass its test
703
+ * vectors. Every hash is SHA-256 as 64 lowercase hex characters, over
704
+ * UTF-8 text.
705
+ */
706
+
707
+ declare const DSE_FORMULA_VERSION = "dse.tcu.dispatch.v1";
708
+ declare const DCAE_PREIMAGE_VERSION = "verdifax.dcae.v1";
709
+ declare const CRES_PREIMAGE_VERSION = "verdifax.cres.v1";
710
+ declare const CRES_ENGINE_VERSION = "verdifax-cres/1.0.0";
711
+ /** The DSE formula joins its fields with a period. */
712
+ declare function dseDispatchHash(fields: {
713
+ envelope_id: string;
714
+ sequence_id: string;
715
+ program_id: Hex64;
716
+ registry_record_hash: Hex64;
717
+ }): Hex64;
718
+ /** The DCAE formula joins its fields with a pipe. */
719
+ declare function dcaeClosureHash(fields: {
720
+ manifest_hash: Hex64;
721
+ aer_hash: Hex64;
722
+ envelope_id: string;
723
+ zksp_binding_hash: Hex64;
724
+ formal_verifier_status: string;
725
+ }): Hex64;
726
+ /** The CRES formula joins its fields with a pipe. `engine_version`
727
+ * defaults to {@link CRES_ENGINE_VERSION}; pass another value only to
728
+ * recompute a receipt from an earlier engine. */
729
+ declare function cresReceiptHash(fields: {
730
+ envelope_id: string;
731
+ field_path: string;
732
+ deletion_clock: string;
733
+ actor_id: string;
734
+ ciphertext_hash_at_shred: Hex64;
735
+ dsar_reference: string;
736
+ engine_version?: string;
737
+ }): Hex64;
738
+
392
739
  /**
393
740
  * Optional customer request signing.
394
741
  *
@@ -498,4 +845,4 @@ declare class APIKeyRequiredError extends VerdifaxError {
498
845
  constructor();
499
846
  }
500
847
 
501
- export { APIError, APIKeyRequiredError, type AdminAPIKey, type AdminCreateKeyResponse, type AdminEraseRequest, type AttestRequest, AuthError, type ClientConfig, type DCAEProofBundle, type DCAEVerdict, type DeletionReceipt, type ExecuteRequest, type ExecuteResponse, type ExecutionManifest, type FormulaEra, type Health, type Hex64, type ListRunsParams, NotFoundError, type PDFFormat, type RequestKeyPair, type RequestKeyRegistration, type RequestKeyRegistrationBody, type RequestSignature, type Run, type RunSummary, VerdifaxClient, VerdifaxError, type VerdifaxVersion, type VerifyResponse, fromEnv, generateRequestKeyPair, requestKeyRegistrationBody, requestSignaturePreimage, signRequest, validateHex64, validateRouteId };
848
+ export { APIError, APIKeyRequiredError, type AdminAPIKey, type AdminCreateKeyResponse, type AdminEraseRequest, type AttestRequest, type AttestationList, AuthError, CRES_ENGINE_VERSION, CRES_PREIMAGE_VERSION, type ClientConfig, type DCAEProofBundle, type DCAEVerdict, DCAE_PREIMAGE_VERSION, DSE_FORMULA_VERSION, type DeletionReceipt, type DeterminismDiff, type DeterminismRun, type ExecuteBatchResponse, type ExecuteBatchResult, type ExecuteRequest, type ExecuteResponse, type ExecutionManifest, type ExportRow, type ExportRunsParams, type FormulaEra, type Health, type Hex64, type ListAttestationsParams, type ListRunsParams, MAX_BATCH_ROWS, NotFoundError, type PDFFormat, RUN_STATUSES, type ReproducibilityContext, type RequestKeyPair, type RequestKeyRegistration, type RequestKeyRegistrationBody, type RequestSignature, type Run, type RunStats, type RunStatus, type RunSummary, type RunsExport, type RunsExportCSV, type SearchRunsParams, VerdifaxClient, VerdifaxError, type VerdifaxVersion, type VerifyDeterminismResponse, type VerifyResponse, captureEnvironment, cresReceiptHash, dcaeClosureHash, dseDispatchHash, formatProviderPayload, fromEnv, generateRequestKeyPair, requestKeyRegistrationBody, requestSignaturePreimage, signRequest, validateHex64, validateRouteId };