@paybond/kit 0.12.0 → 0.12.1

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 (107) hide show
  1. package/dist/agent/evidence.d.ts +10 -0
  2. package/dist/agent/evidence.js +16 -0
  3. package/dist/agent/index.d.ts +1 -1
  4. package/dist/agent/index.js +1 -1
  5. package/dist/agent/interceptor.js +4 -0
  6. package/dist/agent/receipt-client.d.ts +16 -1
  7. package/dist/agent/run.d.ts +3 -0
  8. package/dist/agent/run.js +1 -1
  9. package/dist/agent-mandate.d.ts +103 -0
  10. package/dist/agent-mandate.js +423 -0
  11. package/dist/agent-receipt-external-attestations.d.ts +27 -0
  12. package/dist/agent-receipt-external-attestations.js +61 -0
  13. package/dist/agent-receipt-pdf-export.d.ts +43 -0
  14. package/dist/agent-receipt-pdf-export.js +109 -0
  15. package/dist/agent-receipt-prevalidate.d.ts +7 -0
  16. package/dist/agent-receipt-prevalidate.js +63 -0
  17. package/dist/agent-receipt.d.ts +21 -1
  18. package/dist/agent-receipt.js +63 -4
  19. package/dist/cli/command-spec.js +50 -1
  20. package/dist/cli/commands/dev.js +10 -3
  21. package/dist/cli/commands/setup.js +19 -1
  22. package/dist/cli/commands/shopify.d.ts +53 -0
  23. package/dist/cli/commands/shopify.js +808 -0
  24. package/dist/cli/help.d.ts +1 -1
  25. package/dist/cli/help.js +13 -3
  26. package/dist/cli/router.js +15 -1
  27. package/dist/commerce-binding.d.ts +59 -0
  28. package/dist/commerce-binding.js +129 -0
  29. package/dist/doctor-completion.d.ts +16 -0
  30. package/dist/doctor-completion.js +157 -1
  31. package/dist/index.d.ts +27 -2
  32. package/dist/index.js +43 -7
  33. package/dist/mcp-server.d.ts +1 -0
  34. package/dist/mcp-server.js +28 -9
  35. package/dist/policy/presets.d.ts +1 -1
  36. package/dist/policy/presets.js +1 -0
  37. package/dist/project-init.d.ts +1 -1
  38. package/dist/project-init.js +1 -0
  39. package/dist/protocol-receipt.d.ts +129 -0
  40. package/dist/protocol-receipt.js +620 -0
  41. package/dist/shopify/checkout.d.ts +29 -0
  42. package/dist/shopify/checkout.js +79 -0
  43. package/dist/shopify/evidence.d.ts +13 -0
  44. package/dist/shopify/evidence.js +85 -0
  45. package/dist/shopify/index.d.ts +8 -0
  46. package/dist/shopify/index.js +6 -0
  47. package/dist/shopify/instrument.d.ts +61 -0
  48. package/dist/shopify/instrument.js +52 -0
  49. package/dist/shopify/order.d.ts +8 -0
  50. package/dist/shopify/order.js +110 -0
  51. package/dist/shopify/types.d.ts +82 -0
  52. package/dist/shopify/types.js +4 -0
  53. package/dist/solutions/catalog.d.ts +1 -1
  54. package/dist/solutions/catalog.js +1 -1
  55. package/dist/stripe-commerce/evidence.d.ts +13 -0
  56. package/dist/stripe-commerce/evidence.js +164 -0
  57. package/dist/stripe-commerce/index.d.ts +3 -0
  58. package/dist/stripe-commerce/index.js +2 -0
  59. package/dist/stripe-commerce/metadata.d.ts +11 -0
  60. package/dist/stripe-commerce/metadata.js +34 -0
  61. package/dist/stripe-commerce/types.d.ts +38 -0
  62. package/dist/stripe-commerce/types.js +1 -0
  63. package/dist/template-init.d.ts +1 -1
  64. package/dist/template-init.js +6 -1
  65. package/package.json +1 -1
  66. package/policy/presets/stripe-commerce.yaml +19 -0
  67. package/solutions/stripe-commerce.json +19 -0
  68. package/templates/manifest.json +82 -10
  69. package/templates/openai-shopping-agent/package-lock.json +10 -10
  70. package/templates/openai-shopping-agent/src/paybond.config.ts +1 -1
  71. package/templates/paybond-aws-operator/package-lock.json +7 -7
  72. package/templates/paybond-aws-operator/src/paybond.config.ts +1 -1
  73. package/templates/paybond-claude-agents-demo/package-lock.json +7 -7
  74. package/templates/paybond-claude-agents-demo/src/paybond.config.ts +1 -1
  75. package/templates/paybond-mastra-travel-agent/package-lock.json +30 -30
  76. package/templates/paybond-mastra-travel-agent/src/paybond.config.ts +1 -1
  77. package/templates/paybond-mcp-coding-agent/package-lock.json +7 -7
  78. package/templates/paybond-mcp-coding-agent/src/paybond.config.ts +1 -1
  79. package/templates/paybond-openai-agents-demo/package-lock.json +10 -10
  80. package/templates/paybond-openai-agents-demo/src/paybond.config.ts +1 -1
  81. package/templates/paybond-procurement-agent/package-lock.json +7 -7
  82. package/templates/paybond-procurement-agent/src/paybond.config.ts +1 -1
  83. package/templates/paybond-shopify-shopping-agent/.env.example +3 -0
  84. package/templates/paybond-shopify-shopping-agent/.github/workflows/smoke.yml +20 -0
  85. package/templates/paybond-shopify-shopping-agent/LICENSE +201 -0
  86. package/templates/paybond-shopify-shopping-agent/README.md +29 -0
  87. package/templates/paybond-shopify-shopping-agent/package-lock.json +223 -0
  88. package/templates/paybond-shopify-shopping-agent/package.json +20 -0
  89. package/templates/paybond-shopify-shopping-agent/paybond.policy.yaml +22 -0
  90. package/templates/paybond-shopify-shopping-agent/src/index.ts +54 -0
  91. package/templates/paybond-shopify-shopping-agent/src/paybond.config.ts +51 -0
  92. package/templates/paybond-shopify-shopping-agent/tsconfig.json +13 -0
  93. package/templates/paybond-stripe-agent-demo/.env.example +9 -0
  94. package/templates/paybond-stripe-agent-demo/.github/workflows/smoke.yml +20 -0
  95. package/templates/paybond-stripe-agent-demo/LICENSE +201 -0
  96. package/templates/paybond-stripe-agent-demo/README.md +50 -0
  97. package/templates/paybond-stripe-agent-demo/package-lock.json +223 -0
  98. package/templates/paybond-stripe-agent-demo/package.json +20 -0
  99. package/templates/paybond-stripe-agent-demo/paybond.policy.yaml +22 -0
  100. package/templates/paybond-stripe-agent-demo/src/charge-customer.ts +237 -0
  101. package/templates/paybond-stripe-agent-demo/src/index.ts +78 -0
  102. package/templates/paybond-stripe-agent-demo/src/paybond.config.ts +51 -0
  103. package/templates/paybond-stripe-agent-demo/tsconfig.json +13 -0
  104. package/templates/paybond-travel-agent/package-lock.json +13 -13
  105. package/templates/paybond-travel-agent/src/paybond.config.ts +1 -1
  106. package/templates/paybond-vercel-shopping-agent/package-lock.json +7 -7
  107. package/templates/paybond-vercel-shopping-agent/src/paybond.config.ts +1 -1
