@paybond/kit 0.11.11 → 0.12.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.
Files changed (52) hide show
  1. package/completion-presets/catalog.json +10 -5
  2. package/completion-presets/catalog.sha256 +1 -1
  3. package/dist/agent/index.d.ts +2 -1
  4. package/dist/agent/index.js +1 -0
  5. package/dist/agent/interceptor.d.ts +9 -0
  6. package/dist/agent/interceptor.js +177 -1
  7. package/dist/agent/receipt-client.d.ts +49 -0
  8. package/dist/agent/receipt-client.js +45 -0
  9. package/dist/agent/registry.js +1 -0
  10. package/dist/agent/run.d.ts +2 -0
  11. package/dist/agent/run.js +52 -0
  12. package/dist/agent/types.d.ts +70 -0
  13. package/dist/agent-receipt-external-attestations.d.ts +29 -0
  14. package/dist/agent-receipt-external-attestations.js +124 -0
  15. package/dist/agent-receipt.d.ts +134 -0
  16. package/dist/agent-receipt.js +580 -0
  17. package/dist/audit/exports.d.ts +15 -1
  18. package/dist/audit/exports.js +55 -8
  19. package/dist/audit/index.d.ts +2 -2
  20. package/dist/audit/wire.d.ts +12 -0
  21. package/dist/audit/wire.js +13 -1
  22. package/dist/cli/command-spec.js +4 -2
  23. package/dist/cli/commands/discovery.js +17 -6
  24. package/dist/cli/help.d.ts +1 -1
  25. package/dist/cli/help.js +3 -3
  26. package/dist/completion-catalog-digest.d.ts +1 -1
  27. package/dist/completion-catalog-digest.js +1 -1
  28. package/dist/index.d.ts +83 -7
  29. package/dist/index.js +180 -13
  30. package/dist/mcp-receipt-resource.d.ts +10 -0
  31. package/dist/mcp-receipt-resource.js +32 -0
  32. package/dist/mcp-server.d.ts +6 -0
  33. package/dist/mcp-server.js +62 -1
  34. package/dist/mpp-commercial.d.ts +19 -0
  35. package/dist/mpp-commercial.js +34 -0
  36. package/dist/mpp-funding.d.ts +71 -0
  37. package/dist/mpp-funding.js +192 -0
  38. package/dist/payment-transport.d.ts +30 -0
  39. package/dist/payment-transport.js +56 -0
  40. package/dist/policy/intent-spec.js +2 -0
  41. package/dist/principal-intent.d.ts +1 -1
  42. package/dist/principal-intent.js +4 -1
  43. package/package.json +1 -1
  44. package/templates/openai-shopping-agent/package-lock.json +7 -7
  45. package/templates/paybond-aws-operator/package-lock.json +4 -4
  46. package/templates/paybond-claude-agents-demo/package-lock.json +7 -7
  47. package/templates/paybond-mastra-travel-agent/package-lock.json +10 -10
  48. package/templates/paybond-mcp-coding-agent/package-lock.json +4 -4
  49. package/templates/paybond-openai-agents-demo/package-lock.json +7 -7
  50. package/templates/paybond-procurement-agent/package-lock.json +4 -4
  51. package/templates/paybond-travel-agent/package-lock.json +7 -7
  52. package/templates/paybond-vercel-shopping-agent/package-lock.json +4 -4
