verdifax 1.0.0 → 1.2.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/dist/index.js CHANGED
@@ -27,11 +27,13 @@ __export(index_exports, {
27
27
  CRES_PREIMAGE_VERSION: () => CRES_PREIMAGE_VERSION,
28
28
  DCAE_PREIMAGE_VERSION: () => DCAE_PREIMAGE_VERSION,
29
29
  DSE_FORMULA_VERSION: () => DSE_FORMULA_VERSION,
30
+ EXECUTE_FIELDS: () => EXECUTE_FIELDS,
30
31
  MAX_BATCH_ROWS: () => MAX_BATCH_ROWS,
31
32
  NotFoundError: () => NotFoundError,
32
33
  RUN_STATUSES: () => RUN_STATUSES,
33
34
  VerdifaxClient: () => VerdifaxClient,
34
35
  VerdifaxError: () => VerdifaxError,
36
+ VerdifaxJob: () => VerdifaxJob,
35
37
  captureEnvironment: () => captureEnvironment,
36
38
  cresReceiptHash: () => cresReceiptHash,
37
39
  dcaeClosureHash: () => dcaeClosureHash,
@@ -39,10 +41,17 @@ __export(index_exports, {
39
41
  formatProviderPayload: () => formatProviderPayload,
40
42
  fromEnv: () => fromEnv,
41
43
  generateRequestKeyPair: () => generateRequestKeyPair,
44
+ policyActivationApproval: () => policyActivationApproval,
45
+ policyActivationPreimage: () => policyActivationPreimage,
46
+ requestKeyChangeApproval: () => requestKeyChangeApproval,
47
+ requestKeyChangePreimage: () => requestKeyChangePreimage,
42
48
  requestKeyRegistrationBody: () => requestKeyRegistrationBody,
43
49
  requestSignaturePreimage: () => requestSignaturePreimage,
50
+ requestSignaturePreimageV2: () => requestSignaturePreimageV2,
44
51
  signRequest: () => signRequest,
52
+ signRequestV2: () => signRequestV2,
45
53
  validateHex64: () => validateHex64,
54
+ validateJobName: () => validateJobName,
46
55
  validateRouteId: () => validateRouteId
47
56
  });
48
57
  module.exports = __toCommonJS(index_exports);
@@ -72,15 +81,23 @@ var NotFoundError = class extends VerdifaxError {
72
81
  name = "VerdifaxNotFoundError";
73
82
  };
74
83
  var APIError = class extends VerdifaxError {
75
- constructor(status, path, message) {
84
+ constructor(status, path, message, recordHash, signedRequest) {
76
85
  super(`verdifax: API error at ${path} (HTTP ${status}): ${message}`);
77
86
  this.status = status;
78
87
  this.path = path;
79
88
  this.message = message;
89
+ this.recordHash = recordHash;
90
+ if (signedRequest !== void 0) {
91
+ Object.defineProperty(this, "signedRequest", {
92
+ value: signedRequest,
93
+ enumerable: false
94
+ });
95
+ }
80
96
  }
81
97
  status;
82
98
  path;
83
99
  message;
100
+ recordHash;
84
101
  name = "VerdifaxAPIError";
85
102
  };
86
103
  var APIKeyRequiredError = class extends VerdifaxError {
@@ -92,8 +109,286 @@ var APIKeyRequiredError = class extends VerdifaxError {
92
109
 
93
110
  // src/signing.ts
94
111
  var import_node_crypto = require("crypto");
112
+
113
+ // src/validation.ts
114
+ function validateHex64(value, fieldName) {
115
+ if (typeof value !== "string" || value.length !== 64) {
116
+ throw new VerdifaxError(
117
+ `verdifax: ${fieldName} must be 64 hex characters (got ${typeof value === "string" ? value.length : typeof value})`
118
+ );
119
+ }
120
+ if (!/^[0-9a-f]{64}$/.test(value)) {
121
+ throw new VerdifaxError(
122
+ `verdifax: ${fieldName} must contain only lowercase hex (0-9, a-f)`
123
+ );
124
+ }
125
+ }
126
+ function validateRouteId(value) {
127
+ if (!value || typeof value !== "string") {
128
+ throw new VerdifaxError("verdifax: route_id is required");
129
+ }
130
+ if (value.length > 256) {
131
+ throw new VerdifaxError(
132
+ `verdifax: route_id is too long (${value.length} > 256)`
133
+ );
134
+ }
135
+ if (!/^[\x20-\x7E]+$/.test(value)) {
136
+ throw new VerdifaxError(
137
+ "verdifax: route_id contains non-printable-ASCII character"
138
+ );
139
+ }
140
+ }
141
+ function validateJobName(value, fieldName) {
142
+ if (typeof value !== "string" || !/^[A-Za-z0-9._:-]{1,128}$/.test(value)) {
143
+ throw new VerdifaxError(
144
+ `verdifax: ${fieldName} must be 1 to 128 letters, digits, dots, underscores, colons or dashes`
145
+ );
146
+ }
147
+ }
148
+
149
+ // src/helpers.ts
150
+ function formatProviderPayload(provider, prompt, response) {
151
+ if ([provider, prompt, response].some((text) => /[\uD800-\uDFFF]/u.test(text))) {
152
+ throw new VerdifaxError(
153
+ "verdifax: provider payload text cannot be encoded as UTF-8"
154
+ );
155
+ }
156
+ return JSON.stringify({ prompt, provider, response });
157
+ }
158
+ function isProvided(value) {
159
+ return value !== null && value !== void 0 && value !== "" && value !== false;
160
+ }
161
+ function withAttestedFlag(context) {
162
+ const provided = Object.entries(context).some(
163
+ ([name, value]) => name !== "attested" && isProvided(value)
164
+ );
165
+ return { ...context, attested: provided };
166
+ }
167
+ function withDeclaredFlag(context) {
168
+ const declared = Object.entries(context).some(
169
+ ([name, value]) => name !== "declared" && isProvided(value) && !(Array.isArray(value) && value.length === 0)
170
+ );
171
+ return { ...context, declared };
172
+ }
173
+ function refuseCallerOriginHashes(substance) {
174
+ const origin = substance?.origin;
175
+ if (origin?.source_ip_hash || origin?.user_agent_hash) {
176
+ throw new VerdifaxError(
177
+ "verdifax: request_substance.origin.source_ip_hash and user_agent_hash are computed by the server and cannot be supplied"
178
+ );
179
+ }
180
+ }
181
+ var JOB_FIELDS = {
182
+ job_id: true,
183
+ step_id: true,
184
+ previous_record_hashes: true,
185
+ external_previous: true,
186
+ final: true
187
+ };
188
+ function refuseUnknownFields(value, known, label) {
189
+ for (const name of Object.keys(value)) {
190
+ if (!Object.hasOwn(known, name)) {
191
+ throw new VerdifaxError(`verdifax: ${label} has an unknown field: ${name}`);
192
+ }
193
+ }
194
+ }
195
+ function sortedUnique(hashes, fieldName) {
196
+ if (hashes === void 0) return [];
197
+ if (!Array.isArray(hashes) || hashes.some((hash) => typeof hash !== "string")) {
198
+ throw new VerdifaxError(`verdifax: ${fieldName} must be a list of strings`);
199
+ }
200
+ return [...new Set(hashes)].sort();
201
+ }
202
+ function normalizedJob(job) {
203
+ if (typeof job !== "object" || job === null || Array.isArray(job)) {
204
+ throw new VerdifaxError("verdifax: job must be an object");
205
+ }
206
+ refuseUnknownFields(job, JOB_FIELDS, "job");
207
+ validateJobName(job.job_id, "job_id");
208
+ validateJobName(job.step_id, "step_id");
209
+ if (job.final !== void 0 && typeof job.final !== "boolean") {
210
+ throw new VerdifaxError("verdifax: job.final must be true or false");
211
+ }
212
+ const out = { job_id: job.job_id, step_id: job.step_id };
213
+ const previous = sortedUnique(job.previous_record_hashes, "previous_record_hashes");
214
+ if (previous.length > 0) out.previous_record_hashes = previous;
215
+ const external = sortedUnique(job.external_previous, "external_previous");
216
+ if (external.length > 0) out.external_previous = external;
217
+ if (job.final) out.final = true;
218
+ return out;
219
+ }
220
+ var POLICY_ACTOR_TYPES = ["agent", "user", "service", "system"];
221
+ var POLICY_OBJECT_TYPES = ["text", "transaction", "code", "data", "model", "file"];
222
+ var POLICY_CLASSIFICATIONS = [
223
+ "PUBLIC",
224
+ "INTERNAL",
225
+ "CONFIDENTIAL",
226
+ "RESTRICTED",
227
+ "TOP_SECRET",
228
+ "TS_SCI"
229
+ ];
230
+ var MAX_POLICY_OBJECT_ID_BYTES = 256;
231
+ var POLICY_CONTEXT_FIELDS = {
232
+ actor_type: true,
233
+ mfa_satisfied: true,
234
+ session_age_seconds: true,
235
+ object_type: true,
236
+ object_id: true,
237
+ classification: true
238
+ };
239
+ function refuseOutsideList(value, allowed, fieldName) {
240
+ if (typeof value !== "string" || !allowed.includes(value)) {
241
+ throw new VerdifaxError(
242
+ `verdifax: policy_context.${fieldName} must be one of ${allowed.join(", ")}`
243
+ );
244
+ }
245
+ }
246
+ function checkedPolicyContext(context) {
247
+ if (typeof context !== "object" || context === null || Array.isArray(context)) {
248
+ throw new VerdifaxError("verdifax: policy_context must be an object");
249
+ }
250
+ refuseUnknownFields(context, POLICY_CONTEXT_FIELDS, "policy_context");
251
+ const out = {};
252
+ const {
253
+ actor_type,
254
+ mfa_satisfied,
255
+ session_age_seconds,
256
+ object_type,
257
+ object_id,
258
+ classification
259
+ } = context;
260
+ if (actor_type !== void 0) {
261
+ refuseOutsideList(actor_type, POLICY_ACTOR_TYPES, "actor_type");
262
+ out.actor_type = actor_type;
263
+ }
264
+ if (mfa_satisfied !== void 0) {
265
+ if (typeof mfa_satisfied !== "boolean") {
266
+ throw new VerdifaxError(
267
+ "verdifax: policy_context.mfa_satisfied must be true or false"
268
+ );
269
+ }
270
+ out.mfa_satisfied = mfa_satisfied;
271
+ }
272
+ if (session_age_seconds !== void 0) {
273
+ if (!Number.isSafeInteger(session_age_seconds) || session_age_seconds < 0) {
274
+ throw new VerdifaxError(
275
+ "verdifax: policy_context.session_age_seconds must be a whole number of seconds, not negative"
276
+ );
277
+ }
278
+ out.session_age_seconds = session_age_seconds;
279
+ }
280
+ if (object_type !== void 0) {
281
+ refuseOutsideList(object_type, POLICY_OBJECT_TYPES, "object_type");
282
+ out.object_type = object_type;
283
+ }
284
+ if (object_id !== void 0) {
285
+ if (typeof object_id !== "string") {
286
+ throw new VerdifaxError("verdifax: policy_context.object_id must be a string");
287
+ }
288
+ if (Buffer.byteLength(object_id, "utf8") > MAX_POLICY_OBJECT_ID_BYTES) {
289
+ throw new VerdifaxError(
290
+ `verdifax: policy_context.object_id is longer than ${MAX_POLICY_OBJECT_ID_BYTES} bytes`
291
+ );
292
+ }
293
+ out.object_id = object_id;
294
+ }
295
+ if (classification !== void 0) {
296
+ refuseOutsideList(classification, POLICY_CLASSIFICATIONS, "classification");
297
+ out.classification = classification;
298
+ }
299
+ return out;
300
+ }
301
+ function refuseActorFactsWithoutActor(context, attested) {
302
+ const declaresActor = context.actor_type !== void 0 || context.mfa_satisfied === true || (context.session_age_seconds ?? 0) !== 0;
303
+ if (declaresActor && attested?.attested !== true) {
304
+ throw new VerdifaxError(
305
+ "verdifax: policy_context.actor_type, mfa_satisfied and session_age_seconds describe the attested actor; send attested_context with the actor, for example its actor_id"
306
+ );
307
+ }
308
+ }
309
+ var EXECUTE_FIELD_SET = {
310
+ payload: true,
311
+ payload_text: true,
312
+ program_id: true,
313
+ route_id: true,
314
+ registry_record_hash: true,
315
+ ai_output_text: true,
316
+ attested_context: true,
317
+ reproducibility_context: true,
318
+ request_substance: true,
319
+ authorization_chain: true,
320
+ regulatory_scaffolding: true,
321
+ causal_graph: true,
322
+ request_signature: true,
323
+ signed_request: true,
324
+ job: true,
325
+ policy_context: true,
326
+ expected_policy_hash: true
327
+ };
328
+ var EXECUTE_FIELDS = Object.freeze(
329
+ Object.keys(EXECUTE_FIELD_SET)
330
+ );
331
+ var ATTESTED_CONTEXT_FIELDS = {
332
+ attested: true,
333
+ actor_id: true,
334
+ actor_role: true,
335
+ authorization_policy: true,
336
+ actor_signature: true,
337
+ model_provider: true,
338
+ model_name: true,
339
+ model_version: true,
340
+ model_temperature: true,
341
+ prompt_hash: true,
342
+ decision_kind: true,
343
+ decision_result: true,
344
+ decision_note: true
345
+ };
346
+ function refuseUnknownRequestFields(req, label = "request") {
347
+ if (typeof req !== "object" || req === null || Array.isArray(req)) {
348
+ throw new VerdifaxError(`verdifax: ${label} must be an object`);
349
+ }
350
+ refuseUnknownFields(req, EXECUTE_FIELD_SET, label);
351
+ const context = req.attested_context;
352
+ if (typeof context === "object" && context !== null) {
353
+ refuseUnknownFields(context, ATTESTED_CONTEXT_FIELDS, "attested_context");
354
+ }
355
+ }
356
+ function withExecuteFlags(req) {
357
+ refuseUnknownRequestFields(req);
358
+ const body = { ...req };
359
+ if (req.job === void 0 || req.job === null) {
360
+ delete body.job;
361
+ } else {
362
+ body.job = normalizedJob(req.job);
363
+ }
364
+ if (req.attested_context) {
365
+ body.attested_context = withAttestedFlag(req.attested_context);
366
+ }
367
+ if (req.reproducibility_context) {
368
+ body.reproducibility_context = withDeclaredFlag(req.reproducibility_context);
369
+ }
370
+ if (req.policy_context === void 0 || req.policy_context === null) {
371
+ delete body.policy_context;
372
+ } else {
373
+ body.policy_context = checkedPolicyContext(req.policy_context);
374
+ refuseActorFactsWithoutActor(body.policy_context, body.attested_context);
375
+ }
376
+ if (req.expected_policy_hash === void 0 || req.expected_policy_hash === null) {
377
+ delete body.expected_policy_hash;
378
+ } else {
379
+ validateHex64(req.expected_policy_hash, "expected_policy_hash");
380
+ }
381
+ return body;
382
+ }
383
+
384
+ // src/signing.ts
95
385
  var REQUEST_SIGNATURE_FORM = "verdifax.request.v1";
386
+ var REQUEST_SIGNATURE_FORM_V2 = "verdifax.request.v2";
387
+ var REQUEST_SIGNATURE_VERSION_2 = "2";
388
+ var JOB_FORM = "verdifax.job.v1";
96
389
  var REQUEST_KEY_PROOF_FORM = "verdifax.request-key.v1";
390
+ var REQUEST_KEY_CHANGE_FORM = "verdifax.request-key-change.v1";
391
+ var POLICY_ACTIVATION_FORM = "verdifax.policy-activation.v1";
97
392
  var SIGNING_KEY_BYTES = 32;
98
393
  var PKCS8_ED25519_HEADER = Buffer.from(
99
394
  "302e020100300506032b657004220420",
@@ -124,6 +419,12 @@ function loadSigningKey(key) {
124
419
  type: "pkcs8"
125
420
  });
126
421
  }
422
+ function sha256Hex(text) {
423
+ return (0, import_node_crypto.createHash)("sha256").update(Buffer.from(text, "utf8")).digest("hex");
424
+ }
425
+ function signedAtNow() {
426
+ return (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d+Z$/, "Z");
427
+ }
127
428
  function requestSignaturePreimage(fields) {
128
429
  return Buffer.from(
129
430
  [
@@ -138,13 +439,62 @@ function requestSignaturePreimage(fields) {
138
439
  "utf8"
139
440
  );
140
441
  }
442
+ function requestSignaturePreimageV2(fields) {
443
+ const { job } = fields;
444
+ return Buffer.from(
445
+ [
446
+ REQUEST_SIGNATURE_FORM_V2,
447
+ fields.body_hash,
448
+ fields.payload_hash,
449
+ fields.program_id,
450
+ fields.route_id,
451
+ fields.registry_record_hash,
452
+ fields.ai_output_hash,
453
+ JOB_FORM,
454
+ job?.job_id ?? "",
455
+ job?.step_id ?? "",
456
+ (job?.previous_record_hashes ?? []).join(","),
457
+ (job?.external_previous ?? []).join(","),
458
+ job?.final ? "true" : "false",
459
+ fields.signed_at,
460
+ fields.nonce
461
+ ].join("\0"),
462
+ "utf8"
463
+ );
464
+ }
465
+ function signRequestV2(signingKey, req, options = {}) {
466
+ const key = loadSigningKey(signingKey);
467
+ const { request_signature: _unsigned, ...fields } = withExecuteFlags(req);
468
+ const signed_request = JSON.stringify(fields);
469
+ const signed_at = options.signedAt ?? signedAtNow();
470
+ const nonce = options.nonce ?? (0, import_node_crypto.randomBytes)(16).toString("hex");
471
+ const preimage = requestSignaturePreimageV2({
472
+ body_hash: sha256Hex(signed_request),
473
+ payload_hash: sha256Hex(fields.payload_text || fields.payload || ""),
474
+ program_id: fields.program_id,
475
+ route_id: fields.route_id,
476
+ registry_record_hash: fields.registry_record_hash,
477
+ ai_output_hash: fields.ai_output_text ? sha256Hex(fields.ai_output_text) : "",
478
+ job: fields.job,
479
+ signed_at,
480
+ nonce
481
+ });
482
+ return {
483
+ signed_request,
484
+ request_signature: {
485
+ version: REQUEST_SIGNATURE_VERSION_2,
486
+ signature: (0, import_node_crypto.sign)(null, preimage, key).toString("base64"),
487
+ signed_at,
488
+ nonce
489
+ }
490
+ };
491
+ }
141
492
  function signRequest(signingKey, req, options = {}) {
142
493
  const key = loadSigningKey(signingKey);
143
- const signed_at = options.signedAt ?? (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d+Z$/, "Z");
494
+ const signed_at = options.signedAt ?? signedAtNow();
144
495
  const nonce = options.nonce ?? (0, import_node_crypto.randomBytes)(16).toString("hex");
145
- const payload_hash = (0, import_node_crypto.createHash)("sha256").update(Buffer.from(req.payload_text || req.payload || "", "utf8")).digest("hex");
146
496
  const preimage = requestSignaturePreimage({
147
- payload_hash,
497
+ payload_hash: sha256Hex(req.payload_text || req.payload || ""),
148
498
  program_id: req.program_id,
149
499
  route_id: req.route_id,
150
500
  registry_record_hash: req.registry_record_hash,
@@ -167,81 +517,164 @@ function requestKeyRegistrationBody(signingKey) {
167
517
  ).toString("base64");
168
518
  return { public_key, proof };
169
519
  }
170
-
171
- // src/helpers.ts
172
- function formatProviderPayload(provider, prompt, response) {
173
- if ([provider, prompt, response].some((text) => /[\uD800-\uDFFF]/u.test(text))) {
174
- throw new VerdifaxError(
175
- "verdifax: provider payload text cannot be encoded as UTF-8"
176
- );
177
- }
178
- return JSON.stringify({ prompt, provider, response });
179
- }
180
- function isProvided(value) {
181
- return value !== null && value !== void 0 && value !== "" && value !== false;
182
- }
183
- function withAttestedFlag(context) {
184
- const provided = Object.entries(context).some(
185
- ([name, value]) => name !== "attested" && isProvided(value)
520
+ function requestKeyChangePreimage(fields) {
521
+ return Buffer.from(
522
+ [
523
+ REQUEST_KEY_CHANGE_FORM,
524
+ fields.new_public_key,
525
+ fields.signed_at,
526
+ fields.nonce
527
+ ].join("\0"),
528
+ "utf8"
186
529
  );
187
- return { ...context, attested: provided };
188
530
  }
189
- function withDeclaredFlag(context) {
190
- const declared = Object.entries(context).some(
191
- ([name, value]) => name !== "declared" && isProvided(value) && !(Array.isArray(value) && value.length === 0)
192
- );
193
- return { ...context, declared };
531
+ function requestKeyChangeApproval(currentSigningKey, newPublicKey, options = {}) {
532
+ const key = loadSigningKey(currentSigningKey);
533
+ const signed_at = options.signedAt ?? signedAtNow();
534
+ const nonce = options.nonce ?? (0, import_node_crypto.randomBytes)(16).toString("hex");
535
+ const preimage = requestKeyChangePreimage({
536
+ new_public_key: newPublicKey,
537
+ signed_at,
538
+ nonce
539
+ });
540
+ return {
541
+ signature: (0, import_node_crypto.sign)(null, preimage, key).toString("base64"),
542
+ signed_at,
543
+ nonce
544
+ };
194
545
  }
195
- function refuseCallerOriginHashes(substance) {
196
- const origin = substance?.origin;
197
- if (origin?.source_ip_hash || origin?.user_agent_hash) {
198
- throw new VerdifaxError(
199
- "verdifax: request_substance.origin.source_ip_hash and user_agent_hash are computed by the server and cannot be supplied"
200
- );
201
- }
546
+ function policyActivationPreimage(fields) {
547
+ return Buffer.from(
548
+ [
549
+ POLICY_ACTIVATION_FORM,
550
+ fields.chain_id,
551
+ fields.document_hash,
552
+ fields.previous_activation_hash,
553
+ fields.signed_at,
554
+ fields.nonce
555
+ ].join("\0"),
556
+ "utf8"
557
+ );
202
558
  }
203
- function withExecuteFlags(req) {
204
- const body = { ...req };
205
- if (req.attested_context) {
206
- body.attested_context = withAttestedFlag(req.attested_context);
207
- }
208
- if (req.reproducibility_context) {
209
- body.reproducibility_context = withDeclaredFlag(req.reproducibility_context);
210
- }
211
- return body;
559
+ function policyActivationApproval(signingKey, fields, options = {}) {
560
+ const key = loadSigningKey(signingKey);
561
+ const signed_at = options.signedAt ?? signedAtNow();
562
+ const nonce = options.nonce ?? (0, import_node_crypto.randomBytes)(16).toString("hex");
563
+ const preimage = policyActivationPreimage({
564
+ chain_id: fields.chain_id,
565
+ document_hash: fields.document_hash,
566
+ previous_activation_hash: fields.previous_activation_hash,
567
+ signed_at,
568
+ nonce
569
+ });
570
+ return {
571
+ signature: (0, import_node_crypto.sign)(null, preimage, key).toString("base64"),
572
+ signed_at,
573
+ nonce
574
+ };
212
575
  }
213
576
 
214
- // src/validation.ts
215
- function validateHex64(value, fieldName) {
216
- if (typeof value !== "string" || value.length !== 64) {
217
- throw new VerdifaxError(
218
- `verdifax: ${fieldName} must be 64 hex characters (got ${typeof value === "string" ? value.length : typeof value})`
219
- );
220
- }
221
- if (!/^[0-9a-f]{64}$/.test(value)) {
222
- throw new VerdifaxError(
223
- `verdifax: ${fieldName} must contain only lowercase hex (0-9, a-f)`
224
- );
225
- }
226
- }
227
- function validateRouteId(value) {
228
- if (!value || typeof value !== "string") {
229
- throw new VerdifaxError("verdifax: route_id is required");
577
+ // src/job.ts
578
+ var STEP_OPTIONS = {
579
+ payload: true,
580
+ payload_text: true,
581
+ program_id: true,
582
+ route_id: true,
583
+ registry_record_hash: true,
584
+ ai_output_text: true,
585
+ attested_context: true,
586
+ reproducibility_context: true,
587
+ request_substance: true,
588
+ authorization_chain: true,
589
+ regulatory_scaffolding: true,
590
+ causal_graph: true,
591
+ policy_context: true,
592
+ expected_policy_hash: true,
593
+ after: true,
594
+ external_previous: true,
595
+ final: true
596
+ };
597
+ var VerdifaxJob = class {
598
+ jobId;
599
+ client;
600
+ hashes = /* @__PURE__ */ new Map();
601
+ #signedRequests = /* @__PURE__ */ new Map();
602
+ lastStepId;
603
+ constructor(client, jobId) {
604
+ validateJobName(jobId, "job_id");
605
+ this.client = client;
606
+ this.jobId = jobId;
607
+ }
608
+ /** Step id to record hash for every step that left a record, on a copy. */
609
+ get recordHashes() {
610
+ return Object.fromEntries(this.hashes);
611
+ }
612
+ /** Step id to the exact text that was signed, for every signed step that
613
+ * left a record, refused and halted steps included, on a copy. Each text
614
+ * can be passed to `verdifax-verify --request FILE`. */
615
+ get signedRequests() {
616
+ return Object.fromEntries(this.#signedRequests);
617
+ }
618
+ /** Runs one step and records its hash and signed text. A refused or halted
619
+ * step records both from the error, then throws the same error `attest`
620
+ * throws. */
621
+ async step(stepId, options) {
622
+ validateJobName(stepId, "step_id");
623
+ refuseUnknownFields(options, STEP_OPTIONS, "step options");
624
+ const { after, external_previous, final, ...attest } = options;
625
+ const job = {
626
+ job_id: this.jobId,
627
+ step_id: stepId,
628
+ previous_record_hashes: this.previousHashes(after),
629
+ external_previous,
630
+ final
631
+ };
632
+ let result;
633
+ try {
634
+ result = await this.client.attest({ ...attest, job });
635
+ } catch (err) {
636
+ if (err instanceof APIError && err.recordHash) {
637
+ this.record(stepId, err.recordHash, err.signedRequest);
638
+ }
639
+ throw err;
640
+ }
641
+ const hash = result?.record_hash || result?.manifest_hash || result?.manifest?.ManifestHash;
642
+ if (!hash) {
643
+ throw new VerdifaxError(
644
+ `verdifax: the server returned no record_hash or manifest_hash for step ${stepId}, so the job map cannot continue from it`
645
+ );
646
+ }
647
+ this.record(stepId, hash, result.signed_request);
648
+ return result;
230
649
  }
231
- if (value.length > 256) {
232
- throw new VerdifaxError(
233
- `verdifax: route_id is too long (${value.length} > 256)`
234
- );
650
+ previousHashes(after) {
651
+ if (after === void 0 || after === null) {
652
+ return this.lastStepId === void 0 ? [] : [this.hashes.get(this.lastStepId)];
653
+ }
654
+ if (!Array.isArray(after)) {
655
+ throw new VerdifaxError("verdifax: after must be a list of step ids");
656
+ }
657
+ return after.map((stepId) => {
658
+ const hash = this.hashes.get(stepId);
659
+ if (hash === void 0) {
660
+ throw new VerdifaxError(
661
+ `verdifax: after names ${String(stepId)}, which is not a step in job ${this.jobId}`
662
+ );
663
+ }
664
+ return hash;
665
+ });
235
666
  }
236
- if (!/^[\x20-\x7E]+$/.test(value)) {
237
- throw new VerdifaxError(
238
- "verdifax: route_id contains non-printable-ASCII character"
239
- );
667
+ record(stepId, hash, signedRequest) {
668
+ this.hashes.set(stepId, hash);
669
+ if (signedRequest !== void 0) {
670
+ this.#signedRequests.set(stepId, signedRequest);
671
+ }
672
+ this.lastStepId = stepId;
240
673
  }
241
- }
674
+ };
242
675
 
243
676
  // src/version.ts
244
- var SDK_VERSION = "1.0.0";
677
+ var SDK_VERSION = "1.2.0";
245
678
 
246
679
  // src/client.ts
247
680
  var DEFAULT_BASE_URL = "https://api.verdifax.com";
@@ -251,10 +684,42 @@ var DEFAULT_RETRY_BASE_DELAY_MS = 200;
251
684
  var SDK_USER_AGENT = `verdifax-sdk-node/${SDK_VERSION}`;
252
685
  var HEADER_API_KEY = "X-Verdifax-Key";
253
686
  var REQUEST_KEY_PATH = "/keys/request-key";
687
+ var POLICIES_PATH = "/policies";
254
688
  var HEADER_EXPORT_TOTAL = "X-Verdifax-Total";
255
689
  var HEADER_EXPORT_TRUNCATED = "X-Verdifax-Truncated";
256
690
  var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([429, 502, 503, 504]);
257
691
  var MAX_BATCH_ROWS = 1e3;
692
+ var ATTEST_FIELDS = {
693
+ payload: true,
694
+ payload_text: true,
695
+ program_id: true,
696
+ route_id: true,
697
+ registry_record_hash: true,
698
+ ai_output_text: true,
699
+ attested_context: true,
700
+ reproducibility_context: true,
701
+ request_substance: true,
702
+ authorization_chain: true,
703
+ regulatory_scaffolding: true,
704
+ causal_graph: true,
705
+ job: true,
706
+ policy_context: true,
707
+ expected_policy_hash: true
708
+ };
709
+ var PROVIDER_ARGS = Object.fromEntries(
710
+ [
711
+ "program_id",
712
+ "route_id",
713
+ "registry_record_hash",
714
+ "prompt",
715
+ "response",
716
+ "govern",
717
+ "job",
718
+ "policy_context",
719
+ "expected_policy_hash",
720
+ ...EXECUTE_FIELDS
721
+ ].map((name) => [name, true])
722
+ );
258
723
  var VerdifaxClient = class {
259
724
  baseURL;
260
725
  apiKey;
@@ -290,25 +755,39 @@ var VerdifaxClient = class {
290
755
  }
291
756
  // ── Execute / Attest (auth) ───────────────────────────────────
292
757
  async execute(req) {
758
+ refuseUnknownRequestFields(req);
293
759
  this.requireExecuteFields(req);
294
- return this.request("POST", "/execute", this.prepared(req));
760
+ const sent = this.prepared(req);
761
+ const out = await this.request("POST", "/execute", sent);
762
+ return withSignedText(out, sent);
295
763
  }
296
764
  /** Runs one payload twice on the server and compares the manifest
297
765
  * hashes. One signature covers the request, and the server claims
298
- * its nonce once. Both runs are recorded. */
766
+ * its nonce once. Both runs are recorded. A run that happens twice
767
+ * cannot be one job step, so a `job` is refused here. */
299
768
  async verifyDeterminism(req) {
769
+ refuseUnknownRequestFields(req);
300
770
  this.requireExecuteFields(req);
301
- return this.request(
771
+ if (req.job !== void 0 && req.job !== null) {
772
+ throw new VerdifaxError(
773
+ "verdifax: a determinism check runs twice, so it cannot be a job step"
774
+ );
775
+ }
776
+ const sent = this.prepared(req);
777
+ const out = await this.request(
302
778
  "POST",
303
779
  "/execute/verify-determinism",
304
- this.prepared(req)
780
+ sent
305
781
  );
782
+ return withSignedText(out, sent);
306
783
  }
307
784
  /** Sends up to {@link MAX_BATCH_ROWS} runs in one request. With a
308
785
  * signing key each row carries its own signature and nonce. A row
309
786
  * that fails comes back in `results` with `ok: false`, so the call
310
- * does not throw for it. The rows are not checked here: the server
311
- * reports a bad row in that row's result.
787
+ * does not throw for it. The rows are not checked here, except a job
788
+ * block, a `policy_context` and an `expected_policy_hash`, which are
789
+ * refused before anything is sent: the server reports any other bad row
790
+ * in that row's result.
312
791
  *
313
792
  * This is one POST and it is never retried. After a timeout the
314
793
  * server may have run some or all of the rows. */
@@ -322,9 +801,20 @@ var VerdifaxClient = class {
322
801
  `verdifax: executeBatch accepts at most ${MAX_BATCH_ROWS} runs (got ${runs.length})`
323
802
  );
324
803
  }
325
- return this.request("POST", "/execute/batch", {
326
- runs: runs.map((run) => this.prepared(run))
327
- });
804
+ runs.forEach((run, i) => refuseUnknownRequestFields(run, `runs[${i}]`));
805
+ const sent = runs.map((run) => this.prepared(run));
806
+ const out = await this.request(
807
+ "POST",
808
+ "/execute/batch",
809
+ { runs: sent }
810
+ );
811
+ if (!Array.isArray(out?.results)) return out;
812
+ return {
813
+ ...out,
814
+ results: out.results.map(
815
+ (row, i) => i < sent.length ? withSignedText(row, sent[i]) : row
816
+ )
817
+ };
328
818
  }
329
819
  /** High-level convenience wrapper around `execute()`. Accepts
330
820
  * either a Buffer (for binary payloads, auto-base64) or a
@@ -332,6 +822,8 @@ var VerdifaxClient = class {
332
822
  * routes the call through to the canonical /execute. */
333
823
  async attest(req) {
334
824
  this.requireAPIKey();
825
+ refuseUnknownRequestFields(req, "attest request");
826
+ refuseUnknownFields(req, ATTEST_FIELDS, "attest request");
335
827
  if (req.payload !== void 0 && req.payload_text !== void 0) {
336
828
  throw new VerdifaxError(
337
829
  "verdifax: attest accepts payload OR payload_text, not both"
@@ -355,7 +847,10 @@ var VerdifaxClient = class {
355
847
  request_substance: req.request_substance,
356
848
  authorization_chain: req.authorization_chain,
357
849
  regulatory_scaffolding: req.regulatory_scaffolding,
358
- causal_graph: req.causal_graph
850
+ causal_graph: req.causal_graph,
851
+ job: req.job,
852
+ policy_context: req.policy_context,
853
+ expected_policy_hash: req.expected_policy_hash
359
854
  };
360
855
  if (req.payload !== void 0) {
361
856
  body.payload = Buffer.isBuffer(req.payload) ? req.payload.toString("base64") : Buffer.from(req.payload).toString("base64");
@@ -364,6 +859,12 @@ var VerdifaxClient = class {
364
859
  }
365
860
  return this.execute(body);
366
861
  }
862
+ /** A helper that runs the steps of one job through {@link attest} and
863
+ * keeps each step's record hash, so a later step can name it. It makes
864
+ * no request until a step runs. */
865
+ job(jobId) {
866
+ return new VerdifaxJob(this, jobId);
867
+ }
367
868
  // ── Request signing (auth) ───────────────────────────────────
368
869
  /** Registers this client's public key on its API key, with the proof
369
870
  * that the client holds the private key. From then on the server
@@ -381,11 +882,162 @@ var VerdifaxClient = class {
381
882
  requestKeyRegistrationBody(this.signingKey)
382
883
  );
383
884
  }
885
+ /** Replaces the registered key with `newSigningKey`. The new key proves
886
+ * itself and this client's current key approves the change. After
887
+ * success this client signs with the new key. If the call fails it
888
+ * keeps the current key, including after a timeout, when the server may
889
+ * have made the change. */
890
+ async rotateRequestKey(newSigningKey) {
891
+ this.requireAPIKey();
892
+ if (!this.signingKey) {
893
+ throw new VerdifaxError(
894
+ "verdifax: rotateRequestKey needs the current key in the signingKey client option"
895
+ );
896
+ }
897
+ const next = loadSigningKey(newSigningKey);
898
+ const registration = requestKeyRegistrationBody(next);
899
+ const out = await this.request(
900
+ "POST",
901
+ REQUEST_KEY_PATH,
902
+ {
903
+ ...registration,
904
+ change: requestKeyChangeApproval(
905
+ this.signingKey,
906
+ registration.public_key
907
+ )
908
+ }
909
+ );
910
+ this.signingKey = next;
911
+ return out;
912
+ }
384
913
  /** Clears the registered public key, so the server stops requiring
385
- * request signatures on this API key. */
914
+ * request signatures on this API key. With a signing key the client
915
+ * sends that key's approval, which the server requires while a key is
916
+ * registered. After success the client drops its signing key and sends
917
+ * unsigned requests, because the server refuses a signed run on an API
918
+ * key with no registered key. If the call fails it keeps the key. */
386
919
  async clearRequestKey() {
387
920
  this.requireAPIKey();
388
- await this.request("DELETE", REQUEST_KEY_PATH);
921
+ await this.request(
922
+ "DELETE",
923
+ REQUEST_KEY_PATH,
924
+ this.signingKey ? { change: requestKeyChangeApproval(this.signingKey, "") } : void 0
925
+ );
926
+ this.signingKey = void 0;
927
+ }
928
+ // ── Policies (auth) ──────────────────────────────────────────
929
+ /** Stores a policy document. Nothing changes until it is activated with
930
+ * {@link activatePolicy}. The server hashes the exact text, so this
931
+ * sends the string it is given unchanged and refuses anything that is
932
+ * not a string: serializing an object here would change the hash.
933
+ * Verdifax does not write, review or approve a customer's policy. */
934
+ async uploadPolicy(document) {
935
+ this.requireAPIKey();
936
+ if (typeof document !== "string") {
937
+ throw new VerdifaxError(
938
+ "verdifax: document must be the policy's exact text, as a string"
939
+ );
940
+ }
941
+ return this.request("POST", POLICIES_PATH, { document });
942
+ }
943
+ /** This key's stored documents, with the chain its changes belong to,
944
+ * the newest change in it (64 zeros when there is none yet) and the
945
+ * document in force (empty under the built-in policy). */
946
+ async listPolicies() {
947
+ this.requireAPIKey();
948
+ return this.request("GET", POLICIES_PATH);
949
+ }
950
+ /** One stored document, with its exact text as `document`. */
951
+ async getPolicy(documentHash) {
952
+ this.requireAPIKey();
953
+ validateHex64(documentHash, "documentHash");
954
+ return this.request(
955
+ "GET",
956
+ `${POLICIES_PATH}/${documentHash}`
957
+ );
958
+ }
959
+ /** Shows which rule would fire on sample inputs, for a document given as
960
+ * text or one already stored, named by its hash: exactly one of the two.
961
+ * It seals nothing. */
962
+ async testPolicy(req) {
963
+ this.requireAPIKey();
964
+ const { inputs, document, documentHash } = req ?? {};
965
+ if (document === void 0 === (documentHash === void 0)) {
966
+ throw new VerdifaxError(
967
+ "verdifax: testPolicy needs exactly one of document or documentHash"
968
+ );
969
+ }
970
+ if (typeof inputs !== "object" || inputs === null || Array.isArray(inputs)) {
971
+ throw new VerdifaxError("verdifax: testPolicy needs inputs as an object");
972
+ }
973
+ const body = { inputs };
974
+ if (document !== void 0) {
975
+ if (typeof document !== "string") {
976
+ throw new VerdifaxError(
977
+ "verdifax: document must be the policy's exact text, as a string"
978
+ );
979
+ }
980
+ body.document = document;
981
+ } else {
982
+ validateHex64(documentHash, "documentHash");
983
+ body.document_hash = documentHash;
984
+ }
985
+ return this.request(
986
+ "POST",
987
+ `${POLICIES_PATH}/test`,
988
+ body
989
+ );
990
+ }
991
+ /** This key's policy changes, oldest first, as the list the server sends.
992
+ * Save it as JSON, for example with
993
+ * `writeFileSync("policy-history.json", JSON.stringify(history))`, and
994
+ * check it with `verdifax-verify --policy-history policy-history.json`. */
995
+ async getPolicyHistory() {
996
+ this.requireAPIKey();
997
+ return this.request("GET", `${POLICIES_PATH}/history`);
998
+ }
999
+ /** Makes a stored document the policy in force and returns the change
1000
+ * record. It first reads GET /policies for the chain and its newest
1001
+ * change, then names that change as the one this follows. With the
1002
+ * `signingKey` option the request key signs the change, which the server
1003
+ * requires while a request key is registered.
1004
+ *
1005
+ * Rolling back is activating an earlier document: it is one more change
1006
+ * in the chain, so the change it undoes stays on the record.
1007
+ *
1008
+ * An HTTP 409 means the chain moved because another change came first,
1009
+ * or the document is not yet effective. It throws the usual
1010
+ * {@link APIError} and is not retried: read the policies again and
1011
+ * decide. */
1012
+ async activatePolicy(documentHash) {
1013
+ this.requireAPIKey();
1014
+ validateHex64(documentHash, "documentHash");
1015
+ const chain = await this.listPolicies();
1016
+ const previous = chain?.newest_activation_hash;
1017
+ if (typeof previous !== "string") {
1018
+ throw new VerdifaxError(
1019
+ "verdifax: the server did not report newest_activation_hash, so the change cannot name the one it follows"
1020
+ );
1021
+ }
1022
+ const body = { previous_activation_hash: previous };
1023
+ if (this.signingKey) {
1024
+ if (typeof chain.chain_id !== "string" || chain.chain_id === "") {
1025
+ throw new VerdifaxError(
1026
+ "verdifax: the server did not report chain_id, so the change cannot be signed"
1027
+ );
1028
+ }
1029
+ body.signature = policyActivationApproval(this.signingKey, {
1030
+ chain_id: chain.chain_id,
1031
+ document_hash: documentHash,
1032
+ previous_activation_hash: previous
1033
+ });
1034
+ }
1035
+ const out = await this.request(
1036
+ "POST",
1037
+ `${POLICIES_PATH}/${documentHash}/activate`,
1038
+ body
1039
+ );
1040
+ return out.activation;
389
1041
  }
390
1042
  // ── Runs ──────────────────────────────────────────────────────
391
1043
  async getRun(runId) {
@@ -471,6 +1123,7 @@ var VerdifaxClient = class {
471
1123
  const q = new URLSearchParams();
472
1124
  if (params.from) q.set("from", params.from);
473
1125
  if (params.to) q.set("to", params.to);
1126
+ if (params.job_id) q.set("job_id", params.job_id);
474
1127
  q.set("format", format);
475
1128
  return `/runs/export?${q.toString()}`;
476
1129
  }
@@ -634,17 +1287,29 @@ var VerdifaxClient = class {
634
1287
  }
635
1288
  await this.request("DELETE", `/admin/keys/${keyId}`);
636
1289
  }
1290
+ /** Clears the request key on an API key whose holder lost it, after a
1291
+ * manual check. It is the one way to clear a key without that key. The
1292
+ * id can be any API key, so this client keeps its own signing key. */
1293
+ async adminClearRequestKey(keyId) {
1294
+ this.requireAPIKey();
1295
+ if (keyId <= 0) {
1296
+ throw new VerdifaxError("verdifax: keyId must be > 0");
1297
+ }
1298
+ await this.request("DELETE", `/admin/keys/${keyId}/request-key`);
1299
+ }
637
1300
  // ── Provider helpers (Claude / OpenAI) ───────────────────────
638
1301
  /** Convenience for attesting an Anthropic Claude API response. With
639
1302
  * `govern: true` the response text also goes to the AIVP review as
640
1303
  * `ai_output_text`; that is off by default, so the text leaves your
641
1304
  * machine for review only when you ask. */
642
1305
  async attestClaudeResponse(args) {
1306
+ refuseUnknownFields(args, PROVIDER_ARGS, "attestClaudeResponse arguments");
643
1307
  return this.attestProviderResponse({ ...args, provider: "anthropic" });
644
1308
  }
645
1309
  /** Convenience for attesting an OpenAI API response. `govern` works as
646
1310
  * in {@link attestClaudeResponse}. */
647
1311
  async attestOpenAIResponse(args) {
1312
+ refuseUnknownFields(args, PROVIDER_ARGS, "attestOpenAIResponse arguments");
648
1313
  return this.attestProviderResponse({ ...args, provider: "openai" });
649
1314
  }
650
1315
  async attestProviderResponse(args) {
@@ -666,7 +1331,10 @@ var VerdifaxClient = class {
666
1331
  attested_context: {
667
1332
  actor_role: "ai_assistant",
668
1333
  model_provider: args.provider
669
- }
1334
+ },
1335
+ job: args.job,
1336
+ policy_context: args.policy_context,
1337
+ expected_policy_hash: args.expected_policy_hash
670
1338
  });
671
1339
  }
672
1340
  // ── HTTP plumbing, retry-aware ──────────────────────────────
@@ -713,9 +1381,13 @@ var VerdifaxClient = class {
713
1381
  continue;
714
1382
  }
715
1383
  let errMessage = text.trim();
1384
+ let recordHash;
716
1385
  try {
717
1386
  const env = JSON.parse(text);
718
1387
  if (env.error) errMessage = env.error;
1388
+ if (typeof env.record_hash === "string" && env.record_hash) {
1389
+ recordHash = env.record_hash;
1390
+ }
719
1391
  } catch {
720
1392
  }
721
1393
  switch (resp.status) {
@@ -724,7 +1396,13 @@ var VerdifaxClient = class {
724
1396
  case 404:
725
1397
  throw new NotFoundError(path, errMessage);
726
1398
  default:
727
- throw new APIError(resp.status, path, errMessage);
1399
+ throw new APIError(
1400
+ resp.status,
1401
+ path,
1402
+ errMessage,
1403
+ recordHash,
1404
+ body?.signed_request
1405
+ );
728
1406
  }
729
1407
  }
730
1408
  if (rawText) return { text, headers: resp.headers };
@@ -765,13 +1443,15 @@ var VerdifaxClient = class {
765
1443
  validateRouteId(req.route_id);
766
1444
  refuseCallerOriginHashes(req.request_substance);
767
1445
  }
768
- /** The request with its derived flags and, with a signing key, a fresh
769
- * signature and nonce, on a copy. */
1446
+ /** The body to send, on a copy: the request with its derived flags or,
1447
+ * with a signing key, the signed text with a fresh signature and nonce. */
770
1448
  prepared(req) {
771
- const body = withExecuteFlags(req);
772
- return this.signingKey ? { ...body, request_signature: signRequest(this.signingKey, body) } : body;
1449
+ return this.signingKey ? signRequestV2(this.signingKey, req) : withExecuteFlags(req);
773
1450
  }
774
1451
  };
1452
+ function withSignedText(result, sent) {
1453
+ return "signed_request" in sent ? { ...result, signed_request: sent.signed_request } : result;
1454
+ }
775
1455
 
776
1456
  // src/config.ts
777
1457
  function fromEnv() {
@@ -899,7 +1579,7 @@ var DSE_FORMULA_VERSION = "dse.tcu.dispatch.v1";
899
1579
  var DCAE_PREIMAGE_VERSION = "verdifax.dcae.v1";
900
1580
  var CRES_PREIMAGE_VERSION = "verdifax.cres.v1";
901
1581
  var CRES_ENGINE_VERSION = "verdifax-cres/1.0.0";
902
- function sha256Hex(preimage) {
1582
+ function sha256Hex2(preimage) {
903
1583
  return (0, import_node_crypto2.createHash)("sha256").update(Buffer.from(preimage, "utf8")).digest("hex");
904
1584
  }
905
1585
  function requireHex64(value, name) {
@@ -914,7 +1594,7 @@ function requireHex64(value, name) {
914
1594
  function dseDispatchHash(fields) {
915
1595
  requireHex64(fields.program_id, "program_id");
916
1596
  requireHex64(fields.registry_record_hash, "registry_record_hash");
917
- return sha256Hex(
1597
+ return sha256Hex2(
918
1598
  [
919
1599
  DSE_FORMULA_VERSION,
920
1600
  fields.envelope_id,
@@ -928,7 +1608,7 @@ function dcaeClosureHash(fields) {
928
1608
  requireHex64(fields.manifest_hash, "manifest_hash");
929
1609
  requireHex64(fields.aer_hash, "aer_hash");
930
1610
  requireHex64(fields.zksp_binding_hash, "zksp_binding_hash");
931
- return sha256Hex(
1611
+ return sha256Hex2(
932
1612
  [
933
1613
  DCAE_PREIMAGE_VERSION,
934
1614
  fields.manifest_hash,
@@ -941,7 +1621,7 @@ function dcaeClosureHash(fields) {
941
1621
  }
942
1622
  function cresReceiptHash(fields) {
943
1623
  requireHex64(fields.ciphertext_hash_at_shred, "ciphertext_hash_at_shred");
944
- return sha256Hex(
1624
+ return sha256Hex2(
945
1625
  [
946
1626
  CRES_PREIMAGE_VERSION,
947
1627
  fields.envelope_id,
@@ -963,11 +1643,13 @@ function cresReceiptHash(fields) {
963
1643
  CRES_PREIMAGE_VERSION,
964
1644
  DCAE_PREIMAGE_VERSION,
965
1645
  DSE_FORMULA_VERSION,
1646
+ EXECUTE_FIELDS,
966
1647
  MAX_BATCH_ROWS,
967
1648
  NotFoundError,
968
1649
  RUN_STATUSES,
969
1650
  VerdifaxClient,
970
1651
  VerdifaxError,
1652
+ VerdifaxJob,
971
1653
  captureEnvironment,
972
1654
  cresReceiptHash,
973
1655
  dcaeClosureHash,
@@ -975,9 +1657,16 @@ function cresReceiptHash(fields) {
975
1657
  formatProviderPayload,
976
1658
  fromEnv,
977
1659
  generateRequestKeyPair,
1660
+ policyActivationApproval,
1661
+ policyActivationPreimage,
1662
+ requestKeyChangeApproval,
1663
+ requestKeyChangePreimage,
978
1664
  requestKeyRegistrationBody,
979
1665
  requestSignaturePreimage,
1666
+ requestSignaturePreimageV2,
980
1667
  signRequest,
1668
+ signRequestV2,
981
1669
  validateHex64,
1670
+ validateJobName,
982
1671
  validateRouteId
983
1672
  });