@@ -7,6 +7,7 @@
7
7
  import type { AgentReceiptExternalAttestationV1 } from "./agent-receipt.js";
8
8
  export declare const AGENT_RECEIPT_EXTERNAL_SOURCE_SEP2828 = "sep2828_mcp";
9
9
  export declare const AGENT_RECEIPT_EXTERNAL_SOURCE_X402 = "x402";
10
+ export declare const AGENT_RECEIPT_EXTERNAL_SOURCE_AP2 = "ap2";
10
11
  /** SHA-256 hex digest of canonical JSON bytes. */
11
12
  export declare function partnerRecordDigestSha256Hex(record: Record<string, unknown>): string;
12
13
  /**
@@ -17,6 +18,20 @@ export declare function sep2828RecordsToExternalAttestations(decisionInput: Reco
17
18
  * Converts a verified x402 signed delivery receipt into one external attestation entry.
18
19
  */
19
20
  export declare function x402ReceiptToExternalAttestations(receiptInput: Record<string, unknown>): AgentReceiptExternalAttestationV1[];
21
+ /**
22
+ * Converts a verified signed AP2 agent mandate into one external attestation entry.
23
+ */
24
+ export declare function signedMandateToExternalAttestations(signed: Record<string, unknown>, transportBinding?: {
25
+ external_authorization_id?: string;
26
+ }): AgentReceiptExternalAttestationV1[];
27
+ /**
28
+ * Converts a verified AP2 protocol authorization receipt into one external attestation entry.
29
+ */
30
+ export declare function protocolAuthorizationReceiptToExternalAttestations(receipt: Record<string, unknown>): AgentReceiptExternalAttestationV1[];
31
+ /**
32
+ * Converts a verified AP2 protocol settlement receipt into one external attestation entry.
33
+ */
34
+ export declare function protocolSettlementReceiptToExternalAttestations(receipt: Record<string, unknown>): AgentReceiptExternalAttestationV1[];
20
35
  export type PaybondExternalAttestationInput = {
21
36
  kind: "sep2828";
22
37
  decision: Record<string, unknown>;
@@ -24,6 +39,18 @@ export type PaybondExternalAttestationInput = {
24
39
  } | {
25
40
  kind: "x402";
26
41
  receipt: Record<string, unknown>;
42
+ } | {
43
+ kind: "ap2_mandate";
44
+ signedMandate: Record<string, unknown>;
45
+ transportBinding?: {
46
+ external_authorization_id?: string;
47
+ };
48
+ } | {
49
+ kind: "ap2_authorization_receipt";
50
+ receipt: Record<string, unknown>;
51
+ } | {
52
+ kind: "ap2_settlement_receipt";
53
+ receipt: Record<string, unknown>;
27
54
  } | AgentReceiptExternalAttestationV1;
28
55
  /** Resolves pre-built or partner-native attestation inputs into normalized receipt entries. */
29
56
  export declare function resolveExternalAttestations(inputs: readonly PaybondExternalAttestationInput[]): AgentReceiptExternalAttestationV1[];
@@ -5,13 +5,16 @@
5
5
  * These entries are never canonical inside Paybond; they provide interop hooks only.
6
6
  */
7
7
  import { createHash } from "node:crypto";
8
+ import { readString, verifySignedAgentMandateV1 } from "./agent-mandate.js";
8
9
  import { normalizeJson } from "./json-digest.js";
10
+ import { verifyProtocolAuthorizationReceiptV1, verifyProtocolSettlementReceiptV1, } from "./protocol-receipt.js";
9
11
  import { stripDigestPrefix } from "./mcp-sep2828-evidence.js";
10
12
  import { verifySep2828ReceiptPair } from "./sep2828-signature.js";
11
13
  import { buildX402ReceiptDigestPayload, } from "./x402-receipt-evidence.js";
12
14
  import { extractSignedX402Receipt, verifySignedX402Receipt } from "./x402-receipt-signature.js";
13
15
  export const AGENT_RECEIPT_EXTERNAL_SOURCE_SEP2828 = "sep2828_mcp";
14
16
  export const AGENT_RECEIPT_EXTERNAL_SOURCE_X402 = "x402";
17
+ export const AGENT_RECEIPT_EXTERNAL_SOURCE_AP2 = "ap2";
15
18
  const SEP2828_SIGNATURE_KEYS = new Set([
16
19
  "signature",
17
20
  "ed25519_signature_hex",
@@ -104,6 +107,52 @@ export function x402ReceiptToExternalAttestations(receiptInput) {
104
107
  },
105
108
  ];
106
109
  }
110
+ /**
111
+ * Converts a verified signed AP2 agent mandate into one external attestation entry.
112
+ */
113
+ export function signedMandateToExternalAttestations(signed, transportBinding) {
114
+ verifySignedAgentMandateV1(signed);
115
+ const digest = readString(signed.message_digest_sha256_hex).trim().toLowerCase();
116
+ const externalAuthorizationId = transportBinding?.external_authorization_id?.trim();
117
+ const nonce = readString(signed.nonce).trim();
118
+ const referenceID = externalAuthorizationId || nonce || undefined;
119
+ return [
120
+ {
121
+ source: AGENT_RECEIPT_EXTERNAL_SOURCE_AP2,
122
+ kind: "agent_mandate_v1",
123
+ digest_sha256_hex: digest,
124
+ reference_id: referenceID,
125
+ },
126
+ ];
127
+ }
128
+ /**
129
+ * Converts a verified AP2 protocol authorization receipt into one external attestation entry.
130
+ */
131
+ export function protocolAuthorizationReceiptToExternalAttestations(receipt) {
132
+ const verified = verifyProtocolAuthorizationReceiptV1(receipt);
133
+ return [
134
+ {
135
+ source: AGENT_RECEIPT_EXTERNAL_SOURCE_AP2,
136
+ kind: "protocol_authorization_receipt_v1",
137
+ digest_sha256_hex: verified.message_digest_sha256_hex,
138
+ reference_id: verified.intent_id,
139
+ },
140
+ ];
141
+ }
142
+ /**
143
+ * Converts a verified AP2 protocol settlement receipt into one external attestation entry.
144
+ */
145
+ export function protocolSettlementReceiptToExternalAttestations(receipt) {
146
+ const verified = verifyProtocolSettlementReceiptV1(receipt);
147
+ return [
148
+ {
149
+ source: AGENT_RECEIPT_EXTERNAL_SOURCE_AP2,
150
+ kind: "protocol_settlement_receipt_v1",
151
+ digest_sha256_hex: verified.message_digest_sha256_hex,
152
+ reference_id: verified.intent_id,
153
+ },
154
+ ];
155
+ }
107
156
  /** Resolves pre-built or partner-native attestation inputs into normalized receipt entries. */
108
157
  export function resolveExternalAttestations(inputs) {
109
158
  const out = [];
@@ -118,6 +167,18 @@ export function resolveExternalAttestations(inputs) {
118
167
  }
119
168
  if (input.kind === "x402") {
120
169
  out.push(...x402ReceiptToExternalAttestations(input.receipt));
170
+ continue;
171
+ }
172
+ if (input.kind === "ap2_mandate") {
173
+ out.push(...signedMandateToExternalAttestations(input.signedMandate, input.transportBinding));
174
+ continue;
175
+ }
176
+ if (input.kind === "ap2_authorization_receipt") {
177
+ out.push(...protocolAuthorizationReceiptToExternalAttestations(input.receipt));
178
+ continue;
179
+ }
180
+ if (input.kind === "ap2_settlement_receipt") {
181
+ out.push(...protocolSettlementReceiptToExternalAttestations(input.receipt));
121
182
  }
122
183
  }
123
184
  return out;
@@ -0,0 +1,43 @@
1
+ import { type AgentReceiptV1, type VerifyAgentReceiptV1Options } from "./agent-receipt.js";
2
+ export declare const AGENT_RECEIPT_PDF_EXPORT_MANIFEST_SCHEMA_VERSION = 1;
3
+ export declare const AGENT_RECEIPT_PDF_EXPORT_MANIFEST_KIND = "paybond.agent_receipt_pdf_export_manifest_v1";
4
+ export declare const AGENT_RECEIPT_PDF_EXPORT_DERIVED_VIEW_LABEL = "Derived from paybond.agent_receipt_v1";
5
+ export declare const FORBIDDEN_PDF_EXPORT_MANIFEST_FIELDS: readonly ["embedded_receipt_json", "receipt_json", "unsigned_receipt", "canonical_receipt", "user_prompt", "system_prompt", "tool_arguments", "tool_results", "evidence_payload", "payee_signature"];
6
+ export type AgentReceiptPDFExportSourceKind = "gateway_fetch" | "audit_export" | "local_file";
7
+ export type AgentReceiptPDFExportFooterStamp = {
8
+ label: typeof AGENT_RECEIPT_PDF_EXPORT_DERIVED_VIEW_LABEL;
9
+ receipt_id: string;
10
+ message_digest_sha256_hex: string;
11
+ verify_endpoint?: string;
12
+ };
13
+ export type AgentReceiptPDFExportManifest = {
14
+ schema_version: typeof AGENT_RECEIPT_PDF_EXPORT_MANIFEST_SCHEMA_VERSION;
15
+ kind: typeof AGENT_RECEIPT_PDF_EXPORT_MANIFEST_KIND;
16
+ receipt_id: string;
17
+ message_digest_sha256_hex: string;
18
+ source_kind: AgentReceiptPDFExportSourceKind;
19
+ source_artifact?: string;
20
+ generated_at_rfc3339: string;
21
+ renderer_id?: string;
22
+ pdf_sha256_hex?: string;
23
+ pdf_page_count?: number;
24
+ derived_view_label: typeof AGENT_RECEIPT_PDF_EXPORT_DERIVED_VIEW_LABEL;
25
+ footer_stamp: AgentReceiptPDFExportFooterStamp;
26
+ };
27
+ /** Reject authority-embedding fields and validate against the published Draft 2020-12 schema. */
28
+ export declare function validateAgentReceiptPDFExportManifestJSON(value: unknown): AgentReceiptPDFExportManifest;
29
+ export declare function parseAgentReceiptPDFExportManifestJSON(raw: string | Uint8Array): AgentReceiptPDFExportManifest;
30
+ export type GateAgentReceiptPDFExportInput = {
31
+ receiptJSON: string | Uint8Array;
32
+ manifestJSON: string | Uint8Array;
33
+ pdfBytes?: Uint8Array;
34
+ verifyOptions?: VerifyAgentReceiptV1Options;
35
+ };
36
+ /**
37
+ * Enforces the PDF export verification gate before rendering or accepting a derived PDF.
38
+ * Verify signed JSON first, bind manifest/footer stamps, optionally verify PDF bytes hash.
39
+ */
40
+ export declare function gateAgentReceiptPDFExport(input: GateAgentReceiptPDFExportInput): Promise<{
41
+ receipt: AgentReceiptV1;
42
+ manifest: AgentReceiptPDFExportManifest;
43
+ }>;
@@ -0,0 +1,109 @@
1
+ import { createHash } from "node:crypto";
2
+ import { readFileSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { Ajv2020 } from "ajv/dist/2020.js";
6
+ import { verifyAgentReceiptV1FromJSON, } from "./agent-receipt.js";
7
+ const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
8
+ const AGENT_RECEIPT_DIR = join(MODULE_DIR, "../../agent-receipt");
9
+ export const AGENT_RECEIPT_PDF_EXPORT_MANIFEST_SCHEMA_VERSION = 1;
10
+ export const AGENT_RECEIPT_PDF_EXPORT_MANIFEST_KIND = "paybond.agent_receipt_pdf_export_manifest_v1";
11
+ export const AGENT_RECEIPT_PDF_EXPORT_DERIVED_VIEW_LABEL = "Derived from paybond.agent_receipt_v1";
12
+ export const FORBIDDEN_PDF_EXPORT_MANIFEST_FIELDS = [
13
+ "embedded_receipt_json",
14
+ "receipt_json",
15
+ "unsigned_receipt",
16
+ "canonical_receipt",
17
+ "user_prompt",
18
+ "system_prompt",
19
+ "tool_arguments",
20
+ "tool_results",
21
+ "evidence_payload",
22
+ "payee_signature",
23
+ ];
24
+ let manifestSchemaValidator;
25
+ function manifestSchemaValidate() {
26
+ if (!manifestSchemaValidator) {
27
+ const ajv = new Ajv2020({ allErrors: true, strict: false });
28
+ const schema = JSON.parse(readFileSync(join(AGENT_RECEIPT_DIR, "pdf-export-manifest-schema.json"), "utf8"));
29
+ manifestSchemaValidator = ajv.compile(schema);
30
+ }
31
+ return manifestSchemaValidator;
32
+ }
33
+ function rejectForbiddenPDFExportManifestFields(value) {
34
+ if (Array.isArray(value)) {
35
+ for (const item of value) {
36
+ rejectForbiddenPDFExportManifestFields(item);
37
+ }
38
+ return;
39
+ }
40
+ if (!value || typeof value !== "object") {
41
+ return;
42
+ }
43
+ const record = value;
44
+ for (const [key, child] of Object.entries(record)) {
45
+ if (FORBIDDEN_PDF_EXPORT_MANIFEST_FIELDS.includes(key)) {
46
+ throw new Error(`agent receipt pdf export manifest: forbidden field ${JSON.stringify(key)}`);
47
+ }
48
+ rejectForbiddenPDFExportManifestFields(child);
49
+ }
50
+ }
51
+ /** Reject authority-embedding fields and validate against the published Draft 2020-12 schema. */
52
+ export function validateAgentReceiptPDFExportManifestJSON(value) {
53
+ rejectForbiddenPDFExportManifestFields(value);
54
+ const validate = manifestSchemaValidate();
55
+ if (!validate(value)) {
56
+ throw new Error(`agent receipt pdf export manifest: schema validation failed: ${JSON.stringify(validate.errors ?? [])}`);
57
+ }
58
+ return value;
59
+ }
60
+ export function parseAgentReceiptPDFExportManifestJSON(raw) {
61
+ const text = typeof raw === "string" ? raw : new TextDecoder().decode(raw);
62
+ let parsed;
63
+ try {
64
+ parsed = JSON.parse(text);
65
+ }
66
+ catch {
67
+ throw new Error("agent receipt pdf export manifest: invalid JSON");
68
+ }
69
+ return validateAgentReceiptPDFExportManifestJSON(parsed);
70
+ }
71
+ function assertManifestMatchesReceipt(manifest, receipt) {
72
+ const receiptId = receipt.receipt_id.trim().toLowerCase();
73
+ const digest = receipt.message_digest_sha256_hex.trim().toLowerCase();
74
+ if (manifest.receipt_id.trim().toLowerCase() !== receiptId) {
75
+ throw new Error("agent receipt pdf export gate: manifest receipt_id does not match verified receipt");
76
+ }
77
+ if (manifest.message_digest_sha256_hex.trim().toLowerCase() !== digest) {
78
+ throw new Error("agent receipt pdf export gate: manifest message_digest_sha256_hex does not match verified receipt");
79
+ }
80
+ if (manifest.derived_view_label !== AGENT_RECEIPT_PDF_EXPORT_DERIVED_VIEW_LABEL) {
81
+ throw new Error(`agent receipt pdf export gate: derived_view_label must be ${JSON.stringify(AGENT_RECEIPT_PDF_EXPORT_DERIVED_VIEW_LABEL)}`);
82
+ }
83
+ const stamp = manifest.footer_stamp;
84
+ if (stamp.receipt_id.trim().toLowerCase() !== receiptId) {
85
+ throw new Error("agent receipt pdf export gate: footer_stamp receipt_id does not match verified receipt");
86
+ }
87
+ if (stamp.message_digest_sha256_hex.trim().toLowerCase() !== digest) {
88
+ throw new Error("agent receipt pdf export gate: footer_stamp message_digest_sha256_hex does not match verified receipt");
89
+ }
90
+ if (stamp.label !== AGENT_RECEIPT_PDF_EXPORT_DERIVED_VIEW_LABEL) {
91
+ throw new Error(`agent receipt pdf export gate: footer_stamp label must be ${JSON.stringify(AGENT_RECEIPT_PDF_EXPORT_DERIVED_VIEW_LABEL)}`);
92
+ }
93
+ }
94
+ /**
95
+ * Enforces the PDF export verification gate before rendering or accepting a derived PDF.
96
+ * Verify signed JSON first, bind manifest/footer stamps, optionally verify PDF bytes hash.
97
+ */
98
+ export async function gateAgentReceiptPDFExport(input) {
99
+ const receipt = await verifyAgentReceiptV1FromJSON(input.receiptJSON, input.verifyOptions);
100
+ const manifest = parseAgentReceiptPDFExportManifestJSON(input.manifestJSON);
101
+ assertManifestMatchesReceipt(manifest, receipt);
102
+ if (input.pdfBytes && manifest.pdf_sha256_hex) {
103
+ const actual = createHash("sha256").update(input.pdfBytes).digest("hex");
104
+ if (actual !== manifest.pdf_sha256_hex.trim().toLowerCase()) {
105
+ throw new Error("agent receipt pdf export gate: pdf_sha256_hex mismatch");
106
+ }
107
+ }
108
+ return { receipt, manifest };
109
+ }
@@ -0,0 +1,7 @@
1
+ import type { AgentReceiptV1 } from "./agent-receipt.js";
2
+ /** Privacy-sensitive keys that MUST NOT appear anywhere in agent receipt JSON. */
3
+ export declare const FORBIDDEN_AGENT_RECEIPT_FIELDS: readonly ["user_prompt", "system_prompt", "tool_arguments", "tool_results", "evidence_payload", "payee_signature"];
4
+ /** Reject forbidden privacy fields and validate against the published Draft 2020-12 schema. */
5
+ export declare function validateAgentReceiptJSON(value: unknown): AgentReceiptV1;
6
+ /** Parse and validate untrusted agent receipt JSON before signature verification. */
7
+ export declare function parseAgentReceiptJSON(raw: string | Uint8Array): AgentReceiptV1;
@@ -0,0 +1,63 @@
1
+ import { Ajv2020 } from "ajv/dist/2020.js";
2
+ import { readFileSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
6
+ const AGENT_RECEIPT_DIR = join(MODULE_DIR, "../../agent-receipt");
7
+ /** Privacy-sensitive keys that MUST NOT appear anywhere in agent receipt JSON. */
8
+ export const FORBIDDEN_AGENT_RECEIPT_FIELDS = [
9
+ "user_prompt",
10
+ "system_prompt",
11
+ "tool_arguments",
12
+ "tool_results",
13
+ "evidence_payload",
14
+ "payee_signature",
15
+ ];
16
+ let schemaValidator;
17
+ function schemaValidate() {
18
+ if (!schemaValidator) {
19
+ const ajv = new Ajv2020({ allErrors: true, strict: false });
20
+ const schema = JSON.parse(readFileSync(join(AGENT_RECEIPT_DIR, "schema.json"), "utf8"));
21
+ schemaValidator = ajv.compile(schema);
22
+ }
23
+ return schemaValidator;
24
+ }
25
+ function rejectForbiddenAgentReceiptFields(value) {
26
+ if (Array.isArray(value)) {
27
+ for (const item of value) {
28
+ rejectForbiddenAgentReceiptFields(item);
29
+ }
30
+ return;
31
+ }
32
+ if (!value || typeof value !== "object") {
33
+ return;
34
+ }
35
+ const record = value;
36
+ for (const [key, child] of Object.entries(record)) {
37
+ if (FORBIDDEN_AGENT_RECEIPT_FIELDS.includes(key)) {
38
+ throw new Error(`agent receipt: forbidden field ${JSON.stringify(key)}`);
39
+ }
40
+ rejectForbiddenAgentReceiptFields(child);
41
+ }
42
+ }
43
+ /** Reject forbidden privacy fields and validate against the published Draft 2020-12 schema. */
44
+ export function validateAgentReceiptJSON(value) {
45
+ rejectForbiddenAgentReceiptFields(value);
46
+ const validate = schemaValidate();
47
+ if (!validate(value)) {
48
+ throw new Error(`agent receipt: schema validation failed: ${JSON.stringify(validate.errors ?? [])}`);
49
+ }
50
+ return value;
51
+ }
52
+ /** Parse and validate untrusted agent receipt JSON before signature verification. */
53
+ export function parseAgentReceiptJSON(raw) {
54
+ const text = typeof raw === "string" ? raw : new TextDecoder().decode(raw);
55
+ let parsed;
56
+ try {
57
+ parsed = JSON.parse(text);
58
+ }
59
+ catch {
60
+ throw new Error("agent receipt: invalid JSON");
61
+ }
62
+ return validateAgentReceiptJSON(parsed);
63
+ }
@@ -5,6 +5,11 @@ export declare const AGENT_RECEIPT_SIGNING_ALGORITHM_ED25519 = "ed25519-sha256-j
5
5
  export declare const AGENT_RECEIPT_SCOPE_ACTION = "action";
6
6
  export declare const AGENT_RECEIPT_SCOPE_INTENT_TERMINAL = "intent_terminal";
7
7
  export declare const AGENT_RECEIPT_WELL_KNOWN_PATH = "/.well-known/agent-receipt-v1.json";
8
+ export declare const AGENT_RECEIPT_SIGNING_KEYS_WELL_KNOWN_PATH = "/.well-known/agent-receipt-signing-keys.json";
9
+ /** Gateway evidence proxy header carrying Kit-verified external attestation digests. */
10
+ export declare const PAYBOND_AGENT_RECEIPT_ATTESTATIONS_HEADER = "x-paybond-agent-receipt-attestations";
11
+ /** Optional agent run id bound to the attestation header for server-side audit. */
12
+ export declare const PAYBOND_AGENT_RECEIPT_SOURCE_RUN_HEADER = "x-paybond-agent-run-id";
8
13
  export type AgentReceiptAgentV1 = {
9
14
  operator_did: string;
10
15
  model_family: string;
@@ -128,7 +133,22 @@ export declare function canonicalAgentReceiptBytes(receipt: AgentReceiptV1): Uin
128
133
  * (Agent Receipt Standard Phase 1) and to compute the digest signers must sign over.
129
134
  */
130
135
  export declare function agentReceiptMessageDigestSha256Hex(receipt: AgentReceiptV1): string;
136
+ /** Optional trust-anchor checks during agent receipt verification. */
137
+ export type VerifyAgentReceiptV1Options = {
138
+ /** Lowercase signing_public_key_ed25519_hex values accepted when non-empty. */
139
+ expectedSigningPublicKeys?: readonly string[];
140
+ /**
141
+ * When true, require any operator_attestation signing key to appear in
142
+ * trustedOperatorPublicKeys (e.g. tenant middleware attach recognition keys). The
143
+ * operator_did binding to authorization.agent.operator_did is always enforced.
144
+ */
145
+ verifyOperatorAgainstRegistry?: boolean;
146
+ /** Lowercase operator signing pubkeys accepted when the registry check is enabled. */
147
+ trustedOperatorPublicKeys?: readonly string[];
148
+ };
131
149
  /** Validates structure, receipt_id derivation, digest, and detached Ed25519 signature. */
132
- export declare function verifyAgentReceiptV1(receipt: AgentReceiptV1): Promise<AgentReceiptV1>;
150
+ export declare function verifyAgentReceiptV1(receipt: AgentReceiptV1, options?: VerifyAgentReceiptV1Options): Promise<AgentReceiptV1>;
151
+ /** Validate raw JSON (schema + forbidden fields) then verify signature. */
152
+ export declare function verifyAgentReceiptV1FromJSON(raw: string | Uint8Array | Record<string, unknown>, options?: VerifyAgentReceiptV1Options): Promise<AgentReceiptV1>;
133
153
  /** Attach an optional operator counter-signature over the Gateway message digest. */
134
154
  export declare function attachOperatorAttestationV1(receipt: AgentReceiptV1, operatorPrivateKeyHex: string, operatorDid: string): Promise<AgentReceiptV1>;
@@ -1,6 +1,7 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { verify } from "@noble/ed25519";
3
3
  import { ensureEd25519Sha512Sync } from "./ed25519-sync.js";
4
+ import { parseAgentReceiptJSON, validateAgentReceiptJSON } from "./agent-receipt-prevalidate.js";
4
5
  export const AGENT_RECEIPT_SCHEMA_VERSION = 1;
5
6
  export const AGENT_RECEIPT_KIND_V1 = "paybond.agent_receipt_v1";
6
7
  export const AGENT_RECEIPT_VERSION_V1 = "1";
@@ -8,6 +9,11 @@ export const AGENT_RECEIPT_SIGNING_ALGORITHM_ED25519 = "ed25519-sha256-json-v1";
8
9
  export const AGENT_RECEIPT_SCOPE_ACTION = "action";
9
10
  export const AGENT_RECEIPT_SCOPE_INTENT_TERMINAL = "intent_terminal";
10
11
  export const AGENT_RECEIPT_WELL_KNOWN_PATH = "/.well-known/agent-receipt-v1.json";
12
+ export const AGENT_RECEIPT_SIGNING_KEYS_WELL_KNOWN_PATH = "/.well-known/agent-receipt-signing-keys.json";
13
+ /** Gateway evidence proxy header carrying Kit-verified external attestation digests. */
14
+ export const PAYBOND_AGENT_RECEIPT_ATTESTATIONS_HEADER = "x-paybond-agent-receipt-attestations";
15
+ /** Optional agent run id bound to the attestation header for server-side audit. */
16
+ export const PAYBOND_AGENT_RECEIPT_SOURCE_RUN_HEADER = "x-paybond-agent-run-id";
11
17
  const SCOPE_TOKEN_RE = /^[a-z0-9][a-z0-9._:/-]{0,127}$/;
12
18
  const HEX64_RE = /^[0-9a-f]{64}$/;
13
19
  const CURRENCY_RE = /^[a-z]{3}$/;
@@ -145,6 +151,9 @@ function normalizeReceipt(receipt) {
145
151
  outcome,
146
152
  references,
147
153
  external_attestations: externalAttestations,
154
+ operator_attestation: receipt.operator_attestation
155
+ ? normalizeOperatorAttestation(receipt.operator_attestation)
156
+ : undefined,
148
157
  signing_algorithm: receipt.signing_algorithm.trim().toLowerCase() || AGENT_RECEIPT_SIGNING_ALGORITHM_ED25519,
149
158
  message_digest_sha256_hex: receipt.message_digest_sha256_hex.trim().toLowerCase(),
150
159
  signing_public_key_ed25519_hex: receipt.signing_public_key_ed25519_hex.trim().toLowerCase(),
@@ -153,6 +162,18 @@ function normalizeReceipt(receipt) {
153
162
  verifyReceiptId(normalized);
154
163
  return normalized;
155
164
  }
165
+ function normalizeOperatorAttestation(attestation) {
166
+ const operatorDid = attestation.operator_did.trim();
167
+ if (!operatorDid) {
168
+ throw new Error("agent receipt: operator_attestation.operator_did is required");
169
+ }
170
+ return {
171
+ operator_did: operatorDid,
172
+ signing_public_key_ed25519_hex: attestation.signing_public_key_ed25519_hex.trim().toLowerCase(),
173
+ message_digest_sha256_hex: attestation.message_digest_sha256_hex.trim().toLowerCase(),
174
+ ed25519_signature_hex: attestation.ed25519_signature_hex.trim().toLowerCase(),
175
+ };
176
+ }
156
177
  function normalizeAuthorization(authorization) {
157
178
  const principalDid = authorization.principal_did.trim();
158
179
  const actorSubject = authorization.actor_subject.trim();
@@ -496,10 +517,27 @@ export function canonicalAgentReceiptBytes(receipt) {
496
517
  export function agentReceiptMessageDigestSha256Hex(receipt) {
497
518
  return sha256Hex(canonicalAgentReceiptBytes(receipt));
498
519
  }
520
+ function allowsSigningPublicKeyHex(signingPublicKeyHex, expectedSigningPublicKeys) {
521
+ if (!expectedSigningPublicKeys || expectedSigningPublicKeys.length === 0) {
522
+ return true;
523
+ }
524
+ const normalized = signingPublicKeyHex.trim().toLowerCase();
525
+ return expectedSigningPublicKeys.some((value) => value.trim().toLowerCase() === normalized);
526
+ }
527
+ function allowsOperatorPublicKeyHex(operatorPublicKeyHex, trustedOperatorPublicKeys) {
528
+ if (!trustedOperatorPublicKeys || trustedOperatorPublicKeys.length === 0) {
529
+ return false;
530
+ }
531
+ const normalized = operatorPublicKeyHex.trim().toLowerCase();
532
+ return trustedOperatorPublicKeys.some((value) => value.trim().toLowerCase() === normalized);
533
+ }
499
534
  /** Validates structure, receipt_id derivation, digest, and detached Ed25519 signature. */
500
- export async function verifyAgentReceiptV1(receipt) {
535
+ export async function verifyAgentReceiptV1(receipt, options = {}) {
501
536
  ensureEd25519Sha512Sync();
502
537
  const normalized = normalizeReceipt(receipt);
538
+ if (!allowsSigningPublicKeyHex(normalized.signing_public_key_ed25519_hex, options.expectedSigningPublicKeys)) {
539
+ throw new Error("agent receipt: signing_public_key_ed25519_hex is not in the configured trusted key set");
540
+ }
503
541
  const canonical = marshalCanonicalAgentReceipt(normalized);
504
542
  const digest = createHash("sha256").update(canonical).digest();
505
543
  const digestHex = sha256Hex(canonical);
@@ -519,10 +557,17 @@ export async function verifyAgentReceiptV1(receipt) {
519
557
  if (!valid) {
520
558
  throw new Error("agent receipt: ed25519 signature verification failed");
521
559
  }
522
- await verifyOperatorAttestation(normalized, digest);
560
+ await verifyOperatorAttestation(normalized, digest, options);
523
561
  return normalized;
524
562
  }
525
- async function verifyOperatorAttestation(receipt, gatewayDigest) {
563
+ /** Validate raw JSON (schema + forbidden fields) then verify signature. */
564
+ export async function verifyAgentReceiptV1FromJSON(raw, options = {}) {
565
+ const receipt = typeof raw === "object" && !(raw instanceof Uint8Array) && !Array.isArray(raw)
566
+ ? validateAgentReceiptJSON(raw)
567
+ : parseAgentReceiptJSON(raw);
568
+ return verifyAgentReceiptV1(receipt, options);
569
+ }
570
+ async function verifyOperatorAttestation(receipt, gatewayDigest, options = {}) {
526
571
  const attestation = receipt.operator_attestation;
527
572
  if (!attestation) {
528
573
  return;
@@ -531,10 +576,17 @@ async function verifyOperatorAttestation(receipt, gatewayDigest) {
531
576
  if (!operatorDid) {
532
577
  throw new Error("agent receipt: operator_attestation.operator_did is required");
533
578
  }
579
+ if (operatorDid !== receipt.authorization.agent.operator_did.trim()) {
580
+ throw new Error("agent receipt: operator_attestation.operator_did must match authorization.agent.operator_did");
581
+ }
534
582
  requireHex64(attestation.message_digest_sha256_hex, "operator_attestation.message_digest_sha256_hex");
535
583
  if (attestation.message_digest_sha256_hex !== receipt.message_digest_sha256_hex) {
536
584
  throw new Error("agent receipt: operator_attestation message_digest_sha256_hex must match gateway digest");
537
585
  }
586
+ if (options.verifyOperatorAgainstRegistry &&
587
+ !allowsOperatorPublicKeyHex(attestation.signing_public_key_ed25519_hex, options.trustedOperatorPublicKeys)) {
588
+ throw new Error("agent receipt: operator_attestation signing key is not in the configured tenant operator registry");
589
+ }
538
590
  const publicKey = hexToBytes(attestation.signing_public_key_ed25519_hex);
539
591
  const signature = hexToBytes(attestation.ed25519_signature_hex);
540
592
  if (publicKey.length !== 32 || signature.length !== 64) {
@@ -549,6 +601,13 @@ async function verifyOperatorAttestation(receipt, gatewayDigest) {
549
601
  export async function attachOperatorAttestationV1(receipt, operatorPrivateKeyHex, operatorDid) {
550
602
  ensureEd25519Sha512Sync();
551
603
  const verified = await verifyAgentReceiptV1(receipt);
604
+ const normalizedOperatorDid = operatorDid.trim();
605
+ if (!normalizedOperatorDid) {
606
+ throw new Error("agent receipt: operator_did is required");
607
+ }
608
+ if (normalizedOperatorDid !== verified.authorization.agent.operator_did.trim()) {
609
+ throw new Error("agent receipt: operator_did must match authorization.agent.operator_did");
610
+ }
552
611
  const digest = hexToBytes(verified.message_digest_sha256_hex);
553
612
  const privateKey = hexToBytes(operatorPrivateKeyHex);
554
613
  if (privateKey.length !== 64 && privateKey.length !== 32) {
@@ -561,7 +620,7 @@ export async function attachOperatorAttestationV1(receipt, operatorPrivateKeyHex
561
620
  return {
562
621
  ...verified,
563
622
  operator_attestation: {
564
- operator_did: operatorDid.trim(),
623
+ operator_did: normalizedOperatorDid,
565
624
  signing_public_key_ed25519_hex: Buffer.from(publicKey).toString("hex"),
566
625
  message_digest_sha256_hex: verified.message_digest_sha256_hex,
567
626
  ed25519_signature_hex: Buffer.from(signature).toString("hex"),
@@ -29,6 +29,16 @@ export const COMMAND_PATHS = [
29
29
  "dev trace",
30
30
  "dev loop",
31
31
  "dev up",
32
+ "shopify doctor",
33
+ "shopify link",
34
+ "shopify dev",
35
+ "shopify webhook trigger",
36
+ "shopify checkout smoke",
37
+ "shopify order show",
38
+ "shopify capture ready",
39
+ "shopify payments doctor",
40
+ "shopify payments smoke",
41
+ "shopify payments session show",
32
42
  "version",
33
43
  "diagnose",
34
44
  "config get",
@@ -196,7 +206,8 @@ export const COMMAND_EXAMPLES = {
196
206
  ],
197
207
  "doctor": [
198
208
  "paybond doctor",
199
- "paybond doctor --agent --format json"
209
+ "paybond doctor --agent --format json",
210
+ "paybond doctor --shopify"
200
211
  ],
201
212
  "dev": [
202
213
  "paybond dev smoke --offline",
@@ -216,6 +227,7 @@ export const COMMAND_EXAMPLES = {
216
227
  "dev loop": [
217
228
  "paybond dev loop",
218
229
  "paybond dev loop --offline",
230
+ "paybond dev loop --preset shopping --shopify",
219
231
  "paybond dev loop --format json"
220
232
  ],
221
233
  "dev up": [
@@ -223,6 +235,43 @@ export const COMMAND_EXAMPLES = {
223
235
  "paybond dev up --port 18089",
224
236
  "paybond dev up --down"
225
237
  ],
238
+ "shopify doctor": [
239
+ "paybond shopify doctor",
240
+ "paybond shopify doctor --format json"
241
+ ],
242
+ "shopify link": [
243
+ "paybond shopify link"
244
+ ],
245
+ "shopify dev": [
246
+ "paybond shopify dev",
247
+ "paybond shopify dev --tunnel https://example.ngrok-free.app"
248
+ ],
249
+ "shopify webhook trigger": [
250
+ "paybond shopify webhook trigger --topic orders/paid --gateway https://api.paybond.ai",
251
+ "paybond shopify webhook trigger --address http://127.0.0.1:8081/webhooks/sandbox/shopify --dry-run"
252
+ ],
253
+ "shopify checkout smoke": [
254
+ "paybond shopify checkout smoke --shop paybond-agent-commerce-dev.myshopify.com",
255
+ "paybond shopify checkout smoke --offline --format json"
256
+ ],
257
+ "shopify order show": [
258
+ "paybond shopify order show gid://shopify/Order/123 --shop paybond-agent-commerce-dev.myshopify.com"
259
+ ],
260
+ "shopify capture ready": [
261
+ "paybond shopify capture ready",
262
+ "paybond shopify capture ready --format json"
263
+ ],
264
+ "shopify payments doctor": [
265
+ "paybond shopify payments doctor",
266
+ "paybond shopify payments doctor --format json"
267
+ ],
268
+ "shopify payments smoke": [
269
+ "paybond shopify payments smoke --shop paybond-agent-commerce-dev.myshopify.com",
270
+ "paybond shopify payments smoke --offline --format json"
271
+ ],
272
+ "shopify payments session show": [
273
+ "paybond shopify payments session show paybond-smoke-payment-session --shop paybond-agent-commerce-dev.myshopify.com"
274
+ ],
226
275
  "version": [
227
276
  "paybond version",
228
277
  "paybond version --verbose --format json"