@@ -0,0 +1,580 @@
1
+ import { createHash } from "node:crypto";
2
+ import { verify } from "@noble/ed25519";
3
+ import { ensureEd25519Sha512Sync } from "./ed25519-sync.js";
4
+ export const AGENT_RECEIPT_SCHEMA_VERSION = 1;
5
+ export const AGENT_RECEIPT_KIND_V1 = "paybond.agent_receipt_v1";
6
+ export const AGENT_RECEIPT_VERSION_V1 = "1";
7
+ export const AGENT_RECEIPT_SIGNING_ALGORITHM_ED25519 = "ed25519-sha256-json-v1";
8
+ export const AGENT_RECEIPT_SCOPE_ACTION = "action";
9
+ export const AGENT_RECEIPT_SCOPE_INTENT_TERMINAL = "intent_terminal";
10
+ export const AGENT_RECEIPT_WELL_KNOWN_PATH = "/.well-known/agent-receipt-v1.json";
11
+ const SCOPE_TOKEN_RE = /^[a-z0-9][a-z0-9._:/-]{0,127}$/;
12
+ const HEX64_RE = /^[0-9a-f]{64}$/;
13
+ const CURRENCY_RE = /^[a-z]{3}$/;
14
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
15
+ function sha256Hex(data) {
16
+ return createHash("sha256").update(data).digest("hex");
17
+ }
18
+ function formatRfc3339Seconds(iso) {
19
+ const date = new Date(iso);
20
+ if (Number.isNaN(date.getTime())) {
21
+ throw new Error("agent receipt: timestamp is invalid");
22
+ }
23
+ return date.toISOString().replace(/\.\d{3}Z$/, "Z");
24
+ }
25
+ function canonicalizeJson(value) {
26
+ if (Array.isArray(value)) {
27
+ return value.map((item) => canonicalizeJson(item));
28
+ }
29
+ if (value && typeof value === "object") {
30
+ const record = value;
31
+ const keys = Object.keys(record).sort();
32
+ const out = {};
33
+ for (const key of keys) {
34
+ out[key] = canonicalizeJson(record[key]);
35
+ }
36
+ return out;
37
+ }
38
+ return value;
39
+ }
40
+ function jcsBytes(value) {
41
+ return new TextEncoder().encode(JSON.stringify(canonicalizeJson(value)));
42
+ }
43
+ /** Returns sha256(JCS({ system_prompt, tools_manifest, policy_snapshot_id })). */
44
+ export function configHashSha256Hex(input) {
45
+ return sha256Hex(jcsBytes(input));
46
+ }
47
+ /** Returns sha256(normalized_user_prompt). */
48
+ export function promptHashSha256Hex(normalizedUserPrompt) {
49
+ return sha256Hex(normalizedUserPrompt);
50
+ }
51
+ /** Returns sha256(JCS(value)). */
52
+ export function valueDigestSha256Hex(value) {
53
+ return sha256Hex(jcsBytes(value));
54
+ }
55
+ /** Returns sha256(intent_id + "\\x00" + tool_call_id) as lowercase hex. */
56
+ export function actionReceiptId(intentId, toolCallId) {
57
+ return sha256Hex(`${intentId}\u0000${toolCallId}`);
58
+ }
59
+ function normalizeScopeToken(value, field) {
60
+ const normalized = value.trim().toLowerCase();
61
+ if (!normalized) {
62
+ throw new Error(`agent receipt: ${field} is required`);
63
+ }
64
+ if (!SCOPE_TOKEN_RE.test(normalized)) {
65
+ throw new Error(`agent receipt: ${field} ${JSON.stringify(normalized)} is not canonical`);
66
+ }
67
+ return normalized;
68
+ }
69
+ function requireHex64(value, field) {
70
+ if (!HEX64_RE.test(value)) {
71
+ throw new Error(`agent receipt: ${field} must be a lowercase 64-byte hex SHA-256 digest`);
72
+ }
73
+ }
74
+ function parseUuid(value, field) {
75
+ const normalized = value.trim().toLowerCase();
76
+ if (!UUID_RE.test(normalized)) {
77
+ throw new Error(`agent receipt: ${field} must be a canonical UUID`);
78
+ }
79
+ return normalized;
80
+ }
81
+ function normalizeScopeSet(values, field) {
82
+ if (!values?.length) {
83
+ return [];
84
+ }
85
+ const seen = new Set();
86
+ const out = [];
87
+ for (const value of values) {
88
+ const normalized = normalizeScopeToken(value, field);
89
+ if (!seen.has(normalized)) {
90
+ seen.add(normalized);
91
+ out.push(normalized);
92
+ }
93
+ }
94
+ return out;
95
+ }
96
+ function normalizeReceipt(receipt) {
97
+ const schemaVersion = receipt.schema_version === 0 ? AGENT_RECEIPT_SCHEMA_VERSION : receipt.schema_version;
98
+ if (schemaVersion !== AGENT_RECEIPT_SCHEMA_VERSION) {
99
+ throw new Error(`agent receipt: unsupported schema_version ${schemaVersion}`);
100
+ }
101
+ const kind = receipt.kind.trim() || AGENT_RECEIPT_KIND_V1;
102
+ if (kind !== AGENT_RECEIPT_KIND_V1) {
103
+ throw new Error(`agent receipt: unsupported kind ${JSON.stringify(kind)}`);
104
+ }
105
+ const receiptVersion = receipt.receipt_version.trim() || AGENT_RECEIPT_VERSION_V1;
106
+ if (receiptVersion !== AGENT_RECEIPT_VERSION_V1) {
107
+ throw new Error(`agent receipt: unsupported receipt_version ${JSON.stringify(receiptVersion)}`);
108
+ }
109
+ const scope = receipt.scope.trim().toLowerCase();
110
+ if (scope !== AGENT_RECEIPT_SCOPE_ACTION && scope !== AGENT_RECEIPT_SCOPE_INTENT_TERMINAL) {
111
+ throw new Error(`agent receipt: scope must be ${AGENT_RECEIPT_SCOPE_ACTION} or ${AGENT_RECEIPT_SCOPE_INTENT_TERMINAL}`);
112
+ }
113
+ const receiptId = receipt.receipt_id.trim().toLowerCase();
114
+ if (!receiptId) {
115
+ throw new Error("agent receipt: receipt_id is required");
116
+ }
117
+ const tenantId = receipt.tenant_id.trim();
118
+ if (!tenantId) {
119
+ throw new Error("agent receipt: tenant_id is required");
120
+ }
121
+ const authorization = normalizeAuthorization(receipt.authorization);
122
+ const outcome = normalizeOutcome(receipt.outcome);
123
+ const references = normalizeReferences(receipt.references);
124
+ const externalAttestations = normalizeExternalAttestations(receipt.external_attestations ?? []);
125
+ let execution;
126
+ if (scope === AGENT_RECEIPT_SCOPE_ACTION) {
127
+ if (!receipt.execution) {
128
+ throw new Error("agent receipt: execution is required for action scope");
129
+ }
130
+ execution = normalizeExecution(receipt.execution);
131
+ }
132
+ const normalized = {
133
+ schema_version: AGENT_RECEIPT_SCHEMA_VERSION,
134
+ kind: AGENT_RECEIPT_KIND_V1,
135
+ receipt_version: AGENT_RECEIPT_VERSION_V1,
136
+ scope: scope,
137
+ receipt_id: receiptId,
138
+ issued_at: formatRfc3339Seconds(receipt.issued_at),
139
+ tenant_id: tenantId,
140
+ authorization,
141
+ execution,
142
+ merchant: receipt.merchant ? normalizeMerchant(receipt.merchant) : undefined,
143
+ evidence: receipt.evidence ? normalizeEvidence(receipt.evidence) : undefined,
144
+ payment: receipt.payment ? normalizePayment(receipt.payment) : undefined,
145
+ outcome,
146
+ references,
147
+ external_attestations: externalAttestations,
148
+ signing_algorithm: receipt.signing_algorithm.trim().toLowerCase() || AGENT_RECEIPT_SIGNING_ALGORITHM_ED25519,
149
+ message_digest_sha256_hex: receipt.message_digest_sha256_hex.trim().toLowerCase(),
150
+ signing_public_key_ed25519_hex: receipt.signing_public_key_ed25519_hex.trim().toLowerCase(),
151
+ ed25519_signature_hex: receipt.ed25519_signature_hex.trim().toLowerCase(),
152
+ };
153
+ verifyReceiptId(normalized);
154
+ return normalized;
155
+ }
156
+ function normalizeAuthorization(authorization) {
157
+ const principalDid = authorization.principal_did.trim();
158
+ const actorSubject = authorization.actor_subject.trim();
159
+ if (!principalDid) {
160
+ throw new Error("agent receipt: principal_did is required");
161
+ }
162
+ if (!actorSubject) {
163
+ throw new Error("agent receipt: actor_subject is required");
164
+ }
165
+ const currency = authorization.currency.trim().toLowerCase();
166
+ if (!CURRENCY_RE.test(currency)) {
167
+ throw new Error(`agent receipt: currency ${JSON.stringify(currency)} is not canonical`);
168
+ }
169
+ if (authorization.requested_spend_cents < 0) {
170
+ throw new Error("agent receipt: requested_spend_cents must be non-negative");
171
+ }
172
+ return {
173
+ principal_did: principalDid,
174
+ actor_subject: actorSubject,
175
+ agent: normalizeAgent(authorization.agent),
176
+ decision_id: parseUuid(authorization.decision_id, "decision_id"),
177
+ audit_id: authorization.audit_id ? parseUuid(authorization.audit_id, "audit_id") : undefined,
178
+ policy: normalizePolicy(authorization.policy),
179
+ authorized_at: formatRfc3339Seconds(authorization.authorized_at),
180
+ requested_spend_cents: authorization.requested_spend_cents,
181
+ currency,
182
+ reason_codes: normalizeScopeSet(authorization.reason_codes, "reason_codes"),
183
+ };
184
+ }
185
+ function normalizeAgent(agent) {
186
+ const modelFamily = normalizeScopeToken(agent.model_family, "agent.model_family");
187
+ const configHash = agent.config_hash_sha256_hex.trim().toLowerCase();
188
+ const promptHash = agent.prompt_hash_sha256_hex.trim().toLowerCase();
189
+ requireHex64(configHash, "agent.config_hash_sha256_hex");
190
+ requireHex64(promptHash, "agent.prompt_hash_sha256_hex");
191
+ const operatorDid = agent.operator_did.trim();
192
+ if (!operatorDid) {
193
+ throw new Error("agent receipt: agent.operator_did is required");
194
+ }
195
+ return {
196
+ operator_did: operatorDid,
197
+ model_family: modelFamily,
198
+ model_instance_id: agent.model_instance_id?.trim() || undefined,
199
+ config_hash_sha256_hex: configHash,
200
+ prompt_hash_sha256_hex: promptHash,
201
+ deployment_epoch: agent.deployment_epoch,
202
+ };
203
+ }
204
+ function normalizePolicy(policy) {
205
+ const templateId = policy.template_id.trim();
206
+ const digest = policy.content_digest_sha256_hex.trim().toLowerCase();
207
+ if (!templateId) {
208
+ throw new Error("agent receipt: policy.template_id is required");
209
+ }
210
+ requireHex64(digest, "policy.content_digest_sha256_hex");
211
+ return {
212
+ template_id: templateId,
213
+ version_seq: policy.version_seq,
214
+ content_digest_sha256_hex: digest,
215
+ spend_policy_version: policy.spend_policy_version,
216
+ };
217
+ }
218
+ function normalizeExecution(execution) {
219
+ const toolCallId = execution.tool_call_id.trim();
220
+ if (!toolCallId) {
221
+ throw new Error("agent receipt: tool_call_id is required");
222
+ }
223
+ const argumentsDigest = execution.arguments_digest_sha256_hex.trim().toLowerCase();
224
+ requireHex64(argumentsDigest, "arguments_digest_sha256_hex");
225
+ let resultDigest;
226
+ if (execution.result_digest_sha256_hex) {
227
+ resultDigest = execution.result_digest_sha256_hex.trim().toLowerCase();
228
+ requireHex64(resultDigest, "result_digest_sha256_hex");
229
+ }
230
+ const outcome = execution.outcome.trim().toLowerCase();
231
+ if (!["executed", "denied", "skipped", "failed"].includes(outcome)) {
232
+ throw new Error("agent receipt: outcome must be executed, denied, skipped, or failed");
233
+ }
234
+ if ((execution.duration_ms ?? 0) < 0) {
235
+ throw new Error("agent receipt: duration_ms must be non-negative");
236
+ }
237
+ return {
238
+ run_id: parseUuid(execution.run_id, "run_id"),
239
+ tool_call_id: toolCallId,
240
+ tool_name: normalizeScopeToken(execution.tool_name, "tool_name"),
241
+ operation: normalizeScopeToken(execution.operation, "operation"),
242
+ arguments_digest_sha256_hex: argumentsDigest,
243
+ result_digest_sha256_hex: resultDigest,
244
+ outcome: outcome,
245
+ started_at: formatRfc3339Seconds(execution.started_at),
246
+ completed_at: formatRfc3339Seconds(execution.completed_at),
247
+ duration_ms: execution.duration_ms,
248
+ };
249
+ }
250
+ function normalizeMerchant(merchant) {
251
+ const payeeDid = merchant.payee_did.trim();
252
+ if (!payeeDid) {
253
+ throw new Error("agent receipt: payee_did is required");
254
+ }
255
+ return {
256
+ payee_did: payeeDid,
257
+ vendor_id: merchant.vendor_id ? normalizeScopeToken(merchant.vendor_id, "vendor_id") : undefined,
258
+ vendor_ref_id: merchant.vendor_ref_id?.trim() || undefined,
259
+ };
260
+ }
261
+ function normalizeEvidence(evidence) {
262
+ const payloadDigest = evidence.payload_digest_sha256_hex.trim().toLowerCase();
263
+ requireHex64(payloadDigest, "payload_digest_sha256_hex");
264
+ let artifactsDigest;
265
+ if (evidence.artifacts_digest_sha256_hex) {
266
+ artifactsDigest = evidence.artifacts_digest_sha256_hex.trim().toLowerCase();
267
+ requireHex64(artifactsDigest, "artifacts_digest_sha256_hex");
268
+ }
269
+ let payeeSignatureDigest;
270
+ if (evidence.payee_signature_digest_sha256_hex) {
271
+ payeeSignatureDigest = evidence.payee_signature_digest_sha256_hex.trim().toLowerCase();
272
+ requireHex64(payeeSignatureDigest, "payee_signature_digest_sha256_hex");
273
+ }
274
+ const payeeDid = evidence.payee_did.trim();
275
+ if (!payeeDid) {
276
+ throw new Error("agent receipt: payee_did is required");
277
+ }
278
+ return {
279
+ completion_preset_id: normalizeScopeToken(evidence.completion_preset_id, "completion_preset_id"),
280
+ payload_digest_sha256_hex: payloadDigest,
281
+ artifacts_digest_sha256_hex: artifactsDigest,
282
+ predicate_passed: evidence.predicate_passed,
283
+ payee_did: payeeDid,
284
+ payee_signature_digest_sha256_hex: payeeSignatureDigest,
285
+ };
286
+ }
287
+ function normalizePayment(payment) {
288
+ let fundingDigest;
289
+ if (payment.funding_receipt_digest_sha256_hex) {
290
+ fundingDigest = payment.funding_receipt_digest_sha256_hex.trim().toLowerCase();
291
+ requireHex64(fundingDigest, "funding_receipt_digest_sha256_hex");
292
+ }
293
+ return {
294
+ intent_id: parseUuid(payment.intent_id, "intent_id"),
295
+ settlement_rail: normalizeScopeToken(payment.settlement_rail, "settlement_rail"),
296
+ funding_method: payment.funding_method
297
+ ? normalizeScopeToken(payment.funding_method, "funding_method")
298
+ : undefined,
299
+ funding_reference: payment.funding_reference?.trim() || undefined,
300
+ funding_receipt_digest_sha256_hex: fundingDigest,
301
+ };
302
+ }
303
+ function normalizeOutcome(outcome) {
304
+ const harborState = normalizeScopeToken(outcome.harbor_state, "harbor_state");
305
+ let spendReservationOutcome;
306
+ if (outcome.spend_reservation_outcome) {
307
+ const normalized = outcome.spend_reservation_outcome.trim().toLowerCase();
308
+ if (!["consumed", "released", "pending", "none"].includes(normalized)) {
309
+ throw new Error("agent receipt: spend_reservation_outcome must be consumed, released, pending, or none");
310
+ }
311
+ spendReservationOutcome = normalized;
312
+ }
313
+ return {
314
+ harbor_state: harborState,
315
+ spend_reservation_outcome: spendReservationOutcome,
316
+ predicate_passed: outcome.predicate_passed,
317
+ };
318
+ }
319
+ function normalizeReferences(references) {
320
+ if ((references.ledger_seq ?? 0) < 0) {
321
+ throw new Error("agent receipt: ledger_seq must be non-negative");
322
+ }
323
+ let settlementReceiptId = references.settlement_receipt_id;
324
+ if (settlementReceiptId) {
325
+ const trimmed = settlementReceiptId.trim().toLowerCase();
326
+ if (!trimmed) {
327
+ settlementReceiptId = null;
328
+ }
329
+ else if (!UUID_RE.test(trimmed) && !HEX64_RE.test(trimmed)) {
330
+ throw new Error("agent receipt: settlement_receipt_id must be a canonical UUID or lowercase 64-byte hex digest");
331
+ }
332
+ else {
333
+ settlementReceiptId = trimmed;
334
+ }
335
+ }
336
+ return {
337
+ intent_id: parseUuid(references.intent_id, "intent_id"),
338
+ ledger_seq: references.ledger_seq,
339
+ settlement_receipt_id: settlementReceiptId ?? null,
340
+ };
341
+ }
342
+ function normalizeExternalAttestations(values) {
343
+ return values.map((value) => {
344
+ const digest = value.digest_sha256_hex.trim().toLowerCase();
345
+ requireHex64(digest, "digest_sha256_hex");
346
+ if (!value.kind.trim()) {
347
+ throw new Error("agent receipt: kind is required");
348
+ }
349
+ return {
350
+ source: normalizeScopeToken(value.source, "source"),
351
+ kind: value.kind.trim(),
352
+ digest_sha256_hex: digest,
353
+ reference_id: value.reference_id?.trim() || undefined,
354
+ };
355
+ });
356
+ }
357
+ function verifyReceiptId(receipt) {
358
+ if (receipt.scope === AGENT_RECEIPT_SCOPE_ACTION) {
359
+ if (!receipt.execution) {
360
+ throw new Error("agent receipt: execution is required to verify action receipt_id");
361
+ }
362
+ const expected = actionReceiptId(receipt.references.intent_id, receipt.execution.tool_call_id);
363
+ if (receipt.receipt_id !== expected) {
364
+ throw new Error("agent receipt: receipt_id does not match action scope derivation");
365
+ }
366
+ requireHex64(receipt.receipt_id, "receipt_id");
367
+ return;
368
+ }
369
+ if (receipt.receipt_id !== receipt.references.intent_id) {
370
+ throw new Error("agent receipt: receipt_id must equal intent_id for intent_terminal scope");
371
+ }
372
+ parseUuid(receipt.receipt_id, "receipt_id");
373
+ }
374
+ function marshalCanonicalAgentReceipt(receipt) {
375
+ const authorization = {
376
+ principal_did: receipt.authorization.principal_did,
377
+ actor_subject: receipt.authorization.actor_subject,
378
+ agent: {
379
+ operator_did: receipt.authorization.agent.operator_did,
380
+ model_family: receipt.authorization.agent.model_family,
381
+ ...(receipt.authorization.agent.model_instance_id
382
+ ? { model_instance_id: receipt.authorization.agent.model_instance_id }
383
+ : {}),
384
+ config_hash_sha256_hex: receipt.authorization.agent.config_hash_sha256_hex,
385
+ prompt_hash_sha256_hex: receipt.authorization.agent.prompt_hash_sha256_hex,
386
+ ...(receipt.authorization.agent.deployment_epoch
387
+ ? { deployment_epoch: receipt.authorization.agent.deployment_epoch }
388
+ : {}),
389
+ },
390
+ decision_id: receipt.authorization.decision_id,
391
+ ...(receipt.authorization.audit_id ? { audit_id: receipt.authorization.audit_id } : {}),
392
+ policy: {
393
+ template_id: receipt.authorization.policy.template_id,
394
+ ...(receipt.authorization.policy.version_seq
395
+ ? { version_seq: receipt.authorization.policy.version_seq }
396
+ : {}),
397
+ content_digest_sha256_hex: receipt.authorization.policy.content_digest_sha256_hex,
398
+ ...(receipt.authorization.policy.spend_policy_version
399
+ ? { spend_policy_version: receipt.authorization.policy.spend_policy_version }
400
+ : {}),
401
+ },
402
+ authorized_at: receipt.authorization.authorized_at,
403
+ requested_spend_cents: receipt.authorization.requested_spend_cents,
404
+ currency: receipt.authorization.currency,
405
+ ...(receipt.authorization.reason_codes?.length
406
+ ? { reason_codes: receipt.authorization.reason_codes }
407
+ : {}),
408
+ };
409
+ const payload = {
410
+ schema_version: receipt.schema_version,
411
+ kind: receipt.kind,
412
+ receipt_version: receipt.receipt_version,
413
+ scope: receipt.scope,
414
+ receipt_id: receipt.receipt_id,
415
+ issued_at: receipt.issued_at,
416
+ tenant_id: receipt.tenant_id,
417
+ authorization,
418
+ };
419
+ if (receipt.execution) {
420
+ payload.execution = {
421
+ run_id: receipt.execution.run_id,
422
+ tool_call_id: receipt.execution.tool_call_id,
423
+ tool_name: receipt.execution.tool_name,
424
+ operation: receipt.execution.operation,
425
+ arguments_digest_sha256_hex: receipt.execution.arguments_digest_sha256_hex,
426
+ ...(receipt.execution.result_digest_sha256_hex
427
+ ? { result_digest_sha256_hex: receipt.execution.result_digest_sha256_hex }
428
+ : {}),
429
+ outcome: receipt.execution.outcome,
430
+ started_at: receipt.execution.started_at,
431
+ completed_at: receipt.execution.completed_at,
432
+ ...(receipt.execution.duration_ms ? { duration_ms: receipt.execution.duration_ms } : {}),
433
+ };
434
+ }
435
+ if (receipt.merchant) {
436
+ payload.merchant = {
437
+ payee_did: receipt.merchant.payee_did,
438
+ ...(receipt.merchant.vendor_id ? { vendor_id: receipt.merchant.vendor_id } : {}),
439
+ ...(receipt.merchant.vendor_ref_id ? { vendor_ref_id: receipt.merchant.vendor_ref_id } : {}),
440
+ };
441
+ }
442
+ if (receipt.evidence) {
443
+ payload.evidence = {
444
+ completion_preset_id: receipt.evidence.completion_preset_id,
445
+ payload_digest_sha256_hex: receipt.evidence.payload_digest_sha256_hex,
446
+ ...(receipt.evidence.artifacts_digest_sha256_hex
447
+ ? { artifacts_digest_sha256_hex: receipt.evidence.artifacts_digest_sha256_hex }
448
+ : {}),
449
+ predicate_passed: receipt.evidence.predicate_passed,
450
+ payee_did: receipt.evidence.payee_did,
451
+ ...(receipt.evidence.payee_signature_digest_sha256_hex
452
+ ? { payee_signature_digest_sha256_hex: receipt.evidence.payee_signature_digest_sha256_hex }
453
+ : {}),
454
+ };
455
+ }
456
+ if (receipt.payment) {
457
+ payload.payment = {
458
+ intent_id: receipt.payment.intent_id,
459
+ settlement_rail: receipt.payment.settlement_rail,
460
+ ...(receipt.payment.funding_method ? { funding_method: receipt.payment.funding_method } : {}),
461
+ ...(receipt.payment.funding_reference
462
+ ? { funding_reference: receipt.payment.funding_reference }
463
+ : {}),
464
+ ...(receipt.payment.funding_receipt_digest_sha256_hex
465
+ ? { funding_receipt_digest_sha256_hex: receipt.payment.funding_receipt_digest_sha256_hex }
466
+ : {}),
467
+ };
468
+ }
469
+ payload.outcome = {
470
+ harbor_state: receipt.outcome.harbor_state,
471
+ ...(receipt.outcome.spend_reservation_outcome
472
+ ? { spend_reservation_outcome: receipt.outcome.spend_reservation_outcome }
473
+ : {}),
474
+ ...(receipt.outcome.predicate_passed !== undefined
475
+ ? { predicate_passed: receipt.outcome.predicate_passed }
476
+ : {}),
477
+ };
478
+ payload.references = {
479
+ intent_id: receipt.references.intent_id,
480
+ ...(receipt.references.ledger_seq ? { ledger_seq: receipt.references.ledger_seq } : {}),
481
+ settlement_receipt_id: receipt.references.settlement_receipt_id ?? null,
482
+ };
483
+ payload.external_attestations =
484
+ receipt.external_attestations.length > 0 ? receipt.external_attestations : null;
485
+ return new TextEncoder().encode(JSON.stringify(payload));
486
+ }
487
+ /** Returns canonical signing bytes for a normalized receipt body. */
488
+ export function canonicalAgentReceiptBytes(receipt) {
489
+ return marshalCanonicalAgentReceipt(normalizeReceipt(receipt));
490
+ }
491
+ /**
492
+ * Returns sha256(canonical receipt bytes) as lowercase hex, ignoring any existing
493
+ * `message_digest_sha256_hex` on the input. Used to compose unsigned receipt drafts
494
+ * (Agent Receipt Standard Phase 1) and to compute the digest signers must sign over.
495
+ */
496
+ export function agentReceiptMessageDigestSha256Hex(receipt) {
497
+ return sha256Hex(canonicalAgentReceiptBytes(receipt));
498
+ }
499
+ /** Validates structure, receipt_id derivation, digest, and detached Ed25519 signature. */
500
+ export async function verifyAgentReceiptV1(receipt) {
501
+ ensureEd25519Sha512Sync();
502
+ const normalized = normalizeReceipt(receipt);
503
+ const canonical = marshalCanonicalAgentReceipt(normalized);
504
+ const digest = createHash("sha256").update(canonical).digest();
505
+ const digestHex = sha256Hex(canonical);
506
+ if (normalized.signing_algorithm !== AGENT_RECEIPT_SIGNING_ALGORITHM_ED25519) {
507
+ throw new Error(`agent receipt: signing_algorithm must be ${AGENT_RECEIPT_SIGNING_ALGORITHM_ED25519}`);
508
+ }
509
+ requireHex64(normalized.message_digest_sha256_hex, "message_digest_sha256_hex");
510
+ if (normalized.message_digest_sha256_hex !== digestHex) {
511
+ throw new Error("agent receipt: message digest mismatch");
512
+ }
513
+ const publicKey = hexToBytes(normalized.signing_public_key_ed25519_hex);
514
+ const signature = hexToBytes(normalized.ed25519_signature_hex);
515
+ if (publicKey.length !== 32 || signature.length !== 64) {
516
+ throw new Error("agent receipt: invalid signing material");
517
+ }
518
+ const valid = await verify(signature, digest, publicKey);
519
+ if (!valid) {
520
+ throw new Error("agent receipt: ed25519 signature verification failed");
521
+ }
522
+ await verifyOperatorAttestation(normalized, digest);
523
+ return normalized;
524
+ }
525
+ async function verifyOperatorAttestation(receipt, gatewayDigest) {
526
+ const attestation = receipt.operator_attestation;
527
+ if (!attestation) {
528
+ return;
529
+ }
530
+ const operatorDid = attestation.operator_did?.trim();
531
+ if (!operatorDid) {
532
+ throw new Error("agent receipt: operator_attestation.operator_did is required");
533
+ }
534
+ requireHex64(attestation.message_digest_sha256_hex, "operator_attestation.message_digest_sha256_hex");
535
+ if (attestation.message_digest_sha256_hex !== receipt.message_digest_sha256_hex) {
536
+ throw new Error("agent receipt: operator_attestation message_digest_sha256_hex must match gateway digest");
537
+ }
538
+ const publicKey = hexToBytes(attestation.signing_public_key_ed25519_hex);
539
+ const signature = hexToBytes(attestation.ed25519_signature_hex);
540
+ if (publicKey.length !== 32 || signature.length !== 64) {
541
+ throw new Error("agent receipt: invalid operator attestation signing material");
542
+ }
543
+ const valid = await verify(signature, gatewayDigest, publicKey);
544
+ if (!valid) {
545
+ throw new Error("agent receipt: operator attestation ed25519 signature verification failed");
546
+ }
547
+ }
548
+ /** Attach an optional operator counter-signature over the Gateway message digest. */
549
+ export async function attachOperatorAttestationV1(receipt, operatorPrivateKeyHex, operatorDid) {
550
+ ensureEd25519Sha512Sync();
551
+ const verified = await verifyAgentReceiptV1(receipt);
552
+ const digest = hexToBytes(verified.message_digest_sha256_hex);
553
+ const privateKey = hexToBytes(operatorPrivateKeyHex);
554
+ if (privateKey.length !== 64 && privateKey.length !== 32) {
555
+ throw new Error("agent receipt: operator private key must be 32- or 64-byte ed25519 material");
556
+ }
557
+ const { sign } = await import("@noble/ed25519");
558
+ const signature = await sign(digest, privateKey.slice(0, 32));
559
+ const { getPublicKey } = await import("@noble/ed25519");
560
+ const publicKey = await getPublicKey(privateKey.slice(0, 32));
561
+ return {
562
+ ...verified,
563
+ operator_attestation: {
564
+ operator_did: operatorDid.trim(),
565
+ signing_public_key_ed25519_hex: Buffer.from(publicKey).toString("hex"),
566
+ message_digest_sha256_hex: verified.message_digest_sha256_hex,
567
+ ed25519_signature_hex: Buffer.from(signature).toString("hex"),
568
+ },
569
+ };
570
+ }
571
+ function hexToBytes(value) {
572
+ if (value.length % 2 !== 0) {
573
+ return new Uint8Array();
574
+ }
575
+ const out = new Uint8Array(value.length / 2);
576
+ for (let index = 0; index < out.length; index += 1) {
577
+ out[index] = Number.parseInt(value.slice(index * 2, index * 2 + 2), 16);
578
+ }
579
+ return out;
580
+ }
@@ -1,6 +1,7 @@
1
- import { type AuditExportJobGetResponse, type AuditExportListPage, type AuditVerifyResult } from "./wire.js";
1
+ import { type AuditExportCreateFilter, type AuditExportJobGetResponse, type AuditExportListPage, type AuditVerifyResult } from "./wire.js";
2
2
  export type AuditExportsGateway = {
3
3
  getJson(path: string): Promise<Record<string, unknown>>;
4
+ postJson?(path: string, body: Record<string, unknown>): Promise<Record<string, unknown>>;
4
5
  deleteJson?(path: string): Promise<Record<string, unknown>>;
5
6
  };
