@paybond/kit 0.10.0 → 0.11.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 (346) hide show
  1. package/README.md +59 -15
  2. package/completion-presets/catalog.json +1187 -0
  3. package/completion-presets/catalog.sha256 +1 -0
  4. package/dev/trace-ui/dashboard.html +617 -0
  5. package/dist/agent/adapter.d.ts +51 -0
  6. package/dist/agent/adapter.js +66 -0
  7. package/dist/agent/attach-bundle.d.ts +37 -0
  8. package/dist/agent/attach-bundle.js +118 -0
  9. package/dist/agent/authorization-cache.d.ts +22 -0
  10. package/dist/agent/authorization-cache.js +36 -0
  11. package/dist/agent/deferred-tools.d.ts +11 -0
  12. package/dist/agent/deferred-tools.js +62 -0
  13. package/dist/agent/discover.d.ts +41 -0
  14. package/dist/agent/discover.js +147 -0
  15. package/dist/agent/evidence.d.ts +9 -0
  16. package/dist/agent/evidence.js +28 -0
  17. package/dist/agent/facade.d.ts +48 -0
  18. package/dist/agent/facade.js +112 -0
  19. package/dist/agent/gateway-trace-reporter.d.ts +28 -0
  20. package/dist/agent/gateway-trace-reporter.js +49 -0
  21. package/dist/agent/generic-runner.d.ts +14 -0
  22. package/dist/agent/generic-runner.js +49 -0
  23. package/dist/agent/generic-sandbox-demo.d.ts +36 -0
  24. package/dist/agent/generic-sandbox-demo.js +82 -0
  25. package/dist/agent/guarded-agent.d.ts +49 -0
  26. package/dist/agent/guarded-agent.js +100 -0
  27. package/dist/agent/index.d.ts +13 -0
  28. package/dist/agent/index.js +13 -0
  29. package/dist/agent/instrument.d.ts +156 -0
  30. package/dist/agent/instrument.js +442 -0
  31. package/dist/agent/interceptor.d.ts +24 -0
  32. package/dist/agent/interceptor.js +440 -0
  33. package/dist/agent/lazy-context-tools.d.ts +15 -0
  34. package/dist/agent/lazy-context-tools.js +81 -0
  35. package/dist/agent/registry-file.d.ts +39 -0
  36. package/dist/agent/registry-file.js +219 -0
  37. package/dist/agent/registry.d.ts +37 -0
  38. package/dist/agent/registry.js +128 -0
  39. package/dist/agent/run.d.ts +124 -0
  40. package/dist/agent/run.js +301 -0
  41. package/dist/agent/types.d.ts +318 -0
  42. package/dist/agent/types.js +42 -0
  43. package/dist/agent-recognition.d.ts +72 -0
  44. package/dist/agent-recognition.js +165 -0
  45. package/dist/bincode-wire.d.ts +18 -0
  46. package/dist/bincode-wire.js +93 -0
  47. package/dist/claude-agents/config.d.ts +21 -0
  48. package/dist/claude-agents/config.js +145 -0
  49. package/dist/claude-agents/index.d.ts +2 -0
  50. package/dist/claude-agents/index.js +2 -0
  51. package/dist/claude-agents/sandbox-demo.d.ts +30 -0
  52. package/dist/claude-agents/sandbox-demo.js +91 -0
  53. package/dist/cli/agent/demo-loaders.d.ts +4 -0
  54. package/dist/cli/agent/demo-loaders.js +66 -0
  55. package/dist/cli/agent/env-quote.d.ts +1 -0
  56. package/dist/cli/agent/env-quote.js +6 -0
  57. package/dist/cli/agent/env-write.d.ts +8 -0
  58. package/dist/cli/agent/env-write.js +47 -0
  59. package/dist/cli/agent/paybond.d.ts +16 -0
  60. package/dist/cli/agent/paybond.js +55 -0
  61. package/dist/cli/agent/policy-file.d.ts +29 -0
  62. package/dist/cli/agent/policy-file.js +61 -0
  63. package/dist/cli/agent/production-evidence.d.ts +24 -0
  64. package/dist/cli/agent/production-evidence.js +98 -0
  65. package/dist/cli/agent/run-store.d.ts +30 -0
  66. package/dist/cli/agent/run-store.js +42 -0
  67. package/dist/cli/agent/run-trace-store.d.ts +39 -0
  68. package/dist/cli/agent/run-trace-store.js +143 -0
  69. package/dist/cli/agent-run-trace-table.d.ts +9 -0
  70. package/dist/cli/agent-run-trace-table.js +24 -0
  71. package/dist/cli/agent-sandbox-smoke-checklist.d.ts +9 -0
  72. package/dist/cli/agent-sandbox-smoke-checklist.js +50 -0
  73. package/dist/cli/command-spec.d.ts +1 -0
  74. package/dist/cli/command-spec.js +286 -5
  75. package/dist/cli/commands/agent.d.ts +16 -0
  76. package/dist/cli/commands/agent.js +1136 -0
  77. package/dist/cli/commands/dev.d.ts +7 -0
  78. package/dist/cli/commands/dev.js +348 -0
  79. package/dist/cli/commands/discovery.js +3 -3
  80. package/dist/cli/commands/policy.d.ts +13 -0
  81. package/dist/cli/commands/policy.js +769 -0
  82. package/dist/cli/commands/setup.d.ts +3 -0
  83. package/dist/cli/commands/setup.js +124 -8
  84. package/dist/cli/commands/workflows.js +9 -4
  85. package/dist/cli/config.d.ts +2 -0
  86. package/dist/cli/config.js +4 -2
  87. package/dist/cli/context.js +2 -1
  88. package/dist/cli/credentials.js +2 -2
  89. package/dist/cli/doctor-agent-middleware.d.ts +5 -0
  90. package/dist/cli/doctor-agent-middleware.js +49 -0
  91. package/dist/cli/globals.d.ts +1 -0
  92. package/dist/cli/globals.js +11 -1
  93. package/dist/cli/help.d.ts +1 -1
  94. package/dist/cli/help.js +35 -3
  95. package/dist/cli/mcp-install.js +2 -2
  96. package/dist/cli/mcp-policy.d.ts +3 -0
  97. package/dist/cli/mcp-policy.js +19 -13
  98. package/dist/cli/mcp-verify-config.js +9 -11
  99. package/dist/cli/redact.js +29 -8
  100. package/dist/cli/router.js +105 -2
  101. package/dist/cli/smoke-deep-links.d.ts +15 -0
  102. package/dist/cli/smoke-deep-links.js +63 -0
  103. package/dist/cli/telemetry.d.ts +17 -0
  104. package/dist/cli/telemetry.js +94 -0
  105. package/dist/completion-catalog-digest.d.ts +2 -0
  106. package/dist/completion-catalog-digest.js +2 -0
  107. package/dist/completion-catalog-integrity.d.ts +2 -0
  108. package/dist/completion-catalog-integrity.js +17 -0
  109. package/dist/completion-catalog.d.ts +49 -0
  110. package/dist/completion-catalog.js +62 -0
  111. package/dist/completion-contract-digest.d.ts +37 -0
  112. package/dist/completion-contract-digest.js +73 -0
  113. package/dist/completion-forbidden-fields.d.ts +5 -0
  114. package/dist/completion-forbidden-fields.js +26 -0
  115. package/dist/completion-init.d.ts +8 -0
  116. package/dist/completion-init.js +334 -0
  117. package/dist/completion-resolve.d.ts +21 -0
  118. package/dist/completion-resolve.js +86 -0
  119. package/dist/completion-validate-evidence.d.ts +24 -0
  120. package/dist/completion-validate-evidence.js +145 -0
  121. package/dist/dev/offline-gateway.d.ts +24 -0
  122. package/dist/dev/offline-gateway.js +102 -0
  123. package/dist/dev/trace-buffer.d.ts +61 -0
  124. package/dist/dev/trace-buffer.js +330 -0
  125. package/dist/dev/trace-security-headers.d.ts +11 -0
  126. package/dist/dev/trace-security-headers.js +16 -0
  127. package/dist/dev/trace-server.d.ts +8 -0
  128. package/dist/dev/trace-server.js +38 -0
  129. package/dist/dev/trace-ui.d.ts +4 -0
  130. package/dist/dev/trace-ui.js +25 -0
  131. package/dist/dev/wiremock-up.d.ts +15 -0
  132. package/dist/dev/wiremock-up.js +118 -0
  133. package/dist/doctor-completion.d.ts +17 -0
  134. package/dist/doctor-completion.js +428 -0
  135. package/dist/gateway-url.d.ts +7 -0
  136. package/dist/gateway-url.js +69 -0
  137. package/dist/index.d.ts +119 -2
  138. package/dist/index.js +267 -6
  139. package/dist/init.js +374 -57
  140. package/dist/langgraph/awrap-tool-call.d.ts +25 -0
  141. package/dist/langgraph/awrap-tool-call.js +81 -0
  142. package/dist/langgraph/config.d.ts +13 -0
  143. package/dist/langgraph/config.js +11 -0
  144. package/dist/langgraph/index.d.ts +4 -0
  145. package/dist/langgraph/index.js +4 -0
  146. package/dist/langgraph/sandbox-demo.d.ts +40 -0
  147. package/dist/langgraph/sandbox-demo.js +96 -0
  148. package/dist/langgraph/tool-node.d.ts +10 -0
  149. package/dist/langgraph/tool-node.js +38 -0
  150. package/dist/login.js +7 -0
  151. package/dist/mcp/index.d.ts +1 -0
  152. package/dist/mcp/index.js +1 -0
  153. package/dist/mcp/tool-surface.d.ts +25 -0
  154. package/dist/mcp/tool-surface.js +17 -0
  155. package/dist/mcp-capability-token-cache.d.ts +24 -0
  156. package/dist/mcp-capability-token-cache.js +101 -0
  157. package/dist/mcp-evidence-policy.d.ts +48 -0
  158. package/dist/mcp-evidence-policy.js +117 -0
  159. package/dist/mcp-policy-reload.d.ts +79 -0
  160. package/dist/mcp-policy-reload.js +200 -0
  161. package/dist/mcp-sep2828-evidence.d.ts +36 -0
  162. package/dist/mcp-sep2828-evidence.js +65 -0
  163. package/dist/mcp-server.d.ts +6 -0
  164. package/dist/mcp-server.js +224 -44
  165. package/dist/openai-agents/index.d.ts +40 -0
  166. package/dist/openai-agents/index.js +151 -0
  167. package/dist/openai-agents/sandbox-demo.d.ts +34 -0
  168. package/dist/openai-agents/sandbox-demo.js +118 -0
  169. package/dist/payee-evidence.js +2 -29
  170. package/dist/policy/catalog.d.ts +31 -0
  171. package/dist/policy/catalog.js +48 -0
  172. package/dist/policy/compose-utils.d.ts +3 -0
  173. package/dist/policy/compose-utils.js +4 -0
  174. package/dist/policy/compose.d.ts +20 -0
  175. package/dist/policy/compose.js +240 -0
  176. package/dist/policy/digest.d.ts +7 -0
  177. package/dist/policy/digest.js +75 -0
  178. package/dist/policy/domain.d.ts +15 -0
  179. package/dist/policy/domain.js +28 -0
  180. package/dist/policy/guardrail-spec.d.ts +17 -0
  181. package/dist/policy/guardrail-spec.js +140 -0
  182. package/dist/policy/guardrails.d.ts +48 -0
  183. package/dist/policy/guardrails.js +72 -0
  184. package/dist/policy/index.d.ts +21 -0
  185. package/dist/policy/index.js +21 -0
  186. package/dist/policy/init.d.ts +102 -0
  187. package/dist/policy/init.js +351 -0
  188. package/dist/policy/intent-spec.d.ts +52 -0
  189. package/dist/policy/intent-spec.js +176 -0
  190. package/dist/policy/json-path.d.ts +4 -0
  191. package/dist/policy/json-path.js +23 -0
  192. package/dist/policy/layers-io.d.ts +7 -0
  193. package/dist/policy/layers-io.js +28 -0
  194. package/dist/policy/load-effective.d.ts +22 -0
  195. package/dist/policy/load-effective.js +77 -0
  196. package/dist/policy/load.d.ts +85 -0
  197. package/dist/policy/load.js +164 -0
  198. package/dist/policy/merge.d.ts +29 -0
  199. package/dist/policy/merge.js +297 -0
  200. package/dist/policy/parse-text.d.ts +2 -0
  201. package/dist/policy/parse-text.js +126 -0
  202. package/dist/policy/policy-api.d.ts +45 -0
  203. package/dist/policy/policy-api.js +61 -0
  204. package/dist/policy/presets.d.ts +19 -0
  205. package/dist/policy/presets.js +66 -0
  206. package/dist/policy/registry.d.ts +7 -0
  207. package/dist/policy/registry.js +33 -0
  208. package/dist/policy/reload.d.ts +86 -0
  209. package/dist/policy/reload.js +233 -0
  210. package/dist/policy/render-yaml.d.ts +3 -0
  211. package/dist/policy/render-yaml.js +69 -0
  212. package/dist/policy/sandbox-bootstrap.d.ts +19 -0
  213. package/dist/policy/sandbox-bootstrap.js +66 -0
  214. package/dist/policy/schema.d.ts +204 -0
  215. package/dist/policy/schema.js +255 -0
  216. package/dist/policy/snapshot.d.ts +33 -0
  217. package/dist/policy/snapshot.js +23 -0
  218. package/dist/policy/validate-remote.d.ts +43 -0
  219. package/dist/policy/validate-remote.js +104 -0
  220. package/dist/policy/validate.d.ts +36 -0
  221. package/dist/policy/validate.js +150 -0
  222. package/dist/policy/watcher.d.ts +29 -0
  223. package/dist/policy/watcher.js +112 -0
  224. package/dist/principal-intent.d.ts +52 -0
  225. package/dist/principal-intent.js +193 -37
  226. package/dist/project-init.d.ts +34 -0
  227. package/dist/project-init.js +898 -0
  228. package/dist/sep2828-signature.d.ts +10 -0
  229. package/dist/sep2828-signature.js +134 -0
  230. package/dist/solutions/api.d.ts +22 -0
  231. package/dist/solutions/api.js +40 -0
  232. package/dist/solutions/catalog.d.ts +34 -0
  233. package/dist/solutions/catalog.js +129 -0
  234. package/dist/solutions/index.d.ts +2 -0
  235. package/dist/solutions/index.js +2 -0
  236. package/dist/template-init.d.ts +54 -0
  237. package/dist/template-init.js +203 -0
  238. package/dist/vercel-ai/config.d.ts +15 -0
  239. package/dist/vercel-ai/config.js +13 -0
  240. package/dist/vercel-ai/index.d.ts +4 -0
  241. package/dist/vercel-ai/index.js +4 -0
  242. package/dist/vercel-ai/sandbox-demo.d.ts +44 -0
  243. package/dist/vercel-ai/sandbox-demo.js +153 -0
  244. package/dist/vercel-ai/tool-approval.d.ts +16 -0
  245. package/dist/vercel-ai/tool-approval.js +41 -0
  246. package/dist/vercel-ai/wrap-tools.d.ts +9 -0
  247. package/dist/vercel-ai/wrap-tools.js +40 -0
  248. package/dist/x402-receipt-evidence.d.ts +29 -0
  249. package/dist/x402-receipt-evidence.js +97 -0
  250. package/dist/x402-receipt-signature.d.ts +12 -0
  251. package/dist/x402-receipt-signature.js +211 -0
  252. package/package.json +75 -3
  253. package/solutions/aws.json +17 -0
  254. package/solutions/saas.json +17 -0
  255. package/solutions/shopping.json +17 -0
  256. package/solutions/travel.json +18 -0
  257. package/templates/manifest.json +169 -0
  258. package/templates/openai-shopping-agent/.env.example +3 -0
  259. package/templates/openai-shopping-agent/.github/workflows/smoke.yml +20 -0
  260. package/templates/openai-shopping-agent/LICENSE +201 -0
  261. package/templates/openai-shopping-agent/README.md +29 -0
  262. package/templates/openai-shopping-agent/package-lock.json +1525 -0
  263. package/templates/openai-shopping-agent/package.json +22 -0
  264. package/templates/openai-shopping-agent/paybond.policy.yaml +22 -0
  265. package/templates/openai-shopping-agent/src/index.ts +22 -0
  266. package/templates/openai-shopping-agent/src/paybond.config.ts +51 -0
  267. package/templates/openai-shopping-agent/tsconfig.json +13 -0
  268. package/templates/paybond-aws-operator/.env.example +3 -0
  269. package/templates/paybond-aws-operator/.github/workflows/smoke.yml +20 -0
  270. package/templates/paybond-aws-operator/LICENSE +201 -0
  271. package/templates/paybond-aws-operator/README.md +29 -0
  272. package/templates/paybond-aws-operator/package-lock.json +151 -0
  273. package/templates/paybond-aws-operator/package.json +20 -0
  274. package/templates/paybond-aws-operator/paybond.policy.yaml +22 -0
  275. package/templates/paybond-aws-operator/src/index.ts +54 -0
  276. package/templates/paybond-aws-operator/src/paybond.config.ts +51 -0
  277. package/templates/paybond-aws-operator/tsconfig.json +13 -0
  278. package/templates/paybond-claude-agents-demo/.env.example +3 -0
  279. package/templates/paybond-claude-agents-demo/.github/workflows/smoke.yml +20 -0
  280. package/templates/paybond-claude-agents-demo/LICENSE +201 -0
  281. package/templates/paybond-claude-agents-demo/README.md +29 -0
  282. package/templates/paybond-claude-agents-demo/package-lock.json +1489 -0
  283. package/templates/paybond-claude-agents-demo/package.json +22 -0
  284. package/templates/paybond-claude-agents-demo/paybond.policy.yaml +22 -0
  285. package/templates/paybond-claude-agents-demo/src/index.ts +22 -0
  286. package/templates/paybond-claude-agents-demo/src/paybond.config.ts +51 -0
  287. package/templates/paybond-claude-agents-demo/tsconfig.json +13 -0
  288. package/templates/paybond-invoice-agent/.env.example +3 -0
  289. package/templates/paybond-invoice-agent/.github/workflows/smoke.yml +19 -0
  290. package/templates/paybond-invoice-agent/LICENSE +201 -0
  291. package/templates/paybond-invoice-agent/README.md +29 -0
  292. package/templates/paybond-invoice-agent/app.py +27 -0
  293. package/templates/paybond-invoice-agent/package.json +6 -0
  294. package/templates/paybond-invoice-agent/paybond.policy.yaml +22 -0
  295. package/templates/paybond-invoice-agent/paybond_config.py +45 -0
  296. package/templates/paybond-invoice-agent/requirements.txt +2 -0
  297. package/templates/paybond-mcp-coding-agent/.env.example +3 -0
  298. package/templates/paybond-mcp-coding-agent/.github/workflows/smoke.yml +20 -0
  299. package/templates/paybond-mcp-coding-agent/LICENSE +201 -0
  300. package/templates/paybond-mcp-coding-agent/README.md +39 -0
  301. package/templates/paybond-mcp-coding-agent/package-lock.json +151 -0
  302. package/templates/paybond-mcp-coding-agent/package.json +20 -0
  303. package/templates/paybond-mcp-coding-agent/paybond.policy.yaml +25 -0
  304. package/templates/paybond-mcp-coding-agent/src/index.ts +40 -0
  305. package/templates/paybond-mcp-coding-agent/src/paybond.config.ts +51 -0
  306. package/templates/paybond-mcp-coding-agent/tsconfig.json +13 -0
  307. package/templates/paybond-openai-agents-demo/.env.example +3 -0
  308. package/templates/paybond-openai-agents-demo/.github/workflows/smoke.yml +20 -0
  309. package/templates/paybond-openai-agents-demo/LICENSE +201 -0
  310. package/templates/paybond-openai-agents-demo/README.md +29 -0
  311. package/templates/paybond-openai-agents-demo/package-lock.json +1525 -0
  312. package/templates/paybond-openai-agents-demo/package.json +22 -0
  313. package/templates/paybond-openai-agents-demo/paybond.policy.yaml +22 -0
  314. package/templates/paybond-openai-agents-demo/src/index.ts +22 -0
  315. package/templates/paybond-openai-agents-demo/src/paybond.config.ts +51 -0
  316. package/templates/paybond-openai-agents-demo/tsconfig.json +13 -0
  317. package/templates/paybond-procurement-agent/.env.example +3 -0
  318. package/templates/paybond-procurement-agent/.github/workflows/smoke.yml +20 -0
  319. package/templates/paybond-procurement-agent/LICENSE +201 -0
  320. package/templates/paybond-procurement-agent/README.md +29 -0
  321. package/templates/paybond-procurement-agent/package-lock.json +151 -0
  322. package/templates/paybond-procurement-agent/package.json +20 -0
  323. package/templates/paybond-procurement-agent/paybond.policy.yaml +25 -0
  324. package/templates/paybond-procurement-agent/src/index.ts +54 -0
  325. package/templates/paybond-procurement-agent/src/paybond.config.ts +51 -0
  326. package/templates/paybond-procurement-agent/tsconfig.json +13 -0
  327. package/templates/paybond-travel-agent/.env.example +3 -0
  328. package/templates/paybond-travel-agent/.github/workflows/smoke.yml +20 -0
  329. package/templates/paybond-travel-agent/LICENSE +201 -0
  330. package/templates/paybond-travel-agent/README.md +29 -0
  331. package/templates/paybond-travel-agent/package-lock.json +444 -0
  332. package/templates/paybond-travel-agent/package.json +23 -0
  333. package/templates/paybond-travel-agent/paybond.policy.yaml +22 -0
  334. package/templates/paybond-travel-agent/src/index.ts +22 -0
  335. package/templates/paybond-travel-agent/src/paybond.config.ts +51 -0
  336. package/templates/paybond-travel-agent/tsconfig.json +13 -0
  337. package/templates/paybond-vercel-shopping-agent/.env.example +3 -0
  338. package/templates/paybond-vercel-shopping-agent/.github/workflows/smoke.yml +20 -0
  339. package/templates/paybond-vercel-shopping-agent/LICENSE +201 -0
  340. package/templates/paybond-vercel-shopping-agent/README.md +29 -0
  341. package/templates/paybond-vercel-shopping-agent/package-lock.json +265 -0
  342. package/templates/paybond-vercel-shopping-agent/package.json +22 -0
  343. package/templates/paybond-vercel-shopping-agent/paybond.policy.yaml +22 -0
  344. package/templates/paybond-vercel-shopping-agent/src/index.ts +22 -0
  345. package/templates/paybond-vercel-shopping-agent/src/paybond.config.ts +51 -0
  346. package/templates/paybond-vercel-shopping-agent/tsconfig.json +13 -0
@@ -0,0 +1,4 @@
1
+ export { createPaybondVercelAgentConfig, } from "./config.js";
2
+ export { mapPaybondDecisionToVercelToolApproval, paybondVercelToolApproval, } from "./tool-approval.js";
3
+ export { paybondVercelWrapTools } from "./wrap-tools.js";
4
+ export { runVercelAiSandboxDemo, } from "./sandbox-demo.js";
@@ -0,0 +1,44 @@
1
+ import type { Paybond } from "../index.js";
2
+ export type RunVercelAiSandboxDemoInput = {
3
+ paybond: Paybond;
4
+ operation?: string;
5
+ requestedSpendCents?: number;
6
+ evidencePreset?: string;
7
+ toolCallId?: string;
8
+ };
9
+ export type RunVercelAiSandboxDemoResult = {
10
+ bind: {
11
+ run_id: string;
12
+ tenant_id: string;
13
+ intent_id: string;
14
+ capability_token: string;
15
+ operation: string;
16
+ sandbox_lifecycle_status?: string;
17
+ };
18
+ tool_approval: string | {
19
+ type: string;
20
+ reason?: string;
21
+ };
22
+ generate_text: {
23
+ text: string;
24
+ step_count: number;
25
+ tool_calls: number;
26
+ };
27
+ execute: {
28
+ tool_result?: unknown;
29
+ authorization?: {
30
+ audit_id?: string;
31
+ decision_id?: string;
32
+ };
33
+ evidence?: {
34
+ submitted: boolean;
35
+ sandbox_lifecycle_status?: string;
36
+ predicate_passed?: boolean | null;
37
+ };
38
+ };
39
+ };
40
+ /**
41
+ * No-LLM Vercel AI SDK sandbox demo: `toolApproval` + wrapped `execute` + auto-evidence.
42
+ * Uses `MockLanguageModelV4` — no provider API key required.
43
+ */
44
+ export declare function runVercelAiSandboxDemo(input: RunVercelAiSandboxDemoInput): Promise<RunVercelAiSandboxDemoResult>;
@@ -0,0 +1,153 @@
1
+ import { generateText, jsonSchema, stepCountIs, tool } from "ai";
2
+ import { MockLanguageModelV4 } from "ai/test";
3
+ import { createPaybondToolRegistry } from "../agent/registry.js";
4
+ import { paybondVercelToolApproval } from "./tool-approval.js";
5
+ import { paybondVercelWrapTools } from "./wrap-tools.js";
6
+ function mockUsage() {
7
+ return {
8
+ inputTokens: { total: 3, noCache: 3, cacheRead: undefined, cacheWrite: undefined },
9
+ outputTokens: { total: 10, text: 10, reasoning: undefined },
10
+ };
11
+ }
12
+ async function executePaidTool(args) {
13
+ return { status: "completed", cost_cents: args.estimatedPriceCents };
14
+ }
15
+ async function searchWeb(args) {
16
+ return { hits: [{ title: args.query, url: "https://example.com" }] };
17
+ }
18
+ /**
19
+ * No-LLM Vercel AI SDK sandbox demo: `toolApproval` + wrapped `execute` + auto-evidence.
20
+ * Uses `MockLanguageModelV4` — no provider API key required.
21
+ */
22
+ export async function runVercelAiSandboxDemo(input) {
23
+ const operation = (input.operation ?? "paid-tool").trim();
24
+ const requestedSpendCents = input.requestedSpendCents ?? 100;
25
+ const evidencePreset = (input.evidencePreset ?? "cost_and_completion").trim();
26
+ const toolCallId = (input.toolCallId ?? "vercel-demo-1").trim();
27
+ const registry = createPaybondToolRegistry({
28
+ defaultDeny: true,
29
+ sideEffecting: {
30
+ [operation]: {
31
+ operation,
32
+ evidencePreset,
33
+ spendCents: requestedSpendCents,
34
+ evidenceMapper: (result) => {
35
+ const payload = result;
36
+ return {
37
+ status: payload.status,
38
+ cost_cents: payload.cost_cents,
39
+ };
40
+ },
41
+ },
42
+ },
43
+ });
44
+ const run = await input.paybond.agentRun.bind({
45
+ bootstrap: {
46
+ kind: "sandbox",
47
+ operation,
48
+ requestedSpendCents,
49
+ completionPreset: evidencePreset,
50
+ },
51
+ registry,
52
+ });
53
+ const rawTools = {
54
+ [operation]: tool({
55
+ description: `Paid operation ${operation}`,
56
+ inputSchema: jsonSchema({
57
+ type: "object",
58
+ properties: {
59
+ estimatedPriceCents: { type: "integer", minimum: 0 },
60
+ },
61
+ required: ["estimatedPriceCents"],
62
+ additionalProperties: false,
63
+ }),
64
+ execute: async (args) => executePaidTool(args),
65
+ }),
66
+ "search.web": tool({
67
+ description: "Read-only web search",
68
+ inputSchema: jsonSchema({
69
+ type: "object",
70
+ properties: { query: { type: "string" } },
71
+ required: ["query"],
72
+ additionalProperties: false,
73
+ }),
74
+ execute: async (args) => searchWeb(args),
75
+ }),
76
+ };
77
+ const tools = paybondVercelWrapTools(run, rawTools);
78
+ const toolApproval = paybondVercelToolApproval(run);
79
+ const toolInput = { estimatedPriceCents: requestedSpendCents };
80
+ const approvalStatus = await toolApproval({
81
+ toolCall: {
82
+ type: "tool-call",
83
+ toolName: operation,
84
+ toolCallId,
85
+ input: toolInput,
86
+ },
87
+ tools,
88
+ toolsContext: {},
89
+ runtimeContext: undefined,
90
+ messages: [],
91
+ });
92
+ let stepCount = 0;
93
+ const generated = await generateText({
94
+ model: new MockLanguageModelV4({
95
+ doGenerate: [
96
+ {
97
+ content: [
98
+ {
99
+ type: "tool-call",
100
+ toolCallId,
101
+ toolName: operation,
102
+ input: JSON.stringify(toolInput),
103
+ },
104
+ ],
105
+ finishReason: { unified: "tool-calls", raw: "tool_calls" },
106
+ usage: mockUsage(),
107
+ warnings: [],
108
+ },
109
+ {
110
+ content: [{ type: "text", text: "paid tool completed" }],
111
+ finishReason: { unified: "stop", raw: "stop" },
112
+ usage: mockUsage(),
113
+ warnings: [],
114
+ },
115
+ ],
116
+ }),
117
+ tools,
118
+ toolApproval: toolApproval,
119
+ stopWhen: stepCountIs(5),
120
+ prompt: "run the paid tool",
121
+ });
122
+ stepCount = generated.steps.length;
123
+ const paidToolResult = generated.toolResults.find((entry) => entry.toolName === operation);
124
+ return {
125
+ bind: {
126
+ run_id: run.runId,
127
+ tenant_id: run.tenantId,
128
+ intent_id: run.intentId,
129
+ capability_token: run.capabilityToken,
130
+ operation,
131
+ sandbox_lifecycle_status: run.binding.sandbox?.sandboxLifecycleStatus,
132
+ },
133
+ tool_approval: approvalStatus === undefined
134
+ ? "not-applicable"
135
+ : typeof approvalStatus === "string"
136
+ ? approvalStatus
137
+ : { type: approvalStatus.type },
138
+ generate_text: {
139
+ text: generated.text,
140
+ step_count: stepCount,
141
+ tool_calls: generated.toolCalls.length,
142
+ },
143
+ execute: {
144
+ tool_result: paidToolResult?.output,
145
+ evidence: paidToolResult
146
+ ? {
147
+ submitted: true,
148
+ sandbox_lifecycle_status: run.binding.sandbox?.sandboxLifecycleStatus,
149
+ }
150
+ : undefined,
151
+ },
152
+ };
153
+ }
@@ -0,0 +1,16 @@
1
+ import type { GenericToolApprovalFunction, ToolApprovalStatus, ToolSet } from "ai";
2
+ import type { PaybondAgentRun } from "../agent/run.js";
3
+ import type { PaybondToolInputGuardDecision } from "../agent/types.js";
4
+ /** Map a framework-neutral Paybond decision to Vercel AI SDK tool approval status. */
5
+ export declare function mapPaybondDecisionToVercelToolApproval(decision: PaybondToolInputGuardDecision): ToolApprovalStatus;
6
+ export type PaybondVercelToolApprovalOptions = {
7
+ /** Override Paybond → Vercel approval status mapping (for example custom HITL labels). */
8
+ mapDecision?: (decision: PaybondToolInputGuardDecision) => ToolApprovalStatus;
9
+ };
10
+ /**
11
+ * Centralized `toolApproval` bridge for Vercel AI SDK `generateText` / `streamText`.
12
+ *
13
+ * Non-side-effecting tools are auto-approved without Harbor verify. Side-effecting
14
+ * registered tools run the Paybond interceptor pre-check; denials propagate as tool errors.
15
+ */
16
+ export declare function paybondVercelToolApproval<TOOLS extends ToolSet = ToolSet>(run: PaybondAgentRun, options?: PaybondVercelToolApprovalOptions): GenericToolApprovalFunction<TOOLS, never, never>;
@@ -0,0 +1,41 @@
1
+ import { createToolInputGuardAdapter } from "../agent/adapter.js";
2
+ /** Map a framework-neutral Paybond decision to Vercel AI SDK tool approval status. */
3
+ export function mapPaybondDecisionToVercelToolApproval(decision) {
4
+ if (decision.kind === "allow") {
5
+ return "approved";
6
+ }
7
+ if (decision.kind === "approval_required") {
8
+ return "user-approval";
9
+ }
10
+ return { type: "denied", reason: decision.message };
11
+ }
12
+ /**
13
+ * Centralized `toolApproval` bridge for Vercel AI SDK `generateText` / `streamText`.
14
+ *
15
+ * Non-side-effecting tools are auto-approved without Harbor verify. Side-effecting
16
+ * registered tools run the Paybond interceptor pre-check; denials propagate as tool errors.
17
+ */
18
+ export function paybondVercelToolApproval(run, options) {
19
+ const guard = createToolInputGuardAdapter(run);
20
+ const mapDecision = options?.mapDecision ?? mapPaybondDecisionToVercelToolApproval;
21
+ const approve = async ({ toolCall, }) => {
22
+ const toolName = toolCall.toolName;
23
+ const toolCallId = toolCall.toolCallId;
24
+ if (!run.registry.isSideEffecting(toolName)) {
25
+ const resolution = run.registry.resolveTool(toolName, {
26
+ allowedTools: run.allowedTools,
27
+ });
28
+ if (resolution.kind === "passthrough") {
29
+ return "approved";
30
+ }
31
+ }
32
+ const decision = await guard.evaluate({
33
+ toolName,
34
+ toolCallId,
35
+ arguments: toolCall.input,
36
+ approvalToken: run.getApprovalToken(toolCallId),
37
+ });
38
+ return mapDecision(decision);
39
+ };
40
+ return approve;
41
+ }
@@ -0,0 +1,9 @@
1
+ import type { ToolSet } from "ai";
2
+ import type { PaybondAgentRun } from "../agent/run.js";
3
+ /**
4
+ * Wrap side-effecting Vercel AI SDK tools with Paybond `wrapExecute` so Harbor
5
+ * verify, spend finalize, and auto-evidence run after successful execution.
6
+ *
7
+ * Read-only and provider-executed tools pass through unchanged.
8
+ */
9
+ export declare function paybondVercelWrapTools<TOOLS extends ToolSet>(run: PaybondAgentRun, tools: TOOLS): TOOLS;
@@ -0,0 +1,40 @@
1
+ function isClientExecutedTool(tool) {
2
+ if (typeof tool !== "object" || tool === null) {
3
+ return false;
4
+ }
5
+ const record = tool;
6
+ if (record.isProviderExecuted === true) {
7
+ return false;
8
+ }
9
+ return typeof record.execute === "function";
10
+ }
11
+ /**
12
+ * Wrap side-effecting Vercel AI SDK tools with Paybond `wrapExecute` so Harbor
13
+ * verify, spend finalize, and auto-evidence run after successful execution.
14
+ *
15
+ * Read-only and provider-executed tools pass through unchanged.
16
+ */
17
+ export function paybondVercelWrapTools(run, tools) {
18
+ const wrapped = {};
19
+ for (const [toolName, tool] of Object.entries(tools)) {
20
+ if (!isClientExecutedTool(tool) || !run.registry.isSideEffecting(toolName)) {
21
+ wrapped[toolName] = tool;
22
+ continue;
23
+ }
24
+ const originalExecute = tool.execute.bind(tool);
25
+ wrapped[toolName] = {
26
+ ...tool,
27
+ execute: async (input, options) => {
28
+ const result = await run.interceptor.wrapExecute({
29
+ toolName,
30
+ toolCallId: options.toolCallId,
31
+ arguments: input,
32
+ approvalToken: run.getApprovalToken(options.toolCallId),
33
+ execute: () => originalExecute(input, options),
34
+ });
35
+ return result.toolResult;
36
+ },
37
+ };
38
+ }
39
+ return wrapped;
40
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Maps x402 Signed Offer & Receipt extension payloads into artifact_attested evidence.
3
+ *
4
+ * Digests JCS-canonical receipt bytes (resourceUrl, payer, network, issuedAt, optional transaction)
5
+ * into artifact_blake3_hex. Does not import Coinbase authorization_succeeded funding webhooks.
6
+ */
7
+ export declare const X402_RECEIPT_MAPPER_VERSION = "x402_receipt_v1";
8
+ export type X402ReceiptPayloadV1 = {
9
+ resourceUrl: string;
10
+ payer: string;
11
+ network: string;
12
+ issuedAt: number;
13
+ transaction?: string;
14
+ };
15
+ export type ArtifactAttestedEvidence = {
16
+ artifact_blake3_hex: string[];
17
+ operation: string;
18
+ vendor_ref_id: string;
19
+ };
20
+ /** Rejects Coinbase funding webhook shapes — those are not tool-completion evidence. */
21
+ export declare function assertNotX402FundingArtifact(input: Record<string, unknown>): void;
22
+ /** Normalizes wire fields into the v1 digest payload (camelCase, optional transaction only when set). */
23
+ export declare function buildX402ReceiptDigestPayload(raw: Record<string, unknown>): X402ReceiptPayloadV1;
24
+ /** BLAKE3 hex digest of JCS-canonical x402 receipt payload bytes. */
25
+ export declare function x402ReceiptPayloadDigestHex(payload: X402ReceiptPayloadV1): string;
26
+ /**
27
+ * Converts an x402 signed receipt artifact or payload into artifact_attested evidence fields.
28
+ */
29
+ export declare function mapX402ReceiptToArtifactAttestedEvidence(receiptInput: Record<string, unknown>): ArtifactAttestedEvidence;
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Maps x402 Signed Offer & Receipt extension payloads into artifact_attested evidence.
3
+ *
4
+ * Digests JCS-canonical receipt bytes (resourceUrl, payer, network, issuedAt, optional transaction)
5
+ * into artifact_blake3_hex. Does not import Coinbase authorization_succeeded funding webhooks.
6
+ */
7
+ import { jsonValueDigest } from "./json-digest.js";
8
+ import { extractSignedX402Receipt, verifySignedX402Receipt } from "./x402-receipt-signature.js";
9
+ export const X402_RECEIPT_MAPPER_VERSION = "x402_receipt_v1";
10
+ const FUNDING_EVIDENCE_FIELDS = [
11
+ "payment_session_id",
12
+ "authorization_id",
13
+ "capture_id",
14
+ "void_id",
15
+ "x402_payment_session_id",
16
+ "onchain_transaction_hashes",
17
+ ];
18
+ function readString(record, ...keys) {
19
+ for (const key of keys) {
20
+ const value = record[key];
21
+ if (typeof value === "string" && value.length > 0) {
22
+ return value;
23
+ }
24
+ }
25
+ return undefined;
26
+ }
27
+ function readNumber(record, ...keys) {
28
+ for (const key of keys) {
29
+ const value = record[key];
30
+ if (typeof value === "number" && Number.isFinite(value)) {
31
+ return value;
32
+ }
33
+ }
34
+ return undefined;
35
+ }
36
+ function digestToHex(bytes) {
37
+ return Buffer.from(bytes).toString("hex");
38
+ }
39
+ /** Rejects Coinbase funding webhook shapes — those are not tool-completion evidence. */
40
+ export function assertNotX402FundingArtifact(input) {
41
+ const eventType = readString(input, "event_type", "eventType", "type");
42
+ if (eventType === "authorization_succeeded") {
43
+ throw new Error("authorization_succeeded webhooks are funding signals, not x402 delivery receipt evidence");
44
+ }
45
+ for (const field of FUNDING_EVIDENCE_FIELDS) {
46
+ if (Object.prototype.hasOwnProperty.call(input, field)) {
47
+ throw new Error(`funding field ${field} must not be submitted as tool-completion evidence`);
48
+ }
49
+ }
50
+ }
51
+ function hasReceiptShape(record) {
52
+ return (readString(record, "resourceUrl", "resource_url") !== undefined &&
53
+ readString(record, "payer") !== undefined &&
54
+ readString(record, "network") !== undefined &&
55
+ readNumber(record, "issuedAt", "issued_at") !== undefined);
56
+ }
57
+ function unwrapReceiptRecord(input) {
58
+ assertNotX402FundingArtifact(input);
59
+ const signed = extractSignedX402Receipt(input);
60
+ const verifiedPayload = verifySignedX402Receipt(signed);
61
+ if (hasReceiptShape(verifiedPayload)) {
62
+ return verifiedPayload;
63
+ }
64
+ throw new Error("x402 receipt payload missing required fields (resourceUrl, payer, network, issuedAt)");
65
+ }
66
+ /** Normalizes wire fields into the v1 digest payload (camelCase, optional transaction only when set). */
67
+ export function buildX402ReceiptDigestPayload(raw) {
68
+ const resourceUrl = readString(raw, "resourceUrl", "resource_url");
69
+ const payer = readString(raw, "payer");
70
+ const network = readString(raw, "network");
71
+ const issuedAt = readNumber(raw, "issuedAt", "issued_at");
72
+ const transaction = readString(raw, "transaction", "txHash", "tx_hash");
73
+ if (!resourceUrl || !payer || !network || issuedAt === undefined) {
74
+ throw new Error("x402 receipt payload missing required fields (resourceUrl, payer, network, issuedAt)");
75
+ }
76
+ const payload = { resourceUrl, payer, network, issuedAt };
77
+ if (transaction) {
78
+ payload.transaction = transaction;
79
+ }
80
+ return payload;
81
+ }
82
+ /** BLAKE3 hex digest of JCS-canonical x402 receipt payload bytes. */
83
+ export function x402ReceiptPayloadDigestHex(payload) {
84
+ return digestToHex(jsonValueDigest(payload));
85
+ }
86
+ /**
87
+ * Converts an x402 signed receipt artifact or payload into artifact_attested evidence fields.
88
+ */
89
+ export function mapX402ReceiptToArtifactAttestedEvidence(receiptInput) {
90
+ const raw = unwrapReceiptRecord(receiptInput);
91
+ const payload = buildX402ReceiptDigestPayload(raw);
92
+ return {
93
+ artifact_blake3_hex: [x402ReceiptPayloadDigestHex(payload)],
94
+ operation: "attested",
95
+ vendor_ref_id: payload.resourceUrl,
96
+ };
97
+ }
@@ -0,0 +1,12 @@
1
+ /** x402 Signed Offer & Receipt extension signature verification. */
2
+ export type SignedX402Receipt = {
3
+ format: "eip712" | "jws";
4
+ payload?: Record<string, unknown>;
5
+ signature: string;
6
+ };
7
+ /** Locates a signed x402 receipt artifact in common wire envelopes. */
8
+ export declare function extractSignedX402Receipt(input: Record<string, unknown>): SignedX402Receipt;
9
+ /** Cryptographically verifies an x402 signed receipt before digest mapping. */
10
+ export declare function verifySignedX402Receipt(signed: SignedX402Receipt, options?: {
11
+ expectedSigner?: string;
12
+ }): Record<string, unknown>;
@@ -0,0 +1,211 @@
1
+ /** x402 Signed Offer & Receipt extension signature verification. */
2
+ import { createPublicKey, verify as cryptoVerify } from "node:crypto";
3
+ import { keccak_256 } from "@noble/hashes/sha3";
4
+ import { Signature } from "@noble/secp256k1";
5
+ function readObject(value) {
6
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
7
+ return value;
8
+ }
9
+ return undefined;
10
+ }
11
+ function readString(record, ...keys) {
12
+ for (const key of keys) {
13
+ const value = record[key];
14
+ if (typeof value === "string" && value.length > 0) {
15
+ return value;
16
+ }
17
+ }
18
+ return undefined;
19
+ }
20
+ function base64UrlToBytes(input) {
21
+ const normalized = input.replace(/-/g, "+").replace(/_/g, "/");
22
+ const pad = normalized.length % 4 === 0 ? "" : "=".repeat(4 - (normalized.length % 4));
23
+ return Uint8Array.from(Buffer.from(normalized + pad, "base64"));
24
+ }
25
+ function bytesToBase64Url(bytes) {
26
+ return Buffer.from(bytes)
27
+ .toString("base64")
28
+ .replace(/\+/g, "-")
29
+ .replace(/\//g, "_")
30
+ .replace(/=+$/g, "");
31
+ }
32
+ function keccakHex(data) {
33
+ return keccak_256(data);
34
+ }
35
+ function encodeType(typeName, fields) {
36
+ return `${typeName}(${fields.map((field) => `${field.type} ${field.name}`).join(",")})`;
37
+ }
38
+ function encodeValue(type, value) {
39
+ if (type === "string") {
40
+ return keccakHex(new TextEncoder().encode(String(value ?? "")));
41
+ }
42
+ if (type === "uint256") {
43
+ const bigint = typeof value === "bigint" ? value : BigInt(String(value ?? 0));
44
+ const hex = bigint.toString(16).padStart(64, "0");
45
+ return Uint8Array.from(Buffer.from(hex, "hex"));
46
+ }
47
+ throw new Error(`unsupported EIP-712 type ${type}`);
48
+ }
49
+ function hashStruct(typeName, fields, data) {
50
+ const encoded = [
51
+ keccakHex(new TextEncoder().encode(encodeType(typeName, fields))),
52
+ ...fields.map((field) => encodeValue(field.type, data[field.name])),
53
+ ];
54
+ return keccakHex(Buffer.concat(encoded.map((part) => Buffer.from(part))));
55
+ }
56
+ const RECEIPT_FIELDS = [
57
+ { name: "version", type: "uint256" },
58
+ { name: "network", type: "string" },
59
+ { name: "resourceUrl", type: "string" },
60
+ { name: "payer", type: "string" },
61
+ { name: "issuedAt", type: "uint256" },
62
+ { name: "transaction", type: "string" },
63
+ ];
64
+ function normalizeReceiptPayload(payload) {
65
+ const transaction = payload.transaction;
66
+ return {
67
+ ...payload,
68
+ transaction: typeof transaction === "string" ? transaction : "",
69
+ };
70
+ }
71
+ function eip712ReceiptDigest(payload) {
72
+ const domainFields = [
73
+ { name: "name", type: "string" },
74
+ { name: "version", type: "string" },
75
+ { name: "chainId", type: "uint256" },
76
+ ];
77
+ const domain = {
78
+ name: "x402 receipt",
79
+ version: "1",
80
+ chainId: 1,
81
+ };
82
+ const normalized = normalizeReceiptPayload(payload);
83
+ const domainSeparator = hashStruct("EIP712Domain", domainFields, domain);
84
+ const structHash = hashStruct("Receipt", [...RECEIPT_FIELDS], normalized);
85
+ return keccakHex(Buffer.concat([Buffer.from([0x19, 0x01]), Buffer.from(domainSeparator), Buffer.from(structHash)]));
86
+ }
87
+ function parseEip712Signature(signature) {
88
+ const trimmed = signature.trim();
89
+ if (!/^0x[0-9a-fA-F]{130}$/.test(trimmed)) {
90
+ throw new Error("x402 EIP-712 signature must be 0x-prefixed 65-byte hex");
91
+ }
92
+ const body = trimmed.slice(2);
93
+ const r = BigInt(`0x${body.slice(0, 64)}`);
94
+ const s = BigInt(`0x${body.slice(64, 128)}`);
95
+ const v = Number.parseInt(body.slice(128, 130), 16);
96
+ return { r, s, v };
97
+ }
98
+ function recoverEip712Signer(digest, signature) {
99
+ const { r, s, v } = parseEip712Signature(signature);
100
+ const recovery = v >= 27 ? v - 27 : v;
101
+ const sigBytes = new Uint8Array(64);
102
+ sigBytes.set(Uint8Array.from(Buffer.from(r.toString(16).padStart(64, "0"), "hex")), 0);
103
+ sigBytes.set(Uint8Array.from(Buffer.from(s.toString(16).padStart(64, "0"), "hex")), 32);
104
+ const publicKey = Signature.fromCompact(sigBytes).addRecoveryBit(recovery).recoverPublicKey(digest);
105
+ const uncompressed = publicKey.toBytes(false);
106
+ const addressBytes = keccakHex(uncompressed.slice(1)).slice(-20);
107
+ return `0x${Buffer.from(addressBytes).toString("hex")}`;
108
+ }
109
+ function verifyJwsCompactSignature(signature) {
110
+ const parts = signature.split(".");
111
+ if (parts.length !== 3) {
112
+ throw new Error("x402 JWS signature must use compact serialization");
113
+ }
114
+ const [headerB64, payloadB64, sigB64] = parts;
115
+ const header = JSON.parse(Buffer.from(base64UrlToBytes(headerB64)).toString("utf8"));
116
+ const payload = JSON.parse(Buffer.from(base64UrlToBytes(payloadB64)).toString("utf8"));
117
+ const signingInput = new TextEncoder().encode(`${headerB64}.${payloadB64}`);
118
+ const signatureBytes = base64UrlToBytes(sigB64);
119
+ const alg = header.alg;
120
+ if (alg === "EdDSA" || alg === "Ed25519") {
121
+ const jwk = readObject(header.jwk);
122
+ const x = jwk ? readString(jwk, "x") : undefined;
123
+ if (!x) {
124
+ throw new Error("x402 JWS Ed25519 verification requires embedded jwk.x");
125
+ }
126
+ const publicKey = createPublicKey({
127
+ key: header.jwk,
128
+ format: "jwk",
129
+ });
130
+ if (!cryptoVerify(null, signingInput, publicKey, signatureBytes)) {
131
+ throw new Error("x402 JWS Ed25519 signature verification failed");
132
+ }
133
+ return payload;
134
+ }
135
+ if (alg === "ES256") {
136
+ const jwk = readObject(header.jwk);
137
+ if (!jwk) {
138
+ throw new Error("x402 JWS ES256 verification requires embedded jwk");
139
+ }
140
+ const publicKey = createPublicKey({
141
+ key: jwk,
142
+ format: "jwk",
143
+ });
144
+ if (!cryptoVerify("sha256", signingInput, publicKey, signatureBytes)) {
145
+ throw new Error("x402 JWS ES256 signature verification failed");
146
+ }
147
+ return payload;
148
+ }
149
+ throw new Error(`unsupported x402 JWS alg ${String(alg)}`);
150
+ }
151
+ /** Locates a signed x402 receipt artifact in common wire envelopes. */
152
+ export function extractSignedX402Receipt(input) {
153
+ const extensions = readObject(input.extensions);
154
+ if (extensions) {
155
+ const offerReceipt = readObject(extensions["offer-receipt"]) ?? readObject(extensions.offerReceipt);
156
+ const info = offerReceipt ? readObject(offerReceipt.info) : undefined;
157
+ const receipt = info ? readObject(info.receipt) : undefined;
158
+ if (receipt && typeof receipt.format === "string" && typeof receipt.signature === "string") {
159
+ return {
160
+ format: receipt.format === "jws" ? "jws" : "eip712",
161
+ payload: readObject(receipt.payload),
162
+ signature: receipt.signature,
163
+ };
164
+ }
165
+ if (offerReceipt) {
166
+ const nested = readObject(offerReceipt.receipt) ?? offerReceipt;
167
+ if (nested && typeof nested.format === "string" && typeof nested.signature === "string") {
168
+ return {
169
+ format: nested.format === "jws" ? "jws" : "eip712",
170
+ payload: readObject(nested.payload),
171
+ signature: nested.signature,
172
+ };
173
+ }
174
+ }
175
+ }
176
+ const receipt = readObject(input.receipt);
177
+ if (receipt && typeof receipt.format === "string" && typeof receipt.signature === "string") {
178
+ return {
179
+ format: receipt.format === "jws" ? "jws" : "eip712",
180
+ payload: readObject(receipt.payload),
181
+ signature: receipt.signature,
182
+ };
183
+ }
184
+ if (typeof input.format === "string" && typeof input.signature === "string") {
185
+ return {
186
+ format: input.format === "jws" ? "jws" : "eip712",
187
+ payload: readObject(input.payload),
188
+ signature: input.signature,
189
+ };
190
+ }
191
+ throw new Error("x402 receipt input missing signed offer-receipt artifact (format and signature required)");
192
+ }
193
+ /** Cryptographically verifies an x402 signed receipt before digest mapping. */
194
+ export function verifySignedX402Receipt(signed, options) {
195
+ if (signed.format === "jws") {
196
+ const payload = verifyJwsCompactSignature(signed.signature);
197
+ return payload;
198
+ }
199
+ if (!signed.payload) {
200
+ throw new Error("x402 EIP-712 receipt requires payload alongside signature");
201
+ }
202
+ const digest = eip712ReceiptDigest(signed.payload);
203
+ const recovered = recoverEip712Signer(digest, signed.signature);
204
+ if (options?.expectedSigner) {
205
+ const expected = options.expectedSigner.trim().toLowerCase();
206
+ if (recovered.toLowerCase() !== expected) {
207
+ throw new Error("x402 EIP-712 recovered signer does not match expected signer");
208
+ }
209
+ }
210
+ return signed.payload;
211
+ }