6
7
  export type GatewayAuditExportsClientOptions = {
@@ -17,6 +18,7 @@ export declare class GatewayAuditExportsClient implements AuditExportsGateway {
17
18
  private readonly maxRetries;
18
19
  constructor(gatewayBaseUrl: string, tenantId: string, options: GatewayAuditExportsClientOptions);
19
20
  getJson(path: string): Promise<Record<string, unknown>>;
21
+ postJson(path: string, body: Record<string, unknown>): Promise<Record<string, unknown>>;
20
22
  deleteJson(path: string): Promise<Record<string, unknown>>;
21
23
  private requestJSON;
22
24
  }
@@ -27,6 +29,13 @@ export type PaybondAuditExportsListParams = {
27
29
  export type PaybondAuditExportsGetParams = {
28
30
  issueDownload?: boolean;
29
31
  };
32
+ export type PaybondAuditExportsCreateParams = {
33
+ filter: AuditExportCreateFilter;
34
+ /** Defaults to `standard` when omitted. */
35
+ disclosureTier?: "standard" | "extended";
36
+ /** Bundle retention in hours (gateway default 168, max 720). */
37
+ retentionHours?: number;
38
+ };
30
39
  /**
31
40
  * SDK surface for compliance audit export jobs and local bundle verification.
32
41
  */
@@ -39,6 +48,11 @@ export declare class PaybondAuditExports {
39
48
  static open(gatewayBaseUrl: string, tenantId: string, options: GatewayAuditExportsClientOptions): PaybondAuditExports;
40
49
  list(params?: PaybondAuditExportsListParams): Promise<AuditExportListPage>;
41
50
  get(jobId: string, params?: PaybondAuditExportsGetParams): Promise<AuditExportJobGetResponse>;
51
+ /**
52
+ * Create a compliance audit export job (`POST /v1/compliance/audit-exports`).
53
+ * Tenant scope comes from the API key — never pass a tenant id.
54
+ */
55
+ create(params: PaybondAuditExportsCreateParams): Promise<AuditExportJobGetResponse>;
42
56
  delete(jobId: string): Promise<{
43
57
  job_id: string;
44
58
  deleted: true;