settld 0.1.1 → 0.1.5

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 (441) hide show
  1. package/README.md +61 -3
  2. package/SETTLD_VERSION +1 -1
  3. package/bin/settld-mcp +2 -0
  4. package/bin/settld.js +13 -0
  5. package/conformance/kernel-v0/README.md +7 -0
  6. package/conformance/kernel-v0/run.mjs +292 -4
  7. package/docs/ACCESS.md +57 -0
  8. package/docs/ADOPTION_CHECKLIST.md +44 -0
  9. package/docs/ALERTS.md +198 -0
  10. package/docs/ARCHITECTURE.md +69 -0
  11. package/docs/ARCHITECTURE_FOUNDER_GUIDE.md +284 -0
  12. package/docs/ARTIFACTS.md +60 -0
  13. package/docs/CERTIFICATION_CHECKLIST.md +33 -0
  14. package/docs/CIRCLE_SANDBOX_E2E.md +140 -0
  15. package/docs/CONFIG.md +297 -0
  16. package/docs/CONTRACTS_APIS.md +23 -0
  17. package/docs/DEPRECATION.md +31 -0
  18. package/docs/DOMAIN_MODEL.md +92 -0
  19. package/docs/EVENT_ENVELOPE.md +53 -0
  20. package/docs/FINANCE_PACK_FORMAT.md +53 -0
  21. package/docs/INCIDENT_TAXONOMY.md +30 -0
  22. package/docs/JOB_STATE_MACHINE.md +66 -0
  23. package/docs/KERNEL_COMPATIBLE.md +60 -0
  24. package/docs/KERNEL_V0.md +40 -0
  25. package/docs/KEY_ROTATION.md +80 -0
  26. package/docs/LEDGER.md +82 -0
  27. package/docs/LIVENESS.md +76 -0
  28. package/docs/MVP_BUILD_ORDER.md +36 -0
  29. package/docs/ONCALL_PLAYBOOK.md +39 -0
  30. package/docs/OPERATIONS_SIGNING.md +20 -0
  31. package/docs/OVERVIEW.md +190 -0
  32. package/docs/PERF_BASELINE.md +85 -0
  33. package/docs/PRD.md +77 -0
  34. package/docs/QUICKSTART_KERNEL_V0.md +96 -0
  35. package/docs/QUICKSTART_MCP.md +337 -0
  36. package/docs/QUICKSTART_MCP_HOSTS.md +143 -0
  37. package/docs/QUICKSTART_PRODUCE.md +61 -0
  38. package/docs/QUICKSTART_RELEASE_VERIFY.md +39 -0
  39. package/docs/QUICKSTART_SDK.md +125 -0
  40. package/docs/QUICKSTART_SDK_PYTHON.md +111 -0
  41. package/docs/QUICKSTART_VERIFY.md +54 -0
  42. package/docs/QUICKSTART_X402_GATEWAY.md +317 -0
  43. package/docs/README.md +15 -0
  44. package/docs/RELEASE_CHECKLIST.md +156 -0
  45. package/docs/RELEASING.md +81 -0
  46. package/docs/REPO_SETTINGS.md +37 -0
  47. package/docs/RUNBOOK.md +86 -0
  48. package/docs/SKILLS.md +42 -0
  49. package/docs/SKILL_BUNDLE_FORMAT.md +48 -0
  50. package/docs/SLO.md +70 -0
  51. package/docs/SUMMARY.md +16 -0
  52. package/docs/SUPPORT.md +31 -0
  53. package/docs/THREAT_MODEL.md +36 -0
  54. package/docs/TRUST.md +59 -0
  55. package/docs/WORKFLOW.md +35 -0
  56. package/docs/X402_BATCH_SETTLEMENT.md +126 -0
  57. package/docs/blog/2026-02-14-your-ai-agent-just-spent-500-where-is-the-receipt.md +73 -0
  58. package/docs/examples/x402-provider-payout-registry.example.json +14 -0
  59. package/docs/gitbook/README.md +52 -0
  60. package/docs/gitbook/SETUP.md +25 -0
  61. package/docs/gitbook/SUMMARY.md +15 -0
  62. package/docs/gitbook/api-reference.md +73 -0
  63. package/docs/gitbook/closepacks.md +55 -0
  64. package/docs/gitbook/conformance.md +59 -0
  65. package/docs/gitbook/core-primitives.md +85 -0
  66. package/docs/gitbook/dispute-lifecycle.md +33 -0
  67. package/docs/gitbook/faq.md +21 -0
  68. package/docs/gitbook/guides.md +49 -0
  69. package/docs/gitbook/operations-runbook.md +36 -0
  70. package/docs/gitbook/quickstart.md +104 -0
  71. package/docs/gitbook/replay-and-audit.md +30 -0
  72. package/docs/gitbook/sdk-reference.md +35 -0
  73. package/docs/gitbook/security-model.md +58 -0
  74. package/docs/integrations/README.md +14 -0
  75. package/docs/integrations/github-actions-verify.yml +31 -0
  76. package/docs/integrations/github-actions.md +34 -0
  77. package/docs/integrations/openclaw/CLAWHUB_PUBLISH_CHECKLIST.md +65 -0
  78. package/docs/integrations/openclaw/settld-mcp-skill/SKILL.md +69 -0
  79. package/docs/integrations/openclaw/settld-mcp-skill/mcp-server.example.json +12 -0
  80. package/docs/kernel-compatible/capabilities.json +36 -0
  81. package/docs/marketing/agent-commerce-substrate.md +78 -0
  82. package/docs/marketing/hn-repost-2026-02-17.md +102 -0
  83. package/docs/marketing/show-hn-post.md +45 -0
  84. package/docs/ops/ARTIFACT_VERIFICATION_STATUS.md +43 -0
  85. package/docs/ops/BILLING_WEBHOOK_REPLAY.md +105 -0
  86. package/docs/ops/CI_FLAKE_BUDGET.md +31 -0
  87. package/docs/ops/GO_LIVE_GATE_S13.md +27 -0
  88. package/docs/ops/HOSTED_BASELINE_R2.md +129 -0
  89. package/docs/ops/KERNEL_V0_SHIP_GATE.md +67 -0
  90. package/docs/ops/LIGHTHOUSE_PRODUCTION_CLOSE.md +51 -0
  91. package/docs/ops/MCP_COMPATIBILITY_MATRIX.md +28 -0
  92. package/docs/ops/MINIMUM_PRODUCTION_TOPOLOGY.md +89 -0
  93. package/docs/ops/P0_BACKEND_PROGRESS.md +150 -0
  94. package/docs/ops/PAYMENTS_ALPHA_R5.md +105 -0
  95. package/docs/ops/PILOT_ONBOARDING_RUNBOOK.md +112 -0
  96. package/docs/ops/PRODUCTION_DEPLOYMENT_CHECKLIST.md +103 -0
  97. package/docs/ops/R1_SLOS.md +66 -0
  98. package/docs/ops/RELEASE_SIGNING_INCIDENT.md +58 -0
  99. package/docs/ops/SELF_SERVE_LAUNCH_AUTOMATION.md +89 -0
  100. package/docs/ops/THROUGHPUT_DRILL_10X.md +48 -0
  101. package/docs/ops/TRUST_CONFIG_WIZARD.md +47 -0
  102. package/docs/ops/X402_PILOT_WEEKLY_METRICS.md +76 -0
  103. package/docs/ops/tool-call-disputes-holdback.md +52 -0
  104. package/docs/pilot-kit/PILOT_PACKAGE_SCORECARD_X402.md +46 -0
  105. package/docs/pilot-kit/README.md +29 -0
  106. package/docs/pilot-kit/architecture-one-pager.md +48 -0
  107. package/docs/pilot-kit/buyer-email.txt +19 -0
  108. package/docs/pilot-kit/buyer-one-pager.md +31 -0
  109. package/docs/pilot-kit/gtm-pilot-playbook.md +182 -0
  110. package/docs/pilot-kit/offline-verify.md +33 -0
  111. package/docs/pilot-kit/procurement-one-pager.md +50 -0
  112. package/docs/pilot-kit/rfp-clause.md +46 -0
  113. package/docs/pilot-kit/roi-calculator-template.csv +2 -0
  114. package/docs/pilot-kit/security-qa.md +153 -0
  115. package/docs/pilot-kit/security-summary.md +35 -0
  116. package/docs/plans/2026-02-13-mcp-spike-design.md +113 -0
  117. package/docs/spec/AcceptanceCriteria.v1.md +17 -0
  118. package/docs/spec/AcceptanceEvaluation.v1.md +10 -0
  119. package/docs/spec/AgentEvent.v1.md +47 -0
  120. package/docs/spec/AgentIdentity.v1.md +62 -0
  121. package/docs/spec/AgentPassport.v1.md +95 -0
  122. package/docs/spec/AgentReputation.v1.md +59 -0
  123. package/docs/spec/AgentReputation.v2.md +52 -0
  124. package/docs/spec/AgentRun.v1.md +47 -0
  125. package/docs/spec/AgentRunSettlement.v1.md +52 -0
  126. package/docs/spec/AgentWallet.v1.md +43 -0
  127. package/docs/spec/AgreementDelegation.v1.md +109 -0
  128. package/docs/spec/ArbitrationCase.v1.md +67 -0
  129. package/docs/spec/ArbitrationVerdict.v1.md +60 -0
  130. package/docs/spec/BundleHeadAttestation.v1.md +32 -0
  131. package/docs/spec/CANONICAL_JSON.md +31 -0
  132. package/docs/spec/CRYPTOGRAPHY.md +61 -0
  133. package/docs/spec/ClosePack.v1.md +49 -0
  134. package/docs/spec/ClosePackManifest.v1.md +24 -0
  135. package/docs/spec/DelegationGrant.v1.md +90 -0
  136. package/docs/spec/DisputeOpenEnvelope.v1.md +43 -0
  137. package/docs/spec/ERRORS.md +76 -0
  138. package/docs/spec/ESCROW_NETTING_INVARIANTS.md +71 -0
  139. package/docs/spec/EvidenceIndex.v1.md +20 -0
  140. package/docs/spec/ExecutionIntent.v1.md +90 -0
  141. package/docs/spec/FinancePackBundleManifest.v1.md +24 -0
  142. package/docs/spec/FundingHold.v1.md +60 -0
  143. package/docs/spec/GovernancePolicy.v1.md +34 -0
  144. package/docs/spec/GovernancePolicy.v2.md +30 -0
  145. package/docs/spec/INVARIANTS.md +389 -0
  146. package/docs/spec/InteractionDirectionMatrix.v1.md +30 -0
  147. package/docs/spec/InvoiceBundleManifest.v1.md +24 -0
  148. package/docs/spec/InvoiceClaim.v1.md +11 -0
  149. package/docs/spec/MONEY_RAIL_STATE_MACHINE.md +58 -0
  150. package/docs/spec/MarketplaceAcceptance.v2.md +46 -0
  151. package/docs/spec/MarketplaceOffer.v2.md +54 -0
  152. package/docs/spec/MeteringReport.v1.md +18 -0
  153. package/docs/spec/PRODUCER_ERRORS.md +42 -0
  154. package/docs/spec/PricingMatrix.v1.md +20 -0
  155. package/docs/spec/PricingMatrixSignatures.v1.md +30 -0
  156. package/docs/spec/PricingMatrixSignatures.v2.md +29 -0
  157. package/docs/spec/ProduceCliOutput.v1.md +46 -0
  158. package/docs/spec/ProofBundleManifest.v1.md +24 -0
  159. package/docs/spec/README.md +104 -0
  160. package/docs/spec/REFERENCE_IMPLEMENTATIONS.md +29 -0
  161. package/docs/spec/REFERENCE_VERIFIER_BEHAVIOR.md +68 -0
  162. package/docs/spec/REMOTE_SIGNER.md +66 -0
  163. package/docs/spec/ReleaseIndex.v1.md +32 -0
  164. package/docs/spec/ReleaseIndexSignatures.v1.md +17 -0
  165. package/docs/spec/ReleaseTrust.v1.md +13 -0
  166. package/docs/spec/ReleaseTrust.v2.md +26 -0
  167. package/docs/spec/RemoteSignerRequest.v1.md +21 -0
  168. package/docs/spec/RemoteSignerResponse.v1.md +16 -0
  169. package/docs/spec/ReputationEvent.v1.md +63 -0
  170. package/docs/spec/RevocationList.v1.md +28 -0
  171. package/docs/spec/SIGNER_PROVIDER_PLUGIN.md +32 -0
  172. package/docs/spec/STRICTNESS.md +68 -0
  173. package/docs/spec/SUPPLY_CHAIN.md +33 -0
  174. package/docs/spec/SettlementAdjustment.v1.md +45 -0
  175. package/docs/spec/SettlementDecisionRecord.v1.md +48 -0
  176. package/docs/spec/SettlementDecisionRecord.v2.md +51 -0
  177. package/docs/spec/SettlementDecisionReport.v1.md +44 -0
  178. package/docs/spec/SettlementKernel.v1.md +59 -0
  179. package/docs/spec/SettlementReceipt.v1.md +63 -0
  180. package/docs/spec/SlaDefinition.v1.md +24 -0
  181. package/docs/spec/SlaEvaluation.v1.md +12 -0
  182. package/docs/spec/THREAT_MODEL.md +113 -0
  183. package/docs/spec/TOOL_PROVENANCE.md +30 -0
  184. package/docs/spec/TRUST_ANCHORS.md +84 -0
  185. package/docs/spec/TenantSettings.v1.md +90 -0
  186. package/docs/spec/TenantSettings.v2.md +99 -0
  187. package/docs/spec/TimestampProof.v1.md +25 -0
  188. package/docs/spec/ToolCallAgreement.v1.md +34 -0
  189. package/docs/spec/ToolCallEvidence.v1.md +47 -0
  190. package/docs/spec/ToolManifest.v1.md +47 -0
  191. package/docs/spec/VERIFIER_ENVIRONMENT.md +38 -0
  192. package/docs/spec/VERSIONING.md +107 -0
  193. package/docs/spec/VerificationReport.v1.md +50 -0
  194. package/docs/spec/VerifyAboutOutput.v1.md +10 -0
  195. package/docs/spec/VerifyCliOutput.v1.md +28 -0
  196. package/docs/spec/WARNINGS.md +83 -0
  197. package/docs/spec/error-codes.v1.txt +285 -0
  198. package/docs/spec/examples/agreement_delegation_v1.example.json +21 -0
  199. package/docs/spec/examples/arbitration_case_v1.example.json +26 -0
  200. package/docs/spec/examples/arbitration_verdict_v1.example.json +32 -0
  201. package/docs/spec/examples/dispute_open_envelope_v1.example.json +18 -0
  202. package/docs/spec/examples/produce_cli_output_v1.example.json +32 -0
  203. package/docs/spec/examples/release_index_signature_v1.example.json +9 -0
  204. package/docs/spec/examples/release_index_signatures_v1.example.json +14 -0
  205. package/docs/spec/examples/release_index_v1.example.json +15 -0
  206. package/docs/spec/examples/release_trust_v1.example.json +7 -0
  207. package/docs/spec/examples/release_trust_v2.example.json +22 -0
  208. package/docs/spec/examples/remote_signer_request_v1.example.json +18 -0
  209. package/docs/spec/examples/remote_signer_response_v1.example.json +8 -0
  210. package/docs/spec/examples/reputation_event_v1.example.json +29 -0
  211. package/docs/spec/examples/verification_report_v1.example.json +24 -0
  212. package/docs/spec/examples/verify_about_output_v1.example.json +29 -0
  213. package/docs/spec/examples/verify_cli_output_v1.example.json +13 -0
  214. package/docs/spec/legacy/MarketplaceAcceptance.v1.md +48 -0
  215. package/docs/spec/legacy/MarketplaceOffer.v1.md +56 -0
  216. package/docs/spec/legacy/schemas/MarketplaceAcceptance.v1.schema.json +53 -0
  217. package/docs/spec/legacy/schemas/MarketplaceOffer.v1.schema.json +61 -0
  218. package/docs/spec/producer-error-codes.v1.txt +14 -0
  219. package/docs/spec/schemas/AcceptanceCriteria.v1.schema.json +24 -0
  220. package/docs/spec/schemas/AcceptanceEvaluation.v1.schema.json +26 -0
  221. package/docs/spec/schemas/AgentEvent.v1.schema.json +49 -0
  222. package/docs/spec/schemas/AgentIdentity.v1.schema.json +129 -0
  223. package/docs/spec/schemas/AgentPassport.v1.schema.json +112 -0
  224. package/docs/spec/schemas/AgentReputation.v1.schema.json +151 -0
  225. package/docs/spec/schemas/AgentReputation.v2.schema.json +120 -0
  226. package/docs/spec/schemas/AgentRun.v1.schema.json +71 -0
  227. package/docs/spec/schemas/AgentRunSettlement.v1.schema.json +75 -0
  228. package/docs/spec/schemas/AgentWallet.v1.schema.json +54 -0
  229. package/docs/spec/schemas/AgreementDelegation.v1.schema.json +50 -0
  230. package/docs/spec/schemas/ArbitrationCase.v1.schema.json +133 -0
  231. package/docs/spec/schemas/ArbitrationVerdict.v1.schema.json +149 -0
  232. package/docs/spec/schemas/BundleHeadAttestation.v1.schema.json +21 -0
  233. package/docs/spec/schemas/ClosePackManifest.v1.schema.json +38 -0
  234. package/docs/spec/schemas/DelegationGrant.v1.schema.json +102 -0
  235. package/docs/spec/schemas/DisputeOpenEnvelope.v1.schema.json +78 -0
  236. package/docs/spec/schemas/EvidenceIndex.v1.schema.json +41 -0
  237. package/docs/spec/schemas/ExecutionIntent.v1.schema.json +85 -0
  238. package/docs/spec/schemas/FinancePackBundleManifest.v1.schema.json +38 -0
  239. package/docs/spec/schemas/FundingHold.v1.schema.json +46 -0
  240. package/docs/spec/schemas/GovernancePolicy.v1.schema.json +45 -0
  241. package/docs/spec/schemas/GovernancePolicy.v2.schema.json +70 -0
  242. package/docs/spec/schemas/InteractionDirectionMatrix.v1.schema.json +43 -0
  243. package/docs/spec/schemas/InvoiceBundleManifest.v1.schema.json +38 -0
  244. package/docs/spec/schemas/InvoiceClaim.v1.schema.json +39 -0
  245. package/docs/spec/schemas/MarketplaceAcceptance.v2.schema.json +53 -0
  246. package/docs/spec/schemas/MarketplaceOffer.v2.schema.json +61 -0
  247. package/docs/spec/schemas/MeteringReport.v1.schema.json +45 -0
  248. package/docs/spec/schemas/PricingMatrix.v1.schema.json +24 -0
  249. package/docs/spec/schemas/PricingMatrixSignatures.v1.schema.json +24 -0
  250. package/docs/spec/schemas/PricingMatrixSignatures.v2.schema.json +24 -0
  251. package/docs/spec/schemas/ProduceCliOutput.v1.schema.json +107 -0
  252. package/docs/spec/schemas/ProofBundleManifest.v1.schema.json +37 -0
  253. package/docs/spec/schemas/PublicKeys.v1.schema.json +33 -0
  254. package/docs/spec/schemas/ReleaseIndex.v1.schema.json +45 -0
  255. package/docs/spec/schemas/ReleaseIndexSignature.v1.schema.json +16 -0
  256. package/docs/spec/schemas/ReleaseIndexSignatures.v1.schema.json +16 -0
  257. package/docs/spec/schemas/ReleaseTrust.v1.schema.json +15 -0
  258. package/docs/spec/schemas/ReleaseTrust.v2.schema.json +37 -0
  259. package/docs/spec/schemas/RemoteSignerPublicKeyResponse.v1.schema.json +14 -0
  260. package/docs/spec/schemas/RemoteSignerRequest.v1.schema.json +24 -0
  261. package/docs/spec/schemas/RemoteSignerResponse.v1.schema.json +10 -0
  262. package/docs/spec/schemas/RemoteSignerSignRequest.v1.schema.json +27 -0
  263. package/docs/spec/schemas/RemoteSignerSignResponse.v1.schema.json +16 -0
  264. package/docs/spec/schemas/ReputationEvent.v1.schema.json +164 -0
  265. package/docs/spec/schemas/RevocationList.v1.schema.json +51 -0
  266. package/docs/spec/schemas/SettlementAdjustment.v1.schema.json +44 -0
  267. package/docs/spec/schemas/SettlementDecisionRecord.v1.schema.json +66 -0
  268. package/docs/spec/schemas/SettlementDecisionRecord.v2.schema.json +148 -0
  269. package/docs/spec/schemas/SettlementDecisionReport.v1.schema.json +61 -0
  270. package/docs/spec/schemas/SettlementReceipt.v1.schema.json +135 -0
  271. package/docs/spec/schemas/SlaDefinition.v1.schema.json +33 -0
  272. package/docs/spec/schemas/SlaEvaluation.v1.schema.json +26 -0
  273. package/docs/spec/schemas/TenantSettings.v1.schema.json +90 -0
  274. package/docs/spec/schemas/TenantSettings.v2.schema.json +161 -0
  275. package/docs/spec/schemas/TimestampProof.v1.schema.json +17 -0
  276. package/docs/spec/schemas/ToolCallAgreement.v1.schema.json +34 -0
  277. package/docs/spec/schemas/ToolCallEvidence.v1.schema.json +45 -0
  278. package/docs/spec/schemas/ToolManifest.v1.schema.json +54 -0
  279. package/docs/spec/schemas/VerificationReport.v1.schema.json +83 -0
  280. package/docs/spec/schemas/VerifyAboutOutput.v1.schema.json +54 -0
  281. package/docs/spec/schemas/VerifyCliOutput.v1.schema.json +75 -0
  282. package/docs/spec/schemas/VerifyReleaseOutput.v1.schema.json +47 -0
  283. package/docs/spec/x402-error-codes.v1.txt +21 -0
  284. package/docs/templates/buyer-email.txt +18 -0
  285. package/docs/templates/buyer-one-pager.md +24 -0
  286. package/package.json +40 -6
  287. package/scripts/acceptance/full-stack.mjs +734 -0
  288. package/scripts/acceptance/full-stack.sh +99 -0
  289. package/scripts/audit/build-audit-packet.mjs +242 -0
  290. package/scripts/backup-pg.sh +45 -0
  291. package/scripts/backup-restore/README.md +18 -0
  292. package/scripts/backup-restore/capture-state.mjs +130 -0
  293. package/scripts/backup-restore/client.mjs +97 -0
  294. package/scripts/backup-restore/seed-workload.mjs +235 -0
  295. package/scripts/backup-restore/verify-state.mjs +139 -0
  296. package/scripts/backup-restore-test.sh +217 -0
  297. package/scripts/chaos.js +221 -0
  298. package/scripts/ci/build-launch-cutover-packet.mjs +148 -0
  299. package/scripts/ci/build-self-serve-benchmark-report.mjs +122 -0
  300. package/scripts/ci/changelog-guard.mjs +145 -0
  301. package/scripts/ci/check-kernel-v0-launch-gate.mjs +233 -0
  302. package/scripts/ci/check-secret-hygiene.mjs +78 -0
  303. package/scripts/ci/check-version-consistency.mjs +42 -0
  304. package/scripts/ci/cli-pack-smoke.mjs +160 -0
  305. package/scripts/ci/flake-budget-guard.mjs +68 -0
  306. package/scripts/ci/generate-error-codes.mjs +54 -0
  307. package/scripts/ci/lib/lighthouse-tracker.mjs +90 -0
  308. package/scripts/ci/lib/self-serve-launch-gate.mjs +89 -0
  309. package/scripts/ci/npm-pack-smoke.mjs +454 -0
  310. package/scripts/ci/run-10x-throughput-drill.mjs +246 -0
  311. package/scripts/ci/run-10x-throughput-incident-rehearsal.mjs +325 -0
  312. package/scripts/ci/run-arbitration-workspace-browser-e2e.sh +22 -0
  313. package/scripts/ci/run-circle-sandbox-smoke.mjs +237 -0
  314. package/scripts/ci/run-go-live-gate.mjs +150 -0
  315. package/scripts/ci/run-kernel-v0-ship-gate.mjs +97 -0
  316. package/scripts/ci/run-mcp-host-smoke.mjs +275 -0
  317. package/scripts/ci/run-self-serve-launch-gate.mjs +56 -0
  318. package/scripts/ci/runtime-import-smoke.mjs +58 -0
  319. package/scripts/ci/update-lighthouse-tracker.mjs +112 -0
  320. package/scripts/closepack/lib.mjs +286 -0
  321. package/scripts/collect-debug.sh +263 -0
  322. package/scripts/demo/compositional-settlement-3hop.mjs +237 -0
  323. package/scripts/demo/delivery-robot/export-ui-fixture.mjs +188 -0
  324. package/scripts/demo/delivery-robot/generate.mjs +377 -0
  325. package/scripts/demo/kernel-agent-goes-shopping.mjs +202 -0
  326. package/scripts/demo/magic-link-first-green.mjs +118 -0
  327. package/scripts/demo/magic-link-kind-smoke.mjs +577 -0
  328. package/scripts/demo/mcp-paid-exa.mjs +1110 -0
  329. package/scripts/dev/billing-doctor.sh +145 -0
  330. package/scripts/dev/billing-smoke-prod.sh +219 -0
  331. package/scripts/dev/billing-webhook-replay.sh +161 -0
  332. package/scripts/dev/env.dev.example +29 -0
  333. package/scripts/dev/env.sh +37 -0
  334. package/scripts/dev/new-sdk-key.sh +81 -0
  335. package/scripts/dev/sdk-first-run.sh +21 -0
  336. package/scripts/dev/smoke-x402-gateway.sh +115 -0
  337. package/scripts/dev/start-api.sh +24 -0
  338. package/scripts/examples/produce-and-verify-jobproof.mjs +191 -0
  339. package/scripts/examples/sdk-first-paid-rfq.py +105 -0
  340. package/scripts/examples/sdk-first-verified-run.mjs +85 -0
  341. package/scripts/examples/sdk-first-verified-run.py +99 -0
  342. package/scripts/examples/sdk-tenant-analytics.mjs +103 -0
  343. package/scripts/examples/sdk-tenant-analytics.py +118 -0
  344. package/scripts/finance-pack/bundle.mjs +284 -0
  345. package/scripts/fixtures/generate-bundle-fixtures.mjs +877 -0
  346. package/scripts/governance/export.mjs +169 -0
  347. package/scripts/load/delivery-stress.k6.js +183 -0
  348. package/scripts/load/ingest-burst.k6.js +236 -0
  349. package/scripts/load/run-delivery-load.js +66 -0
  350. package/scripts/load/webhook-receiver.js +131 -0
  351. package/scripts/magic-link/migrate-run-records-to-db.mjs +35 -0
  352. package/scripts/mcp/probe.mjs +238 -0
  353. package/scripts/mcp/settld-mcp-http-gateway.mjs +178 -0
  354. package/scripts/mcp/settld-mcp-server.mjs +1201 -0
  355. package/scripts/openapi/write.mjs +13 -0
  356. package/scripts/ops/bootstrap-tenant-conformance.mjs +185 -0
  357. package/scripts/ops/build-x402-pilot-reliability-report.mjs +489 -0
  358. package/scripts/ops/check-x402-receipt-sample.mjs +181 -0
  359. package/scripts/ops/design-partner-run-packet.mjs +466 -0
  360. package/scripts/ops/hosted-baseline-evidence.mjs +681 -0
  361. package/scripts/ops/money-rails-chargeback-evidence.mjs +509 -0
  362. package/scripts/ops/money-rails-reconcile-evidence.mjs +180 -0
  363. package/scripts/ops/p0-seed-money-rail-operation.mjs +432 -0
  364. package/scripts/pilot/finance-pack.mjs +495 -0
  365. package/scripts/pilot/fixtures/robot-keypair.json +4 -0
  366. package/scripts/pilot/fixtures/server-signer.json +4 -0
  367. package/scripts/proof-bundle/job.mjs +109 -0
  368. package/scripts/proof-bundle/lib.mjs +92 -0
  369. package/scripts/proof-bundle/month.mjs +103 -0
  370. package/scripts/provider/conformance-run.mjs +159 -0
  371. package/scripts/provider/keys-generate.mjs +135 -0
  372. package/scripts/provider/publish.mjs +420 -0
  373. package/scripts/quickstart/x402.mjs +334 -0
  374. package/scripts/release/build-artifacts.mjs +181 -0
  375. package/scripts/release/generate-release-index.mjs +112 -0
  376. package/scripts/release/release-index-lib.mjs +232 -0
  377. package/scripts/release/sign-release-index.mjs +85 -0
  378. package/scripts/release/validate-release-assets.mjs +170 -0
  379. package/scripts/release/verify-release.mjs +261 -0
  380. package/scripts/restore-pg.sh +34 -0
  381. package/scripts/scaffold/create-settld-paid-tool.mjs +19 -0
  382. package/scripts/sdk/smoke-python.py +30 -0
  383. package/scripts/sdk/smoke.mjs +16 -0
  384. package/scripts/settlement/x402-batch-worker.mjs +1091 -0
  385. package/scripts/slo/check.mjs +178 -0
  386. package/scripts/smoke/k8s-smoke.mjs +214 -0
  387. package/scripts/spec/generate-protocol-vectors.mjs +931 -0
  388. package/scripts/test/check-no-generated-artifacts.sh +12 -0
  389. package/scripts/test/run.sh +45 -0
  390. package/scripts/trust/validate-trust-file.mjs +57 -0
  391. package/scripts/trust-config/rotate-settld-pay.mjs +277 -0
  392. package/scripts/trust-config/wizard.mjs +161 -0
  393. package/scripts/vendor-contract-test-lib.mjs +182 -0
  394. package/scripts/vendor-contract-test.mjs +55 -0
  395. package/scripts/vercel/build-mkdocs.sh +9 -0
  396. package/scripts/vercel/ignore-mkdocs.sh +25 -0
  397. package/scripts/vercel/install-mkdocs.sh +6 -0
  398. package/scripts/verify-pg.js +217 -0
  399. package/scripts/x402/receipt-verify.mjs +289 -0
  400. package/services/finance-sink/src/dedupe-store.js +29 -6
  401. package/services/receiver/src/dedupe-store.js +29 -5
  402. package/services/x402-gateway/Dockerfile +13 -0
  403. package/services/x402-gateway/README.md +58 -0
  404. package/services/x402-gateway/examples/upstream-mock.js +337 -0
  405. package/services/x402-gateway/src/server.js +947 -0
  406. package/src/api/app.js +32517 -16877
  407. package/src/api/maintenance.js +70 -0
  408. package/src/api/openapi.js +1130 -17
  409. package/src/api/persistence.js +272 -0
  410. package/src/api/server.js +81 -5
  411. package/src/api/store.js +1248 -6
  412. package/src/api/workers/deliveries.js +99 -4
  413. package/src/api/workers/insolvency-sweep.js +159 -0
  414. package/src/core/agent-card.js +69 -0
  415. package/src/core/agent-wallets.js +97 -0
  416. package/src/core/agreement-delegation.js +549 -0
  417. package/src/core/billing-plans.js +40 -6
  418. package/src/core/circle-reserve-adapter.js +845 -0
  419. package/src/core/maintenance-locks.js +1 -0
  420. package/src/core/paid-tool-manifest.js +318 -0
  421. package/src/core/provider-publish-conformance.js +525 -0
  422. package/src/core/provider-publish-proof.js +396 -0
  423. package/src/core/provider-quote-signature.js +170 -0
  424. package/src/core/settld-keys.js +112 -0
  425. package/src/core/settld-pay-token.js +344 -0
  426. package/src/core/settlement-kernel.js +213 -2
  427. package/src/core/settlement-verifier.js +335 -0
  428. package/src/core/tool-call-agreement.js +112 -0
  429. package/src/core/tool-call-evidence.js +144 -0
  430. package/src/core/tool-provider-signature.js +98 -0
  431. package/src/core/x402-escalation-override.js +258 -0
  432. package/src/core/x402-gate.js +118 -0
  433. package/src/core/x402-provider-refund-decision.js +220 -0
  434. package/src/core/x402-receipt-verifier.js +708 -0
  435. package/src/core/x402-reversal-command.js +251 -0
  436. package/src/core/x402-wallet-issuer-decision.js +252 -0
  437. package/src/core/zk-verifier.js +300 -0
  438. package/src/db/migrations/029_reputation_event_index.sql +54 -0
  439. package/src/db/migrations/030_artifacts_source_event_unique_job_only.sql +15 -0
  440. package/src/db/pg.js +18 -7
  441. package/src/db/store-pg.js +838 -72
package/src/api/store.js CHANGED
@@ -18,23 +18,100 @@ import { computeFinanceAccountMapHash, validateFinanceAccountMapV1 } from "../co
18
18
  import { appendChainedEvent, createChainedEvent } from "../core/event-chain.js";
19
19
  import { normalizeBillingPlanId } from "../core/billing-plans.js";
20
20
 
21
+ const SERVER_SIGNER_FILENAME = "server-signer.json";
22
+ const SETTLD_PAY_KEYSET_STORE_FILENAME = "settld-pay-keyset-store.json";
23
+
24
+ function readJsonFileSafe(filePath) {
25
+ if (!fs.existsSync(filePath)) return null;
26
+ const raw = fs.readFileSync(filePath, "utf8");
27
+ return JSON.parse(raw);
28
+ }
29
+
30
+ function normalizeSettldPayPreviousRows(rows) {
31
+ const out = [];
32
+ const list = Array.isArray(rows) ? rows : [];
33
+ const seen = new Set();
34
+ for (const row of list) {
35
+ if (!row || typeof row !== "object" || Array.isArray(row)) continue;
36
+ const publicKeyPem = typeof row.publicKeyPem === "string" ? row.publicKeyPem : "";
37
+ if (!publicKeyPem.trim()) continue;
38
+ const derivedKeyId = keyIdFromPublicKeyPem(publicKeyPem);
39
+ const keyId = typeof row.keyId === "string" && row.keyId.trim() !== "" ? row.keyId.trim() : derivedKeyId;
40
+ if (keyId !== derivedKeyId) throw new Error("invalid settld-pay-keyset-store.json: previous[].keyId mismatch");
41
+ if (seen.has(keyId)) continue;
42
+ seen.add(keyId);
43
+ const rotatedAt = typeof row.rotatedAt === "string" && row.rotatedAt.trim() !== "" ? row.rotatedAt.trim() : null;
44
+ out.push({ keyId, publicKeyPem, rotatedAt });
45
+ }
46
+ return out;
47
+ }
48
+
49
+ function normalizeSettldPayKeysetStore(payload) {
50
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
51
+ throw new Error("invalid settld-pay-keyset-store.json: object expected");
52
+ }
53
+ const active = payload.active;
54
+ if (!active || typeof active !== "object" || Array.isArray(active)) {
55
+ throw new Error("invalid settld-pay-keyset-store.json: active key missing");
56
+ }
57
+ const activePublicKeyPem = typeof active.publicKeyPem === "string" ? active.publicKeyPem : "";
58
+ const activePrivateKeyPem = typeof active.privateKeyPem === "string" ? active.privateKeyPem : "";
59
+ if (!activePublicKeyPem.trim() || !activePrivateKeyPem.trim()) {
60
+ throw new Error("invalid settld-pay-keyset-store.json: active keypair missing");
61
+ }
62
+ const activeDerivedKeyId = keyIdFromPublicKeyPem(activePublicKeyPem);
63
+ const activeKeyId = typeof active.keyId === "string" && active.keyId.trim() !== "" ? active.keyId.trim() : activeDerivedKeyId;
64
+ if (activeKeyId !== activeDerivedKeyId) throw new Error("invalid settld-pay-keyset-store.json: active.keyId mismatch");
65
+
66
+ const previous = normalizeSettldPayPreviousRows(payload.previous);
67
+ return {
68
+ active: {
69
+ keyId: activeKeyId,
70
+ publicKeyPem: activePublicKeyPem,
71
+ privateKeyPem: activePrivateKeyPem
72
+ },
73
+ previous
74
+ };
75
+ }
76
+
21
77
  function loadOrCreateServerSigner({ persistenceDir }) {
22
78
  if (!persistenceDir) {
23
79
  const { publicKeyPem, privateKeyPem } = createEd25519Keypair();
24
- return { publicKeyPem, privateKeyPem };
80
+ return { active: { publicKeyPem, privateKeyPem }, previous: [], source: "generated-ephemeral" };
25
81
  }
26
82
 
27
83
  fs.mkdirSync(persistenceDir, { recursive: true });
28
- const signerPath = path.join(persistenceDir, "server-signer.json");
84
+ const keysetStorePath = path.join(persistenceDir, SETTLD_PAY_KEYSET_STORE_FILENAME);
85
+ const signerPath = path.join(persistenceDir, SERVER_SIGNER_FILENAME);
86
+ if (fs.existsSync(keysetStorePath)) {
87
+ const parsed = readJsonFileSafe(keysetStorePath);
88
+ const normalized = normalizeSettldPayKeysetStore(parsed);
89
+ // Keep legacy signer file in sync for compatibility with existing tooling.
90
+ fs.writeFileSync(
91
+ signerPath,
92
+ JSON.stringify({ publicKeyPem: normalized.active.publicKeyPem, privateKeyPem: normalized.active.privateKeyPem }, null, 2),
93
+ "utf8"
94
+ );
95
+ return {
96
+ active: { publicKeyPem: normalized.active.publicKeyPem, privateKeyPem: normalized.active.privateKeyPem },
97
+ previous: normalized.previous,
98
+ source: "keyset-store"
99
+ };
100
+ }
101
+
29
102
  if (fs.existsSync(signerPath)) {
30
103
  const parsed = JSON.parse(fs.readFileSync(signerPath, "utf8"));
31
104
  if (!parsed?.publicKeyPem || !parsed?.privateKeyPem) throw new Error("invalid server-signer.json");
32
- return { publicKeyPem: parsed.publicKeyPem, privateKeyPem: parsed.privateKeyPem };
105
+ return {
106
+ active: { publicKeyPem: parsed.publicKeyPem, privateKeyPem: parsed.privateKeyPem },
107
+ previous: [],
108
+ source: "legacy-signer"
109
+ };
33
110
  }
34
111
 
35
112
  const { publicKeyPem, privateKeyPem } = createEd25519Keypair();
36
113
  fs.writeFileSync(signerPath, JSON.stringify({ publicKeyPem, privateKeyPem }, null, 2), "utf8");
37
- return { publicKeyPem, privateKeyPem };
114
+ return { active: { publicKeyPem, privateKeyPem }, previous: [], source: "generated-persistent" };
38
115
  }
39
116
 
40
117
  export function createStore({ persistenceDir = null, serverSignerKeypair = null } = {}) {
@@ -49,8 +126,18 @@ export function createStore({ persistenceDir = null, serverSignerKeypair = null
49
126
  throw new Error("invalid serverSignerKeypair");
50
127
  }
51
128
 
52
- const { publicKeyPem: serverPublicKeyPem, privateKeyPem: serverPrivateKeyPem } =
53
- resolvedServerSignerKeypair ?? loadOrCreateServerSigner({ persistenceDir });
129
+ const loadedServerSigner =
130
+ resolvedServerSignerKeypair === null
131
+ ? loadOrCreateServerSigner({ persistenceDir })
132
+ : {
133
+ active: {
134
+ publicKeyPem: resolvedServerSignerKeypair.publicKeyPem,
135
+ privateKeyPem: resolvedServerSignerKeypair.privateKeyPem
136
+ },
137
+ previous: [],
138
+ source: "explicit-override"
139
+ };
140
+ const { publicKeyPem: serverPublicKeyPem, privateKeyPem: serverPrivateKeyPem } = loadedServerSigner.active;
54
141
  const serverKeyId = keyIdFromPublicKeyPem(serverPublicKeyPem);
55
142
 
56
143
  function parseEvidenceRetentionMaxDaysByTenant() {
@@ -222,6 +309,19 @@ export function createStore({ persistenceDir = null, serverSignerKeypair = null
222
309
  agentRunEvents: new Map(), // `${tenantId}\n${runId}` -> AgentEvent.v1[]
223
310
  agentRunSettlements: new Map(), // `${tenantId}\n${runId}` -> AgentRunSettlement.v1
224
311
  arbitrationCases: new Map(), // `${tenantId}\n${caseId}` -> ArbitrationCase.v1 snapshot
312
+ agreementDelegations: new Map(), // `${tenantId}\n${delegationId}` -> AgreementDelegation.v1
313
+ x402Gates: new Map(), // `${tenantId}\n${gateId}` -> X402 gate record (internal API surface)
314
+ x402Receipts: new Map(), // `${tenantId}\n${receiptId}` -> immutable X402ReceiptRecord.v1 base record
315
+ x402WalletPolicies: new Map(), // `${tenantId}\n${sponsorWalletRef}::${policyRef}::${policyVersion}` -> X402WalletPolicy.v1
316
+ x402ZkVerificationKeys: new Map(), // `${tenantId}\n${verificationKeyId}` -> X402ZkVerificationKey.v1
317
+ x402ReversalEvents: new Map(), // `${tenantId}\n${eventId}` -> X402GateReversalEvent.v1
318
+ x402ReversalNonceUsage: new Map(), // `${tenantId}\n${sponsorRef}\n${nonce}` -> X402ReversalNonceUsage.v1
319
+ x402ReversalCommandUsage: new Map(), // `${tenantId}\n${commandId}` -> X402ReversalCommandUsage.v1
320
+ x402Escalations: new Map(), // `${tenantId}\n${escalationId}` -> X402AuthorizationEscalation.v1
321
+ x402EscalationEvents: new Map(), // `${tenantId}\n${eventId}` -> X402AuthorizationEscalationEvent.v1
322
+ x402EscalationOverrideUsage: new Map(), // `${tenantId}\n${overrideId}` -> X402EscalationOverrideUsage.v1
323
+ x402AgentLifecycles: new Map(), // `${tenantId}\n${agentId}` -> X402AgentLifecycle.v1
324
+ x402WebhookEndpoints: new Map(), // `${tenantId}\n${endpointId}` -> X402WebhookEndpoint.v1
225
325
  toolCallHolds: new Map(), // `${tenantId}\n${holdHash}` -> FundingHold.v1 snapshot
226
326
  settlementAdjustments: new Map(), // `${tenantId}\n${adjustmentId}` -> SettlementAdjustment.v1 snapshot
227
327
  moneyRailOperations: new Map(), // `${tenantId}\n${providerId}\n${operationId}` -> MoneyRailOperation.v1
@@ -230,12 +330,14 @@ export function createStore({ persistenceDir = null, serverSignerKeypair = null
230
330
  financeReconciliationTriages: new Map(), // `${tenantId}\n${triageKey}` -> FinanceReconciliationTriage.v1
231
331
  marketplaceRfqs: new Map(), // `${tenantId}\n${rfqId}` -> MarketplaceRfq.v1
232
332
  marketplaceRfqBids: new Map(), // `${tenantId}\n${rfqId}` -> MarketplaceBid.v1[]
333
+ marketplaceProviderPublications: new Map(), // `${tenantId}\n${providerRef}` -> MarketplaceProviderPublication.v1
233
334
  tenantSettlementPolicies: new Map(), // `${tenantId}\n${policyId}\n${policyVersion}` -> TenantSettlementPolicy.v1
234
335
  tenantSettlementPolicyRollouts: new Map(), // `${tenantId}\nrollout` -> TenantSettlementPolicyRollout.v1
235
336
  contracts: new Map(), // `${tenantId}\n${contractId}` -> contract
236
337
  idempotency: new Map(),
237
338
  publicKeyByKeyId,
238
339
  serverSigner: { keyId: serverKeyId, publicKeyPem: serverPublicKeyPem, privateKeyPem: serverPrivateKeyPem },
340
+ settldPayFallbackKeys: loadedServerSigner.previous.map((row) => ({ keyId: row.keyId, publicKeyPem: row.publicKeyPem })),
239
341
  ledgerByTenant,
240
342
  // Back-compat: keep store.ledger and store.config as the default tenant's objects.
241
343
  ledger: ledgerByTenant.get(DEFAULT_TENANT_ID),
@@ -254,6 +356,7 @@ export function createStore({ persistenceDir = null, serverSignerKeypair = null
254
356
  monthCloseCursor: 0,
255
357
  artifactCursor: 0,
256
358
  deliveryCursor: 0,
359
+ x402WinddownReversalCursor: 0,
257
360
  persistence: persistenceDir ? createFileTxLog({ dir: persistenceDir }) : null
258
361
  };
259
362
 
@@ -782,12 +885,1102 @@ export function createStore({ persistenceDir = null, serverSignerKeypair = null
782
885
  return store.agentRunSettlements.get(makeScopedKey({ tenantId, id: String(runId) })) ?? null;
783
886
  };
784
887
 
888
+ store.sumWalletPolicySpendCentsForDay = async function sumWalletPolicySpendCentsForDay({
889
+ tenantId = DEFAULT_TENANT_ID,
890
+ agentId,
891
+ dayStartIso,
892
+ dayEndIso
893
+ } = {}) {
894
+ tenantId = normalizeTenantId(tenantId);
895
+ if (typeof agentId !== "string" || agentId.trim() === "") throw new TypeError("agentId is required");
896
+ if (typeof dayStartIso !== "string" || dayStartIso.trim() === "" || !Number.isFinite(Date.parse(dayStartIso))) {
897
+ throw new TypeError("dayStartIso must be an ISO date string");
898
+ }
899
+ if (typeof dayEndIso !== "string" || dayEndIso.trim() === "" || !Number.isFinite(Date.parse(dayEndIso))) {
900
+ throw new TypeError("dayEndIso must be an ISO date string");
901
+ }
902
+ const startMs = Date.parse(dayStartIso);
903
+ const endMs = Date.parse(dayEndIso);
904
+ if (!(endMs > startMs)) throw new TypeError("dayEndIso must be after dayStartIso");
905
+
906
+ let total = 0;
907
+
908
+ // Agent run settlements lock escrow for the full settlement amount.
909
+ for (const row of store.agentRunSettlements.values()) {
910
+ if (!row || typeof row !== "object") continue;
911
+ if (normalizeTenantId(row.tenantId ?? DEFAULT_TENANT_ID) !== tenantId) continue;
912
+ if (String(row.payerAgentId ?? "") !== String(agentId)) continue;
913
+ const lockedAt = row.lockedAt ?? null;
914
+ const lockedMs = typeof lockedAt === "string" ? Date.parse(lockedAt) : NaN;
915
+ if (!Number.isFinite(lockedMs) || lockedMs < startMs || lockedMs >= endMs) continue;
916
+ const amountCents = Number(row.amountCents ?? 0);
917
+ if (!Number.isSafeInteger(amountCents) || amountCents <= 0) continue;
918
+ total += amountCents;
919
+ }
920
+
921
+ // Tool-call holds lock escrow for the holdback amount only.
922
+ for (const row of store.toolCallHolds.values()) {
923
+ if (!row || typeof row !== "object") continue;
924
+ if (normalizeTenantId(row.tenantId ?? DEFAULT_TENANT_ID) !== tenantId) continue;
925
+ if (String(row.payerAgentId ?? "") !== String(agentId)) continue;
926
+ const createdAt = row.createdAt ?? null;
927
+ const createdMs = typeof createdAt === "string" ? Date.parse(createdAt) : NaN;
928
+ if (!Number.isFinite(createdMs) || createdMs < startMs || createdMs >= endMs) continue;
929
+ const heldAmountCents = Number(row.heldAmountCents ?? 0);
930
+ if (!Number.isSafeInteger(heldAmountCents) || heldAmountCents <= 0) continue;
931
+ total += heldAmountCents;
932
+ }
933
+
934
+ return total;
935
+ };
936
+
785
937
  store.getArbitrationCase = async function getArbitrationCase({ tenantId = DEFAULT_TENANT_ID, caseId } = {}) {
786
938
  tenantId = normalizeTenantId(tenantId);
787
939
  if (typeof caseId !== "string" || caseId.trim() === "") throw new TypeError("caseId is required");
788
940
  return store.arbitrationCases.get(makeScopedKey({ tenantId, id: String(caseId) })) ?? null;
789
941
  };
790
942
 
943
+ store.getAgreementDelegation = async function getAgreementDelegation({ tenantId = DEFAULT_TENANT_ID, delegationId } = {}) {
944
+ tenantId = normalizeTenantId(tenantId);
945
+ if (typeof delegationId !== "string" || delegationId.trim() === "") throw new TypeError("delegationId is required");
946
+ return store.agreementDelegations.get(makeScopedKey({ tenantId, id: String(delegationId) })) ?? null;
947
+ };
948
+
949
+ store.putAgreementDelegation = async function putAgreementDelegation({ tenantId = DEFAULT_TENANT_ID, delegation, audit = null } = {}) {
950
+ tenantId = normalizeTenantId(tenantId);
951
+ if (!delegation || typeof delegation !== "object" || Array.isArray(delegation)) throw new TypeError("delegation is required");
952
+ const delegationId = delegation.delegationId ?? null;
953
+ if (typeof delegationId !== "string" || delegationId.trim() === "") throw new TypeError("delegation.delegationId is required");
954
+ const key = makeScopedKey({ tenantId, id: String(delegationId) });
955
+ const at = delegation.updatedAt ?? new Date().toISOString();
956
+ await store.commitTx({ at, ops: [{ kind: "AGREEMENT_DELEGATION_UPSERT", tenantId, delegationId, delegation: { ...delegation, tenantId, delegationId } }], audit });
957
+ return store.agreementDelegations.get(key) ?? null;
958
+ };
959
+
960
+ store.listAgreementDelegations = async function listAgreementDelegations({
961
+ tenantId = DEFAULT_TENANT_ID,
962
+ parentAgreementHash = null,
963
+ childAgreementHash = null,
964
+ status = null,
965
+ limit = 200,
966
+ offset = 0
967
+ } = {}) {
968
+ tenantId = normalizeTenantId(tenantId);
969
+ if (parentAgreementHash !== null && (typeof parentAgreementHash !== "string" || parentAgreementHash.trim() === "")) {
970
+ throw new TypeError("parentAgreementHash must be null or a non-empty string");
971
+ }
972
+ if (childAgreementHash !== null && (typeof childAgreementHash !== "string" || childAgreementHash.trim() === "")) {
973
+ throw new TypeError("childAgreementHash must be null or a non-empty string");
974
+ }
975
+ if (status !== null && (typeof status !== "string" || status.trim() === "")) throw new TypeError("status must be null or a non-empty string");
976
+ if (!Number.isSafeInteger(limit) || limit <= 0) throw new TypeError("limit must be a positive safe integer");
977
+ if (!Number.isSafeInteger(offset) || offset < 0) throw new TypeError("offset must be a non-negative safe integer");
978
+
979
+ const statusFilter = status ? String(status).trim().toLowerCase() : null;
980
+ const parentFilter = parentAgreementHash ? String(parentAgreementHash).trim().toLowerCase() : null;
981
+ const childFilter = childAgreementHash ? String(childAgreementHash).trim().toLowerCase() : null;
982
+ const safeLimit = Math.min(1000, limit);
983
+ const safeOffset = offset;
984
+ const out = [];
985
+ for (const row of store.agreementDelegations.values()) {
986
+ if (!row || typeof row !== "object") continue;
987
+ if (normalizeTenantId(row.tenantId ?? DEFAULT_TENANT_ID) !== tenantId) continue;
988
+ if (parentFilter && String(row.parentAgreementHash ?? "").toLowerCase() !== parentFilter) continue;
989
+ if (childFilter && String(row.childAgreementHash ?? "").toLowerCase() !== childFilter) continue;
990
+ if (statusFilter !== null && String(row.status ?? "").toLowerCase() !== statusFilter) continue;
991
+ out.push(row);
992
+ }
993
+ out.sort((left, right) => String(left.delegationId ?? "").localeCompare(String(right.delegationId ?? "")));
994
+ return out.slice(safeOffset, safeOffset + safeLimit);
995
+ };
996
+
997
+ store.getX402Gate = async function getX402Gate({ tenantId = DEFAULT_TENANT_ID, gateId } = {}) {
998
+ tenantId = normalizeTenantId(tenantId);
999
+ if (typeof gateId !== "string" || gateId.trim() === "") throw new TypeError("gateId is required");
1000
+ return store.x402Gates.get(makeScopedKey({ tenantId, id: String(gateId) })) ?? null;
1001
+ };
1002
+
1003
+ store.putX402Gate = async function putX402Gate({ tenantId = DEFAULT_TENANT_ID, gate, audit = null } = {}) {
1004
+ tenantId = normalizeTenantId(tenantId);
1005
+ if (!gate || typeof gate !== "object" || Array.isArray(gate)) throw new TypeError("gate is required");
1006
+ const gateId = gate.gateId ?? gate.id ?? null;
1007
+ if (typeof gateId !== "string" || gateId.trim() === "") throw new TypeError("gate.gateId is required");
1008
+ const key = makeScopedKey({ tenantId, id: String(gateId) });
1009
+ const at = gate.updatedAt ?? gate.createdAt ?? new Date().toISOString();
1010
+ await store.commitTx({ at, ops: [{ kind: "X402_GATE_UPSERT", tenantId, gateId, gate: { ...gate, tenantId, gateId: String(gateId) } }], audit });
1011
+ return store.x402Gates.get(key) ?? null;
1012
+ };
1013
+
1014
+ store.putX402AgentLifecycle = async function putX402AgentLifecycle({ tenantId = DEFAULT_TENANT_ID, agentLifecycle, audit = null } = {}) {
1015
+ tenantId = normalizeTenantId(tenantId);
1016
+ if (!agentLifecycle || typeof agentLifecycle !== "object" || Array.isArray(agentLifecycle)) {
1017
+ throw new TypeError("agentLifecycle is required");
1018
+ }
1019
+ const agentId = typeof agentLifecycle.agentId === "string" ? agentLifecycle.agentId.trim() : "";
1020
+ if (!agentId) throw new TypeError("agentLifecycle.agentId is required");
1021
+ const status = typeof agentLifecycle.status === "string" ? agentLifecycle.status.trim().toLowerCase() : "";
1022
+ if (status !== "active" && status !== "frozen" && status !== "archived") {
1023
+ throw new TypeError("agentLifecycle.status must be active|frozen|archived");
1024
+ }
1025
+ const at = agentLifecycle.updatedAt ?? agentLifecycle.createdAt ?? new Date().toISOString();
1026
+ await store.commitTx({
1027
+ at,
1028
+ ops: [
1029
+ {
1030
+ kind: "X402_AGENT_LIFECYCLE_UPSERT",
1031
+ tenantId,
1032
+ agentId,
1033
+ agentLifecycle: { ...agentLifecycle, tenantId, agentId, status }
1034
+ }
1035
+ ],
1036
+ audit
1037
+ });
1038
+ return store.x402AgentLifecycles.get(makeScopedKey({ tenantId, id: agentId })) ?? null;
1039
+ };
1040
+
1041
+ store.getX402AgentLifecycle = async function getX402AgentLifecycle({ tenantId = DEFAULT_TENANT_ID, agentId } = {}) {
1042
+ tenantId = normalizeTenantId(tenantId);
1043
+ if (typeof agentId !== "string" || agentId.trim() === "") throw new TypeError("agentId is required");
1044
+ return store.x402AgentLifecycles.get(makeScopedKey({ tenantId, id: String(agentId) })) ?? null;
1045
+ };
1046
+
1047
+ function x402WalletPolicyStoreKey({ tenantId, sponsorWalletRef, policyRef, policyVersion }) {
1048
+ const normalizedTenantId = normalizeTenantId(tenantId ?? DEFAULT_TENANT_ID);
1049
+ const normalizedSponsorWalletRef = typeof sponsorWalletRef === "string" ? sponsorWalletRef.trim() : "";
1050
+ const normalizedPolicyRef = typeof policyRef === "string" ? policyRef.trim() : "";
1051
+ const normalizedPolicyVersion = Number(policyVersion);
1052
+ if (!normalizedSponsorWalletRef) throw new TypeError("sponsorWalletRef is required");
1053
+ if (!normalizedPolicyRef) throw new TypeError("policyRef is required");
1054
+ if (!Number.isSafeInteger(normalizedPolicyVersion) || normalizedPolicyVersion <= 0) {
1055
+ throw new TypeError("policyVersion must be a positive safe integer");
1056
+ }
1057
+ return makeScopedKey({
1058
+ tenantId: normalizedTenantId,
1059
+ id: `${normalizedSponsorWalletRef}::${normalizedPolicyRef}::${normalizedPolicyVersion}`
1060
+ });
1061
+ }
1062
+
1063
+ function x402WebhookEndpointStoreKey({ tenantId, endpointId }) {
1064
+ const normalizedTenantId = normalizeTenantId(tenantId ?? DEFAULT_TENANT_ID);
1065
+ const normalizedEndpointId = typeof endpointId === "string" ? endpointId.trim() : "";
1066
+ if (!normalizedEndpointId) throw new TypeError("endpointId is required");
1067
+ return makeScopedKey({ tenantId: normalizedTenantId, id: normalizedEndpointId });
1068
+ }
1069
+
1070
+ function x402ZkVerificationKeyStoreKey({ tenantId, verificationKeyId }) {
1071
+ const normalizedTenantId = normalizeTenantId(tenantId ?? DEFAULT_TENANT_ID);
1072
+ const normalizedVerificationKeyId = typeof verificationKeyId === "string" ? verificationKeyId.trim() : "";
1073
+ if (!normalizedVerificationKeyId) throw new TypeError("verificationKeyId is required");
1074
+ return makeScopedKey({ tenantId: normalizedTenantId, id: normalizedVerificationKeyId });
1075
+ }
1076
+
1077
+ store.putX402WalletPolicy = async function putX402WalletPolicy({ tenantId = DEFAULT_TENANT_ID, policy, audit = null } = {}) {
1078
+ tenantId = normalizeTenantId(tenantId);
1079
+ if (!policy || typeof policy !== "object" || Array.isArray(policy)) throw new TypeError("policy is required");
1080
+ const sponsorWalletRef = typeof policy.sponsorWalletRef === "string" ? policy.sponsorWalletRef.trim() : "";
1081
+ const policyRef = typeof policy.policyRef === "string" ? policy.policyRef.trim() : "";
1082
+ const policyVersion = Number(policy.policyVersion);
1083
+ if (!sponsorWalletRef) throw new TypeError("policy.sponsorWalletRef is required");
1084
+ if (!policyRef) throw new TypeError("policy.policyRef is required");
1085
+ if (!Number.isSafeInteger(policyVersion) || policyVersion <= 0) throw new TypeError("policy.policyVersion must be a positive safe integer");
1086
+ const key = x402WalletPolicyStoreKey({ tenantId, sponsorWalletRef, policyRef, policyVersion });
1087
+ const at = policy.updatedAt ?? policy.createdAt ?? new Date().toISOString();
1088
+ await store.commitTx({
1089
+ at,
1090
+ ops: [
1091
+ {
1092
+ kind: "X402_WALLET_POLICY_UPSERT",
1093
+ tenantId,
1094
+ policy: { ...policy, tenantId, sponsorWalletRef, policyRef, policyVersion }
1095
+ }
1096
+ ],
1097
+ audit
1098
+ });
1099
+ return store.x402WalletPolicies.get(key) ?? null;
1100
+ };
1101
+
1102
+ store.getX402WalletPolicy = async function getX402WalletPolicy({
1103
+ tenantId = DEFAULT_TENANT_ID,
1104
+ sponsorWalletRef,
1105
+ policyRef,
1106
+ policyVersion
1107
+ } = {}) {
1108
+ tenantId = normalizeTenantId(tenantId);
1109
+ const key = x402WalletPolicyStoreKey({ tenantId, sponsorWalletRef, policyRef, policyVersion });
1110
+ return store.x402WalletPolicies.get(key) ?? null;
1111
+ };
1112
+
1113
+ store.listX402WalletPolicies = async function listX402WalletPolicies({
1114
+ tenantId = DEFAULT_TENANT_ID,
1115
+ sponsorWalletRef = null,
1116
+ sponsorRef = null,
1117
+ policyRef = null,
1118
+ status = null,
1119
+ limit = 200,
1120
+ offset = 0
1121
+ } = {}) {
1122
+ tenantId = normalizeTenantId(tenantId);
1123
+ if (sponsorWalletRef !== null && (typeof sponsorWalletRef !== "string" || sponsorWalletRef.trim() === "")) {
1124
+ throw new TypeError("sponsorWalletRef must be null or a non-empty string");
1125
+ }
1126
+ if (sponsorRef !== null && (typeof sponsorRef !== "string" || sponsorRef.trim() === "")) {
1127
+ throw new TypeError("sponsorRef must be null or a non-empty string");
1128
+ }
1129
+ if (policyRef !== null && (typeof policyRef !== "string" || policyRef.trim() === "")) {
1130
+ throw new TypeError("policyRef must be null or a non-empty string");
1131
+ }
1132
+ if (status !== null && (typeof status !== "string" || status.trim() === "")) {
1133
+ throw new TypeError("status must be null or a non-empty string");
1134
+ }
1135
+ if (!Number.isSafeInteger(limit) || limit <= 0) throw new TypeError("limit must be a positive safe integer");
1136
+ if (!Number.isSafeInteger(offset) || offset < 0) throw new TypeError("offset must be a non-negative safe integer");
1137
+
1138
+ const sponsorWalletFilter = sponsorWalletRef ? sponsorWalletRef.trim() : null;
1139
+ const sponsorFilter = sponsorRef ? sponsorRef.trim() : null;
1140
+ const policyFilter = policyRef ? policyRef.trim() : null;
1141
+ const statusFilter = status ? status.trim().toLowerCase() : null;
1142
+ const out = [];
1143
+ for (const row of store.x402WalletPolicies.values()) {
1144
+ if (!row || typeof row !== "object" || Array.isArray(row)) continue;
1145
+ if (normalizeTenantId(row.tenantId ?? DEFAULT_TENANT_ID) !== tenantId) continue;
1146
+ if (sponsorWalletFilter && String(row.sponsorWalletRef ?? "") !== sponsorWalletFilter) continue;
1147
+ if (sponsorFilter && String(row.sponsorRef ?? "") !== sponsorFilter) continue;
1148
+ if (policyFilter && String(row.policyRef ?? "") !== policyFilter) continue;
1149
+ if (statusFilter && String(row.status ?? "").toLowerCase() !== statusFilter) continue;
1150
+ out.push(row);
1151
+ }
1152
+ out.sort((left, right) => {
1153
+ const leftAt = Number.isFinite(Date.parse(String(left?.updatedAt ?? ""))) ? Date.parse(String(left.updatedAt)) : Number.NaN;
1154
+ const rightAt = Number.isFinite(Date.parse(String(right?.updatedAt ?? ""))) ? Date.parse(String(right.updatedAt)) : Number.NaN;
1155
+ if (Number.isFinite(leftAt) && Number.isFinite(rightAt) && rightAt !== leftAt) return rightAt - leftAt;
1156
+ const sponsorOrder = String(left?.sponsorWalletRef ?? "").localeCompare(String(right?.sponsorWalletRef ?? ""));
1157
+ if (sponsorOrder !== 0) return sponsorOrder;
1158
+ const policyOrder = String(left?.policyRef ?? "").localeCompare(String(right?.policyRef ?? ""));
1159
+ if (policyOrder !== 0) return policyOrder;
1160
+ return Number(right?.policyVersion ?? 0) - Number(left?.policyVersion ?? 0);
1161
+ });
1162
+ return out.slice(offset, offset + Math.min(1000, limit));
1163
+ };
1164
+
1165
+ store.putX402ZkVerificationKey = async function putX402ZkVerificationKey({
1166
+ tenantId = DEFAULT_TENANT_ID,
1167
+ verificationKey,
1168
+ audit = null
1169
+ } = {}) {
1170
+ tenantId = normalizeTenantId(tenantId);
1171
+ if (!verificationKey || typeof verificationKey !== "object" || Array.isArray(verificationKey)) {
1172
+ throw new TypeError("verificationKey is required");
1173
+ }
1174
+ const verificationKeyId = typeof verificationKey.verificationKeyId === "string" ? verificationKey.verificationKeyId.trim() : "";
1175
+ if (!verificationKeyId) throw new TypeError("verificationKey.verificationKeyId is required");
1176
+ const key = x402ZkVerificationKeyStoreKey({ tenantId, verificationKeyId });
1177
+ const at = verificationKey.updatedAt ?? verificationKey.createdAt ?? new Date().toISOString();
1178
+ await store.commitTx({
1179
+ at,
1180
+ ops: [
1181
+ {
1182
+ kind: "X402_ZK_VERIFICATION_KEY_PUT",
1183
+ tenantId,
1184
+ verificationKeyId,
1185
+ verificationKey: { ...verificationKey, tenantId, verificationKeyId }
1186
+ }
1187
+ ],
1188
+ audit
1189
+ });
1190
+ return store.x402ZkVerificationKeys.get(key) ?? null;
1191
+ };
1192
+
1193
+ store.getX402ZkVerificationKey = async function getX402ZkVerificationKey({
1194
+ tenantId = DEFAULT_TENANT_ID,
1195
+ verificationKeyId
1196
+ } = {}) {
1197
+ tenantId = normalizeTenantId(tenantId);
1198
+ return store.x402ZkVerificationKeys.get(x402ZkVerificationKeyStoreKey({ tenantId, verificationKeyId })) ?? null;
1199
+ };
1200
+
1201
+ store.listX402ZkVerificationKeys = async function listX402ZkVerificationKeys({
1202
+ tenantId = DEFAULT_TENANT_ID,
1203
+ protocol = null,
1204
+ providerRef = null,
1205
+ limit = 200,
1206
+ offset = 0
1207
+ } = {}) {
1208
+ tenantId = normalizeTenantId(tenantId);
1209
+ if (protocol !== null && (typeof protocol !== "string" || protocol.trim() === "")) {
1210
+ throw new TypeError("protocol must be null or a non-empty string");
1211
+ }
1212
+ if (providerRef !== null && (typeof providerRef !== "string" || providerRef.trim() === "")) {
1213
+ throw new TypeError("providerRef must be null or a non-empty string");
1214
+ }
1215
+ if (!Number.isSafeInteger(limit) || limit <= 0) throw new TypeError("limit must be a positive safe integer");
1216
+ if (!Number.isSafeInteger(offset) || offset < 0) throw new TypeError("offset must be a non-negative safe integer");
1217
+ const protocolFilter = protocol ? protocol.trim().toLowerCase() : null;
1218
+ const providerRefFilter = providerRef ? providerRef.trim() : null;
1219
+ const out = [];
1220
+ for (const row of store.x402ZkVerificationKeys.values()) {
1221
+ if (!row || typeof row !== "object" || Array.isArray(row)) continue;
1222
+ if (normalizeTenantId(row.tenantId ?? DEFAULT_TENANT_ID) !== tenantId) continue;
1223
+ if (protocolFilter && String(row.protocol ?? "").trim().toLowerCase() !== protocolFilter) continue;
1224
+ if (providerRefFilter && String(row.providerRef ?? "") !== providerRefFilter) continue;
1225
+ out.push(row);
1226
+ }
1227
+ out.sort((left, right) => {
1228
+ const leftAt = Number.isFinite(Date.parse(String(left?.createdAt ?? ""))) ? Date.parse(String(left.createdAt)) : Number.NaN;
1229
+ const rightAt = Number.isFinite(Date.parse(String(right?.createdAt ?? ""))) ? Date.parse(String(right.createdAt)) : Number.NaN;
1230
+ if (Number.isFinite(leftAt) && Number.isFinite(rightAt) && rightAt !== leftAt) return rightAt - leftAt;
1231
+ return String(left?.verificationKeyId ?? "").localeCompare(String(right?.verificationKeyId ?? ""));
1232
+ });
1233
+ return out.slice(offset, offset + Math.min(1000, limit));
1234
+ };
1235
+
1236
+ store.putX402WebhookEndpoint = async function putX402WebhookEndpoint({ tenantId = DEFAULT_TENANT_ID, endpoint, audit = null } = {}) {
1237
+ tenantId = normalizeTenantId(tenantId);
1238
+ if (!endpoint || typeof endpoint !== "object" || Array.isArray(endpoint)) throw new TypeError("endpoint is required");
1239
+ const endpointId = typeof endpoint.endpointId === "string" ? endpoint.endpointId.trim() : "";
1240
+ if (!endpointId) throw new TypeError("endpoint.endpointId is required");
1241
+ const at = endpoint.updatedAt ?? endpoint.createdAt ?? new Date().toISOString();
1242
+ await store.commitTx({
1243
+ at,
1244
+ ops: [{ kind: "X402_WEBHOOK_ENDPOINT_UPSERT", tenantId, endpointId, endpoint: { ...endpoint, tenantId, endpointId } }],
1245
+ audit
1246
+ });
1247
+ return store.x402WebhookEndpoints.get(x402WebhookEndpointStoreKey({ tenantId, endpointId })) ?? null;
1248
+ };
1249
+
1250
+ store.getX402WebhookEndpoint = async function getX402WebhookEndpoint({ tenantId = DEFAULT_TENANT_ID, endpointId } = {}) {
1251
+ tenantId = normalizeTenantId(tenantId);
1252
+ return store.x402WebhookEndpoints.get(x402WebhookEndpointStoreKey({ tenantId, endpointId })) ?? null;
1253
+ };
1254
+
1255
+ store.listX402WebhookEndpoints = async function listX402WebhookEndpoints({
1256
+ tenantId = DEFAULT_TENANT_ID,
1257
+ endpointId = null,
1258
+ destinationId = null,
1259
+ status = null,
1260
+ event = null,
1261
+ limit = 200,
1262
+ offset = 0
1263
+ } = {}) {
1264
+ tenantId = normalizeTenantId(tenantId);
1265
+ if (endpointId !== null && (typeof endpointId !== "string" || endpointId.trim() === "")) {
1266
+ throw new TypeError("endpointId must be null or a non-empty string");
1267
+ }
1268
+ if (destinationId !== null && (typeof destinationId !== "string" || destinationId.trim() === "")) {
1269
+ throw new TypeError("destinationId must be null or a non-empty string");
1270
+ }
1271
+ if (status !== null && (typeof status !== "string" || status.trim() === "")) {
1272
+ throw new TypeError("status must be null or a non-empty string");
1273
+ }
1274
+ if (event !== null && (typeof event !== "string" || event.trim() === "")) {
1275
+ throw new TypeError("event must be null or a non-empty string");
1276
+ }
1277
+ if (!Number.isSafeInteger(limit) || limit <= 0) throw new TypeError("limit must be a positive safe integer");
1278
+ if (!Number.isSafeInteger(offset) || offset < 0) throw new TypeError("offset must be a non-negative safe integer");
1279
+
1280
+ const endpointFilter = endpointId ? endpointId.trim() : null;
1281
+ const destinationFilter = destinationId ? destinationId.trim() : null;
1282
+ const statusFilter = status ? status.trim().toLowerCase() : null;
1283
+ const eventFilter = event ? event.trim().toLowerCase() : null;
1284
+ const out = [];
1285
+ for (const row of store.x402WebhookEndpoints.values()) {
1286
+ if (!row || typeof row !== "object" || Array.isArray(row)) continue;
1287
+ if (normalizeTenantId(row.tenantId ?? DEFAULT_TENANT_ID) !== tenantId) continue;
1288
+ if (endpointFilter && String(row.endpointId ?? "") !== endpointFilter) continue;
1289
+ if (destinationFilter && String(row.destinationId ?? "") !== destinationFilter) continue;
1290
+ if (statusFilter && String(row.status ?? "").toLowerCase() !== statusFilter) continue;
1291
+ if (eventFilter) {
1292
+ const events = Array.isArray(row.events) ? row.events.map((value) => String(value).trim().toLowerCase()) : [];
1293
+ if (!events.includes(eventFilter)) continue;
1294
+ }
1295
+ out.push(row);
1296
+ }
1297
+ out.sort((left, right) => {
1298
+ const leftAt = Number.isFinite(Date.parse(String(left?.updatedAt ?? ""))) ? Date.parse(String(left.updatedAt)) : Number.NaN;
1299
+ const rightAt = Number.isFinite(Date.parse(String(right?.updatedAt ?? ""))) ? Date.parse(String(right.updatedAt)) : Number.NaN;
1300
+ if (Number.isFinite(leftAt) && Number.isFinite(rightAt) && rightAt !== leftAt) return rightAt - leftAt;
1301
+ return String(left?.endpointId ?? "").localeCompare(String(right?.endpointId ?? ""));
1302
+ });
1303
+ return out.slice(offset, offset + Math.min(1000, limit));
1304
+ };
1305
+
1306
+ store.recordX402WebhookEndpointDeliveryResult = async function recordX402WebhookEndpointDeliveryResult({
1307
+ tenantId = DEFAULT_TENANT_ID,
1308
+ destinationId,
1309
+ deliveredAt = new Date().toISOString(),
1310
+ success,
1311
+ failureReason = null,
1312
+ statusCode = null,
1313
+ autoDisableThreshold = null,
1314
+ audit = null
1315
+ } = {}) {
1316
+ tenantId = normalizeTenantId(tenantId);
1317
+ if (typeof destinationId !== "string" || destinationId.trim() === "") throw new TypeError("destinationId is required");
1318
+ const matched = await store.listX402WebhookEndpoints({ tenantId, destinationId: destinationId.trim(), limit: 1, offset: 0 });
1319
+ const endpoint = Array.isArray(matched) && matched.length > 0 ? matched[0] : null;
1320
+ if (!endpoint) return null;
1321
+ if (String(endpoint.status ?? "").toLowerCase() === "revoked") return endpoint;
1322
+ const thresholdRaw = autoDisableThreshold ?? store.x402WebhookAutoDisableFailures ?? 10;
1323
+ const threshold = Number.isSafeInteger(Number(thresholdRaw)) && Number(thresholdRaw) > 0 ? Number(thresholdRaw) : 10;
1324
+ const next = {
1325
+ ...endpoint,
1326
+ updatedAt: deliveredAt,
1327
+ lastDeliveryAt: deliveredAt
1328
+ };
1329
+ if (success) {
1330
+ next.consecutiveFailures = 0;
1331
+ next.lastFailureReason = null;
1332
+ next.lastFailureAt = null;
1333
+ next.lastFailureStatusCode = null;
1334
+ } else {
1335
+ const prevFailures = Number.isSafeInteger(Number(endpoint.consecutiveFailures)) ? Number(endpoint.consecutiveFailures) : 0;
1336
+ next.consecutiveFailures = prevFailures + 1;
1337
+ next.lastFailureReason = failureReason ? String(failureReason) : "delivery_failed";
1338
+ next.lastFailureAt = deliveredAt;
1339
+ next.lastFailureStatusCode = Number.isSafeInteger(Number(statusCode)) ? Number(statusCode) : null;
1340
+ if (String(endpoint.status ?? "").toLowerCase() === "active" && next.consecutiveFailures >= threshold) {
1341
+ next.status = "disabled";
1342
+ next.disabledAt = deliveredAt;
1343
+ }
1344
+ }
1345
+ return store.putX402WebhookEndpoint({ tenantId, endpoint: next, audit });
1346
+ };
1347
+
1348
+ function x402ReversalNonceStoreKey({ tenantId, sponsorRef, nonce }) {
1349
+ const normalizedTenantId = normalizeTenantId(tenantId ?? DEFAULT_TENANT_ID);
1350
+ const normalizedSponsorRef = typeof sponsorRef === "string" ? sponsorRef.trim() : "";
1351
+ const normalizedNonce = typeof nonce === "string" ? nonce.trim() : "";
1352
+ if (!normalizedSponsorRef) throw new TypeError("sponsorRef is required");
1353
+ if (!normalizedNonce) throw new TypeError("nonce is required");
1354
+ return `${normalizedTenantId}\n${normalizedSponsorRef}\n${normalizedNonce}`;
1355
+ }
1356
+
1357
+ store.putX402ReversalEvent = async function putX402ReversalEvent({ tenantId = DEFAULT_TENANT_ID, gateId, event, audit = null } = {}) {
1358
+ tenantId = normalizeTenantId(tenantId);
1359
+ if (typeof gateId !== "string" || gateId.trim() === "") throw new TypeError("gateId is required");
1360
+ if (!event || typeof event !== "object" || Array.isArray(event)) throw new TypeError("event is required");
1361
+ const eventId = event.eventId ?? event.id ?? null;
1362
+ if (typeof eventId !== "string" || eventId.trim() === "") throw new TypeError("event.eventId is required");
1363
+ const at = event.occurredAt ?? event.createdAt ?? new Date().toISOString();
1364
+ await store.commitTx({
1365
+ at,
1366
+ ops: [{ kind: "X402_REVERSAL_EVENT_APPEND", tenantId, gateId: String(gateId), eventId: String(eventId), event: { ...event, tenantId, gateId: String(gateId), eventId: String(eventId) } }],
1367
+ audit
1368
+ });
1369
+ return store.x402ReversalEvents.get(makeScopedKey({ tenantId, id: String(eventId) })) ?? null;
1370
+ };
1371
+
1372
+ store.getX402ReversalEvent = async function getX402ReversalEvent({ tenantId = DEFAULT_TENANT_ID, eventId } = {}) {
1373
+ tenantId = normalizeTenantId(tenantId);
1374
+ if (typeof eventId !== "string" || eventId.trim() === "") throw new TypeError("eventId is required");
1375
+ return store.x402ReversalEvents.get(makeScopedKey({ tenantId, id: String(eventId) })) ?? null;
1376
+ };
1377
+
1378
+ store.listX402ReversalEvents = async function listX402ReversalEvents({
1379
+ tenantId = DEFAULT_TENANT_ID,
1380
+ gateId = null,
1381
+ receiptId = null,
1382
+ action = null,
1383
+ from = null,
1384
+ to = null,
1385
+ limit = 200,
1386
+ offset = 0
1387
+ } = {}) {
1388
+ tenantId = normalizeTenantId(tenantId);
1389
+ if (gateId !== null && (typeof gateId !== "string" || gateId.trim() === "")) throw new TypeError("gateId must be null or a non-empty string");
1390
+ if (receiptId !== null && (typeof receiptId !== "string" || receiptId.trim() === "")) throw new TypeError("receiptId must be null or a non-empty string");
1391
+ if (action !== null && (typeof action !== "string" || action.trim() === "")) throw new TypeError("action must be null or a non-empty string");
1392
+ if (from !== null && !Number.isFinite(Date.parse(String(from)))) throw new TypeError("from must be null or an ISO date-time");
1393
+ if (to !== null && !Number.isFinite(Date.parse(String(to)))) throw new TypeError("to must be null or an ISO date-time");
1394
+ if (!Number.isSafeInteger(limit) || limit <= 0) throw new TypeError("limit must be a positive safe integer");
1395
+ if (!Number.isSafeInteger(offset) || offset < 0) throw new TypeError("offset must be a non-negative safe integer");
1396
+
1397
+ const normalizedGateId = gateId ? gateId.trim() : null;
1398
+ const normalizedReceiptId = receiptId ? receiptId.trim() : null;
1399
+ const normalizedAction = action ? action.trim().toLowerCase() : null;
1400
+ const fromMs = from ? Date.parse(String(from)) : null;
1401
+ const toMs = to ? Date.parse(String(to)) : null;
1402
+
1403
+ const out = [];
1404
+ for (const row of store.x402ReversalEvents.values()) {
1405
+ if (!row || typeof row !== "object" || Array.isArray(row)) continue;
1406
+ if (normalizeTenantId(row.tenantId ?? DEFAULT_TENANT_ID) !== tenantId) continue;
1407
+ if (normalizedGateId && String(row.gateId ?? "") !== normalizedGateId) continue;
1408
+ if (normalizedReceiptId && String(row.receiptId ?? "") !== normalizedReceiptId) continue;
1409
+ if (normalizedAction && String(row.action ?? "").toLowerCase() !== normalizedAction) continue;
1410
+ const occurredAtMs = Number.isFinite(Date.parse(String(row.occurredAt ?? ""))) ? Date.parse(String(row.occurredAt)) : Number.NaN;
1411
+ if (fromMs !== null && (!Number.isFinite(occurredAtMs) || occurredAtMs < fromMs)) continue;
1412
+ if (toMs !== null && (!Number.isFinite(occurredAtMs) || occurredAtMs > toMs)) continue;
1413
+ out.push(row);
1414
+ }
1415
+ out.sort((left, right) => {
1416
+ const leftMs = Number.isFinite(Date.parse(String(left?.occurredAt ?? ""))) ? Date.parse(String(left.occurredAt)) : Number.NaN;
1417
+ const rightMs = Number.isFinite(Date.parse(String(right?.occurredAt ?? ""))) ? Date.parse(String(right.occurredAt)) : Number.NaN;
1418
+ if (Number.isFinite(leftMs) && Number.isFinite(rightMs) && leftMs !== rightMs) return rightMs - leftMs;
1419
+ return String(left?.eventId ?? "").localeCompare(String(right?.eventId ?? ""));
1420
+ });
1421
+ return out.slice(offset, offset + Math.min(1000, limit));
1422
+ };
1423
+
1424
+ store.putX402ReversalNonceUsage = async function putX402ReversalNonceUsage({ tenantId = DEFAULT_TENANT_ID, usage, audit = null } = {}) {
1425
+ tenantId = normalizeTenantId(tenantId);
1426
+ if (!usage || typeof usage !== "object" || Array.isArray(usage)) throw new TypeError("usage is required");
1427
+ const sponsorRef = typeof usage.sponsorRef === "string" ? usage.sponsorRef.trim() : "";
1428
+ const nonce = typeof usage.nonce === "string" ? usage.nonce.trim() : "";
1429
+ if (!sponsorRef) throw new TypeError("usage.sponsorRef is required");
1430
+ if (!nonce) throw new TypeError("usage.nonce is required");
1431
+ const at = usage.usedAt ?? new Date().toISOString();
1432
+ await store.commitTx({
1433
+ at,
1434
+ ops: [{ kind: "X402_REVERSAL_NONCE_PUT", tenantId, sponsorRef, nonce, usage: { ...usage, tenantId, sponsorRef, nonce } }],
1435
+ audit
1436
+ });
1437
+ return store.x402ReversalNonceUsage.get(x402ReversalNonceStoreKey({ tenantId, sponsorRef, nonce })) ?? null;
1438
+ };
1439
+
1440
+ store.getX402ReversalNonceUsage = async function getX402ReversalNonceUsage({ tenantId = DEFAULT_TENANT_ID, sponsorRef, nonce } = {}) {
1441
+ tenantId = normalizeTenantId(tenantId);
1442
+ return store.x402ReversalNonceUsage.get(x402ReversalNonceStoreKey({ tenantId, sponsorRef, nonce })) ?? null;
1443
+ };
1444
+
1445
+ store.putX402ReversalCommandUsage = async function putX402ReversalCommandUsage({ tenantId = DEFAULT_TENANT_ID, usage, audit = null } = {}) {
1446
+ tenantId = normalizeTenantId(tenantId);
1447
+ if (!usage || typeof usage !== "object" || Array.isArray(usage)) throw new TypeError("usage is required");
1448
+ const commandId = typeof usage.commandId === "string" ? usage.commandId.trim() : "";
1449
+ if (!commandId) throw new TypeError("usage.commandId is required");
1450
+ const at = usage.usedAt ?? new Date().toISOString();
1451
+ await store.commitTx({
1452
+ at,
1453
+ ops: [{ kind: "X402_REVERSAL_COMMAND_PUT", tenantId, commandId, usage: { ...usage, tenantId, commandId } }],
1454
+ audit
1455
+ });
1456
+ return store.x402ReversalCommandUsage.get(makeScopedKey({ tenantId, id: commandId })) ?? null;
1457
+ };
1458
+
1459
+ store.getX402ReversalCommandUsage = async function getX402ReversalCommandUsage({ tenantId = DEFAULT_TENANT_ID, commandId } = {}) {
1460
+ tenantId = normalizeTenantId(tenantId);
1461
+ if (typeof commandId !== "string" || commandId.trim() === "") throw new TypeError("commandId is required");
1462
+ return store.x402ReversalCommandUsage.get(makeScopedKey({ tenantId, id: commandId.trim() })) ?? null;
1463
+ };
1464
+
1465
+ store.putX402Escalation = async function putX402Escalation({ tenantId = DEFAULT_TENANT_ID, escalation, audit = null } = {}) {
1466
+ tenantId = normalizeTenantId(tenantId);
1467
+ if (!escalation || typeof escalation !== "object" || Array.isArray(escalation)) throw new TypeError("escalation is required");
1468
+ const escalationId = typeof escalation.escalationId === "string" ? escalation.escalationId.trim() : "";
1469
+ if (!escalationId) throw new TypeError("escalation.escalationId is required");
1470
+ const at = escalation.updatedAt ?? escalation.createdAt ?? new Date().toISOString();
1471
+ await store.commitTx({
1472
+ at,
1473
+ ops: [{ kind: "X402_ESCALATION_UPSERT", tenantId, escalationId, escalation: { ...escalation, tenantId, escalationId } }],
1474
+ audit
1475
+ });
1476
+ return store.x402Escalations.get(makeScopedKey({ tenantId, id: escalationId })) ?? null;
1477
+ };
1478
+
1479
+ store.getX402Escalation = async function getX402Escalation({ tenantId = DEFAULT_TENANT_ID, escalationId } = {}) {
1480
+ tenantId = normalizeTenantId(tenantId);
1481
+ if (typeof escalationId !== "string" || escalationId.trim() === "") throw new TypeError("escalationId is required");
1482
+ return store.x402Escalations.get(makeScopedKey({ tenantId, id: escalationId.trim() })) ?? null;
1483
+ };
1484
+
1485
+ store.listX402Escalations = async function listX402Escalations({
1486
+ tenantId = DEFAULT_TENANT_ID,
1487
+ gateId = null,
1488
+ agentId = null,
1489
+ status = null,
1490
+ limit = 200,
1491
+ offset = 0
1492
+ } = {}) {
1493
+ tenantId = normalizeTenantId(tenantId);
1494
+ if (gateId !== null && (typeof gateId !== "string" || gateId.trim() === "")) throw new TypeError("gateId must be null or a non-empty string");
1495
+ if (agentId !== null && (typeof agentId !== "string" || agentId.trim() === "")) throw new TypeError("agentId must be null or a non-empty string");
1496
+ if (status !== null && (typeof status !== "string" || status.trim() === "")) throw new TypeError("status must be null or a non-empty string");
1497
+ if (!Number.isSafeInteger(limit) || limit <= 0) throw new TypeError("limit must be a positive safe integer");
1498
+ if (!Number.isSafeInteger(offset) || offset < 0) throw new TypeError("offset must be a non-negative safe integer");
1499
+
1500
+ const normalizedGateId = gateId ? gateId.trim() : null;
1501
+ const normalizedAgentId = agentId ? agentId.trim() : null;
1502
+ const normalizedStatus = status ? status.trim().toLowerCase() : null;
1503
+ const out = [];
1504
+ for (const row of store.x402Escalations.values()) {
1505
+ if (!row || typeof row !== "object" || Array.isArray(row)) continue;
1506
+ if (normalizeTenantId(row.tenantId ?? DEFAULT_TENANT_ID) !== tenantId) continue;
1507
+ if (normalizedGateId && String(row.gateId ?? "") !== normalizedGateId) continue;
1508
+ if (
1509
+ normalizedAgentId &&
1510
+ String(
1511
+ row.requesterAgentId ??
1512
+ row.payerAgentId ??
1513
+ null
1514
+ ).trim() !== normalizedAgentId
1515
+ ) {
1516
+ continue;
1517
+ }
1518
+ if (normalizedStatus && String(row.status ?? "").toLowerCase() !== normalizedStatus) continue;
1519
+ out.push(row);
1520
+ }
1521
+ out.sort((left, right) => {
1522
+ const leftMs = Number.isFinite(Date.parse(String(left?.updatedAt ?? ""))) ? Date.parse(String(left.updatedAt)) : Number.NaN;
1523
+ const rightMs = Number.isFinite(Date.parse(String(right?.updatedAt ?? ""))) ? Date.parse(String(right.updatedAt)) : Number.NaN;
1524
+ if (Number.isFinite(leftMs) && Number.isFinite(rightMs) && leftMs !== rightMs) return rightMs - leftMs;
1525
+ return String(left?.escalationId ?? "").localeCompare(String(right?.escalationId ?? ""));
1526
+ });
1527
+ return out.slice(offset, offset + Math.min(1000, limit));
1528
+ };
1529
+
1530
+ store.appendX402EscalationEvent = async function appendX402EscalationEvent({ tenantId = DEFAULT_TENANT_ID, event, audit = null } = {}) {
1531
+ tenantId = normalizeTenantId(tenantId);
1532
+ if (!event || typeof event !== "object" || Array.isArray(event)) throw new TypeError("event is required");
1533
+ const eventId = typeof event.eventId === "string" ? event.eventId.trim() : "";
1534
+ const escalationId = typeof event.escalationId === "string" ? event.escalationId.trim() : "";
1535
+ if (!eventId) throw new TypeError("event.eventId is required");
1536
+ if (!escalationId) throw new TypeError("event.escalationId is required");
1537
+ const at = event.occurredAt ?? event.createdAt ?? new Date().toISOString();
1538
+ await store.commitTx({
1539
+ at,
1540
+ ops: [{ kind: "X402_ESCALATION_EVENT_APPEND", tenantId, eventId, escalationId, event: { ...event, tenantId, eventId, escalationId } }],
1541
+ audit
1542
+ });
1543
+ return store.x402EscalationEvents.get(makeScopedKey({ tenantId, id: eventId })) ?? null;
1544
+ };
1545
+
1546
+ store.listX402EscalationEvents = async function listX402EscalationEvents({
1547
+ tenantId = DEFAULT_TENANT_ID,
1548
+ escalationId = null,
1549
+ limit = 200,
1550
+ offset = 0
1551
+ } = {}) {
1552
+ tenantId = normalizeTenantId(tenantId);
1553
+ if (escalationId !== null && (typeof escalationId !== "string" || escalationId.trim() === "")) {
1554
+ throw new TypeError("escalationId must be null or a non-empty string");
1555
+ }
1556
+ if (!Number.isSafeInteger(limit) || limit <= 0) throw new TypeError("limit must be a positive safe integer");
1557
+ if (!Number.isSafeInteger(offset) || offset < 0) throw new TypeError("offset must be a non-negative safe integer");
1558
+ const normalizedEscalationId = escalationId ? escalationId.trim() : null;
1559
+ const out = [];
1560
+ for (const row of store.x402EscalationEvents.values()) {
1561
+ if (!row || typeof row !== "object" || Array.isArray(row)) continue;
1562
+ if (normalizeTenantId(row.tenantId ?? DEFAULT_TENANT_ID) !== tenantId) continue;
1563
+ if (normalizedEscalationId && String(row.escalationId ?? "") !== normalizedEscalationId) continue;
1564
+ out.push(row);
1565
+ }
1566
+ out.sort((left, right) => {
1567
+ const leftMs = Number.isFinite(Date.parse(String(left?.occurredAt ?? ""))) ? Date.parse(String(left.occurredAt)) : Number.NaN;
1568
+ const rightMs = Number.isFinite(Date.parse(String(right?.occurredAt ?? ""))) ? Date.parse(String(right.occurredAt)) : Number.NaN;
1569
+ if (Number.isFinite(leftMs) && Number.isFinite(rightMs) && leftMs !== rightMs) return leftMs - rightMs;
1570
+ return String(left?.eventId ?? "").localeCompare(String(right?.eventId ?? ""));
1571
+ });
1572
+ return out.slice(offset, offset + Math.min(1000, limit));
1573
+ };
1574
+
1575
+ store.putX402EscalationOverrideUsage = async function putX402EscalationOverrideUsage({ tenantId = DEFAULT_TENANT_ID, usage, audit = null } = {}) {
1576
+ tenantId = normalizeTenantId(tenantId);
1577
+ if (!usage || typeof usage !== "object" || Array.isArray(usage)) throw new TypeError("usage is required");
1578
+ const overrideId = typeof usage.overrideId === "string" ? usage.overrideId.trim() : "";
1579
+ if (!overrideId) throw new TypeError("usage.overrideId is required");
1580
+ const at = usage.usedAt ?? new Date().toISOString();
1581
+ await store.commitTx({
1582
+ at,
1583
+ ops: [{ kind: "X402_ESCALATION_OVERRIDE_USAGE_PUT", tenantId, overrideId, usage: { ...usage, tenantId, overrideId } }],
1584
+ audit
1585
+ });
1586
+ return store.x402EscalationOverrideUsage.get(makeScopedKey({ tenantId, id: overrideId })) ?? null;
1587
+ };
1588
+
1589
+ store.getX402EscalationOverrideUsage = async function getX402EscalationOverrideUsage({
1590
+ tenantId = DEFAULT_TENANT_ID,
1591
+ overrideId
1592
+ } = {}) {
1593
+ tenantId = normalizeTenantId(tenantId);
1594
+ if (typeof overrideId !== "string" || overrideId.trim() === "") throw new TypeError("overrideId is required");
1595
+ return store.x402EscalationOverrideUsage.get(makeScopedKey({ tenantId, id: overrideId.trim() })) ?? null;
1596
+ };
1597
+
1598
+ function x402ReceiptStoreKey({ tenantId, receiptId }) {
1599
+ const normalizedTenantId = normalizeTenantId(tenantId ?? DEFAULT_TENANT_ID);
1600
+ const normalizedReceiptId = typeof receiptId === "string" ? receiptId.trim() : "";
1601
+ if (!normalizedReceiptId) throw new TypeError("receiptId is required");
1602
+ return makeScopedKey({ tenantId: normalizedTenantId, id: normalizedReceiptId });
1603
+ }
1604
+
1605
+ function listX402ReversalEventsForReceiptSync({ tenantId = DEFAULT_TENANT_ID, receiptId } = {}) {
1606
+ const normalizedTenantId = normalizeTenantId(tenantId ?? DEFAULT_TENANT_ID);
1607
+ const normalizedReceiptId = typeof receiptId === "string" ? receiptId.trim() : "";
1608
+ if (!normalizedReceiptId) return [];
1609
+ const out = [];
1610
+ for (const row of store.x402ReversalEvents.values()) {
1611
+ if (!row || typeof row !== "object" || Array.isArray(row)) continue;
1612
+ if (normalizeTenantId(row.tenantId ?? DEFAULT_TENANT_ID) !== normalizedTenantId) continue;
1613
+ if (String(row.receiptId ?? "") !== normalizedReceiptId) continue;
1614
+ out.push(row);
1615
+ }
1616
+ out.sort((left, right) => {
1617
+ const leftMs = Number.isFinite(Date.parse(String(left?.occurredAt ?? ""))) ? Date.parse(String(left.occurredAt)) : Number.NaN;
1618
+ const rightMs = Number.isFinite(Date.parse(String(right?.occurredAt ?? ""))) ? Date.parse(String(right.occurredAt)) : Number.NaN;
1619
+ if (Number.isFinite(leftMs) && Number.isFinite(rightMs) && leftMs !== rightMs) return leftMs - rightMs;
1620
+ return String(left?.eventId ?? "").localeCompare(String(right?.eventId ?? ""));
1621
+ });
1622
+ return out;
1623
+ }
1624
+
1625
+ function toX402ReceiptRecord({ tenantId, gate, settlement: settlementInput = null, includeReversalContext = true } = {}) {
1626
+ if (!gate || typeof gate !== "object" || Array.isArray(gate)) return null;
1627
+ const runId = typeof gate.runId === "string" && gate.runId.trim() !== "" ? gate.runId.trim() : null;
1628
+ const settlement =
1629
+ settlementInput && typeof settlementInput === "object" && !Array.isArray(settlementInput)
1630
+ ? settlementInput
1631
+ : runId && store.agentRunSettlements instanceof Map
1632
+ ? store.agentRunSettlements.get(makeScopedKey({ tenantId, id: runId })) ?? null
1633
+ : null;
1634
+ const decisionTrace =
1635
+ settlement?.decisionTrace && typeof settlement.decisionTrace === "object" && !Array.isArray(settlement.decisionTrace)
1636
+ ? settlement.decisionTrace
1637
+ : gate.decisionTrace && typeof gate.decisionTrace === "object" && !Array.isArray(gate.decisionTrace)
1638
+ ? gate.decisionTrace
1639
+ : null;
1640
+ const settlementReceipt =
1641
+ decisionTrace?.settlementReceipt && typeof decisionTrace.settlementReceipt === "object" && !Array.isArray(decisionTrace.settlementReceipt)
1642
+ ? decisionTrace.settlementReceipt
1643
+ : null;
1644
+ if (!settlementReceipt) return null;
1645
+ const receiptId = typeof settlementReceipt.receiptId === "string" ? settlementReceipt.receiptId.trim() : "";
1646
+ if (!receiptId) return null;
1647
+ const bindings =
1648
+ decisionTrace?.bindings && typeof decisionTrace.bindings === "object" && !Array.isArray(decisionTrace.bindings)
1649
+ ? decisionTrace.bindings
1650
+ : null;
1651
+ const verificationContext =
1652
+ gate?.verificationContext && typeof gate.verificationContext === "object" && !Array.isArray(gate.verificationContext)
1653
+ ? gate.verificationContext
1654
+ : gate?.decision?.verificationContext &&
1655
+ typeof gate.decision.verificationContext === "object" &&
1656
+ !Array.isArray(gate.decision.verificationContext)
1657
+ ? gate.decision.verificationContext
1658
+ : null;
1659
+ const sponsorRef =
1660
+ typeof bindings?.spendAuthorization?.sponsorRef === "string" && bindings.spendAuthorization.sponsorRef.trim() !== ""
1661
+ ? bindings.spendAuthorization.sponsorRef.trim()
1662
+ : null;
1663
+ const sponsorWalletRef =
1664
+ typeof bindings?.spendAuthorization?.sponsorWalletRef === "string" && bindings.spendAuthorization.sponsorWalletRef.trim() !== ""
1665
+ ? bindings.spendAuthorization.sponsorWalletRef.trim()
1666
+ : null;
1667
+ const agentKeyId =
1668
+ typeof bindings?.spendAuthorization?.agentKeyId === "string" && bindings.spendAuthorization.agentKeyId.trim() !== ""
1669
+ ? bindings.spendAuthorization.agentKeyId.trim()
1670
+ : null;
1671
+ const settledAt =
1672
+ typeof settlementReceipt.settledAt === "string" && settlementReceipt.settledAt.trim() !== ""
1673
+ ? settlementReceipt.settledAt.trim()
1674
+ : typeof gate.resolvedAt === "string" && gate.resolvedAt.trim() !== ""
1675
+ ? gate.resolvedAt.trim()
1676
+ : null;
1677
+ const base = {
1678
+ schemaVersion: "X402ReceiptRecord.v1",
1679
+ tenantId,
1680
+ receiptId,
1681
+ gateId: typeof gate.gateId === "string" ? gate.gateId : null,
1682
+ runId,
1683
+ payerAgentId: typeof gate.payerAgentId === "string" ? gate.payerAgentId : null,
1684
+ providerId: typeof gate.payeeAgentId === "string" ? gate.payeeAgentId : null,
1685
+ toolId:
1686
+ typeof gate.toolId === "string" && gate.toolId.trim() !== ""
1687
+ ? gate.toolId.trim()
1688
+ : typeof gate?.quote?.toolId === "string" && gate.quote.toolId.trim() !== ""
1689
+ ? gate.quote.toolId.trim()
1690
+ : null,
1691
+ sponsorRef,
1692
+ sponsorWalletRef,
1693
+ agentKeyId,
1694
+ settlementState:
1695
+ typeof settlementReceipt.status === "string" && settlementReceipt.status.trim() !== ""
1696
+ ? settlementReceipt.status.trim().toLowerCase()
1697
+ : typeof settlement?.status === "string" && settlement.status.trim() !== ""
1698
+ ? settlement.status.trim().toLowerCase()
1699
+ : null,
1700
+ verificationStatus:
1701
+ typeof decisionTrace?.verificationStatus === "string" && decisionTrace.verificationStatus.trim() !== ""
1702
+ ? decisionTrace.verificationStatus.trim().toLowerCase()
1703
+ : null,
1704
+ settledAt,
1705
+ createdAt:
1706
+ typeof settlementReceipt.createdAt === "string" && settlementReceipt.createdAt.trim() !== ""
1707
+ ? settlementReceipt.createdAt.trim()
1708
+ : null,
1709
+ updatedAt:
1710
+ typeof gate.updatedAt === "string" && gate.updatedAt.trim() !== ""
1711
+ ? gate.updatedAt.trim()
1712
+ : typeof settledAt === "string"
1713
+ ? settledAt
1714
+ : null,
1715
+ evidenceRefs: Array.isArray(gate.evidenceRefs) ? gate.evidenceRefs.slice() : [],
1716
+ verificationContext,
1717
+ bindings,
1718
+ providerSignature:
1719
+ gate?.providerSignature && typeof gate.providerSignature === "object" && !Array.isArray(gate.providerSignature)
1720
+ ? gate.providerSignature
1721
+ : null,
1722
+ providerQuoteSignature:
1723
+ gate?.providerQuoteSignature && typeof gate.providerQuoteSignature === "object" && !Array.isArray(gate.providerQuoteSignature)
1724
+ ? gate.providerQuoteSignature
1725
+ : null,
1726
+ providerQuotePayload:
1727
+ gate?.providerQuotePayload && typeof gate.providerQuotePayload === "object" && !Array.isArray(gate.providerQuotePayload)
1728
+ ? gate.providerQuotePayload
1729
+ : null,
1730
+ zkProof:
1731
+ gate?.zkProof && typeof gate.zkProof === "object" && !Array.isArray(gate.zkProof)
1732
+ ? gate.zkProof
1733
+ : null,
1734
+ decisionRecord:
1735
+ decisionTrace?.decisionRecord && typeof decisionTrace.decisionRecord === "object" && !Array.isArray(decisionTrace.decisionRecord)
1736
+ ? decisionTrace.decisionRecord
1737
+ : null,
1738
+ settlementReceipt
1739
+ };
1740
+ if (!includeReversalContext) return base;
1741
+ return {
1742
+ ...base,
1743
+ reversal:
1744
+ gate?.reversal && typeof gate.reversal === "object" && !Array.isArray(gate.reversal)
1745
+ ? gate.reversal
1746
+ : null,
1747
+ reversalEvents: listX402ReversalEventsForReceiptSync({ tenantId, receiptId })
1748
+ };
1749
+ }
1750
+
1751
+ function normalizeX402ReceiptRecordForStorage({ receipt } = {}) {
1752
+ if (!receipt || typeof receipt !== "object" || Array.isArray(receipt)) return null;
1753
+ const stableUpdatedAt =
1754
+ typeof receipt.createdAt === "string" && receipt.createdAt.trim() !== ""
1755
+ ? receipt.createdAt
1756
+ : typeof receipt.settledAt === "string" && receipt.settledAt.trim() !== ""
1757
+ ? receipt.settledAt
1758
+ : typeof receipt.updatedAt === "string" && receipt.updatedAt.trim() !== ""
1759
+ ? receipt.updatedAt
1760
+ : new Date().toISOString();
1761
+ const normalized = {
1762
+ ...receipt,
1763
+ reversal: null,
1764
+ reversalEvents: [],
1765
+ updatedAt: stableUpdatedAt
1766
+ };
1767
+ return normalized;
1768
+ }
1769
+
1770
+ function projectX402ReceiptRecord({ tenantId, receipt } = {}) {
1771
+ if (!receipt || typeof receipt !== "object" || Array.isArray(receipt)) return null;
1772
+ const receiptId = typeof receipt.receiptId === "string" ? receipt.receiptId.trim() : "";
1773
+ if (!receiptId) return null;
1774
+ const gateId = typeof receipt.gateId === "string" ? receipt.gateId.trim() : "";
1775
+ const gate =
1776
+ gateId && store.x402Gates instanceof Map
1777
+ ? store.x402Gates.get(makeScopedKey({ tenantId, id: gateId })) ?? null
1778
+ : null;
1779
+ const reversalEvents = listX402ReversalEventsForReceiptSync({ tenantId, receiptId });
1780
+ const latestEvent = reversalEvents.length > 0 ? reversalEvents[reversalEvents.length - 1] : null;
1781
+ const derivedState =
1782
+ typeof latestEvent?.settlementStatusAfter === "string" && latestEvent.settlementStatusAfter.trim() !== ""
1783
+ ? latestEvent.settlementStatusAfter.trim().toLowerCase()
1784
+ : null;
1785
+ const updatedAtCandidates = [receipt.updatedAt, latestEvent?.occurredAt]
1786
+ .map((value) => (typeof value === "string" && value.trim() !== "" && Number.isFinite(Date.parse(value)) ? new Date(Date.parse(value)).toISOString() : null))
1787
+ .filter(Boolean);
1788
+ const updatedAt = updatedAtCandidates.length > 0 ? updatedAtCandidates.sort((a, b) => Date.parse(a) - Date.parse(b))[updatedAtCandidates.length - 1] : null;
1789
+ return {
1790
+ ...receipt,
1791
+ settlementState: derivedState ?? receipt.settlementState ?? null,
1792
+ updatedAt: updatedAt ?? receipt.updatedAt ?? null,
1793
+ reversal:
1794
+ gate?.reversal && typeof gate.reversal === "object" && !Array.isArray(gate.reversal)
1795
+ ? gate.reversal
1796
+ : receipt?.reversal && typeof receipt.reversal === "object" && !Array.isArray(receipt.reversal)
1797
+ ? receipt.reversal
1798
+ : null,
1799
+ reversalEvents
1800
+ };
1801
+ }
1802
+
1803
+ function compareX402ReceiptRecords(left, right) {
1804
+ const leftMs = Number.isFinite(Date.parse(String(left?.settledAt ?? ""))) ? Date.parse(String(left.settledAt)) : Number.NaN;
1805
+ const rightMs = Number.isFinite(Date.parse(String(right?.settledAt ?? ""))) ? Date.parse(String(right.settledAt)) : Number.NaN;
1806
+ if (Number.isFinite(leftMs) && Number.isFinite(rightMs) && leftMs !== rightMs) return rightMs - leftMs;
1807
+ return String(left?.receiptId ?? "").localeCompare(String(right?.receiptId ?? ""));
1808
+ }
1809
+
1810
+ function encodeX402ReceiptCursor(record) {
1811
+ const settledAt = typeof record?.settledAt === "string" && record.settledAt.trim() !== "" ? new Date(Date.parse(record.settledAt)).toISOString() : null;
1812
+ const receiptId = typeof record?.receiptId === "string" && record.receiptId.trim() !== "" ? record.receiptId.trim() : null;
1813
+ if (!settledAt || !receiptId) return null;
1814
+ return Buffer.from(JSON.stringify({ settledAt, receiptId }), "utf8").toString("base64url");
1815
+ }
1816
+
1817
+ function decodeX402ReceiptCursor(raw) {
1818
+ if (raw === null || raw === undefined || String(raw).trim() === "") return null;
1819
+ let parsed;
1820
+ try {
1821
+ parsed = JSON.parse(Buffer.from(String(raw).trim(), "base64url").toString("utf8"));
1822
+ } catch {
1823
+ throw new TypeError("cursor must be base64url-encoded JSON");
1824
+ }
1825
+ const settledAt = typeof parsed?.settledAt === "string" && Number.isFinite(Date.parse(parsed.settledAt)) ? new Date(Date.parse(parsed.settledAt)).toISOString() : null;
1826
+ const receiptId = typeof parsed?.receiptId === "string" && parsed.receiptId.trim() !== "" ? parsed.receiptId.trim() : null;
1827
+ if (!settledAt || !receiptId) throw new TypeError("cursor is invalid");
1828
+ return { settledAt, receiptId };
1829
+ }
1830
+
1831
+ function isReceiptAfterCursor(record, cursor) {
1832
+ if (!cursor) return true;
1833
+ const recordMs = Number.isFinite(Date.parse(String(record?.settledAt ?? ""))) ? Date.parse(String(record.settledAt)) : Number.NaN;
1834
+ const cursorMs = Date.parse(cursor.settledAt);
1835
+ if (!Number.isFinite(recordMs)) return false;
1836
+ if (recordMs < cursorMs) return true;
1837
+ if (recordMs > cursorMs) return false;
1838
+ return String(record?.receiptId ?? "") > String(cursor.receiptId ?? "");
1839
+ }
1840
+
1841
+ function listX402ReceiptCandidates({ tenantId }) {
1842
+ const byReceiptId = new Map();
1843
+ if (store.x402Receipts instanceof Map) {
1844
+ for (const row of store.x402Receipts.values()) {
1845
+ if (!row || typeof row !== "object" || Array.isArray(row)) continue;
1846
+ if (normalizeTenantId(row.tenantId ?? DEFAULT_TENANT_ID) !== tenantId) continue;
1847
+ const receiptId = typeof row.receiptId === "string" ? row.receiptId.trim() : "";
1848
+ if (!receiptId) continue;
1849
+ byReceiptId.set(receiptId, projectX402ReceiptRecord({ tenantId, receipt: row }));
1850
+ }
1851
+ }
1852
+ if (byReceiptId.size === 0 && store.x402Gates instanceof Map) {
1853
+ for (const gate of store.x402Gates.values()) {
1854
+ if (!gate || typeof gate !== "object" || Array.isArray(gate)) continue;
1855
+ if (normalizeTenantId(gate.tenantId ?? DEFAULT_TENANT_ID) !== tenantId) continue;
1856
+ const derived = toX402ReceiptRecord({ tenantId, gate, includeReversalContext: true });
1857
+ if (!derived) continue;
1858
+ const receiptId = typeof derived.receiptId === "string" ? derived.receiptId.trim() : "";
1859
+ if (!receiptId) continue;
1860
+ byReceiptId.set(receiptId, derived);
1861
+ }
1862
+ }
1863
+ return Array.from(byReceiptId.values()).filter(Boolean);
1864
+ }
1865
+
1866
+ store.deriveX402ReceiptRecord = function deriveX402ReceiptRecord({
1867
+ tenantId = DEFAULT_TENANT_ID,
1868
+ gate,
1869
+ settlement = null,
1870
+ includeReversalContext = false
1871
+ } = {}) {
1872
+ tenantId = normalizeTenantId(tenantId);
1873
+ const derived = toX402ReceiptRecord({ tenantId, gate, settlement, includeReversalContext });
1874
+ return normalizeX402ReceiptRecordForStorage({ receipt: derived });
1875
+ };
1876
+
1877
+ store.putX402Receipt = async function putX402Receipt({ tenantId = DEFAULT_TENANT_ID, receipt, audit = null } = {}) {
1878
+ tenantId = normalizeTenantId(tenantId);
1879
+ const normalized = normalizeX402ReceiptRecordForStorage({ receipt });
1880
+ if (!normalized) throw new TypeError("receipt is required");
1881
+ const receiptId = typeof normalized.receiptId === "string" ? normalized.receiptId.trim() : "";
1882
+ if (!receiptId) throw new TypeError("receipt.receiptId is required");
1883
+ const key = x402ReceiptStoreKey({ tenantId, receiptId });
1884
+ const at =
1885
+ typeof normalized.updatedAt === "string" && normalized.updatedAt.trim() !== ""
1886
+ ? normalized.updatedAt
1887
+ : typeof normalized.createdAt === "string" && normalized.createdAt.trim() !== ""
1888
+ ? normalized.createdAt
1889
+ : new Date().toISOString();
1890
+ await store.commitTx({
1891
+ at,
1892
+ ops: [{ kind: "X402_RECEIPT_PUT", tenantId, receiptId, receipt: { ...normalized, tenantId, receiptId } }],
1893
+ audit
1894
+ });
1895
+ return store.x402Receipts.get(key) ?? null;
1896
+ };
1897
+
1898
+ store.getX402Receipt = async function getX402Receipt({ tenantId = DEFAULT_TENANT_ID, receiptId } = {}) {
1899
+ tenantId = normalizeTenantId(tenantId);
1900
+ if (typeof receiptId !== "string" || receiptId.trim() === "") throw new TypeError("receiptId is required");
1901
+ const wanted = receiptId.trim();
1902
+ const key = x402ReceiptStoreKey({ tenantId, receiptId: wanted });
1903
+ const stored = store.x402Receipts instanceof Map ? store.x402Receipts.get(key) ?? null : null;
1904
+ if (stored) return projectX402ReceiptRecord({ tenantId, receipt: stored });
1905
+ for (const gate of store.x402Gates.values()) {
1906
+ if (!gate || typeof gate !== "object" || Array.isArray(gate)) continue;
1907
+ if (normalizeTenantId(gate.tenantId ?? DEFAULT_TENANT_ID) !== tenantId) continue;
1908
+ const receipt = toX402ReceiptRecord({ tenantId, gate, includeReversalContext: true });
1909
+ if (!receipt) continue;
1910
+ if (String(receipt.receiptId ?? "") === wanted) return receipt;
1911
+ }
1912
+ return null;
1913
+ };
1914
+
1915
+ store.listX402ReceiptsPage = async function listX402ReceiptsPage({
1916
+ tenantId = DEFAULT_TENANT_ID,
1917
+ agentId = null,
1918
+ sponsorId = null,
1919
+ sponsorWalletRef = null,
1920
+ toolId = null,
1921
+ state = null,
1922
+ from = null,
1923
+ to = null,
1924
+ limit = 200,
1925
+ offset = 0,
1926
+ cursor = null
1927
+ } = {}) {
1928
+ tenantId = normalizeTenantId(tenantId);
1929
+ if (agentId !== null && (typeof agentId !== "string" || agentId.trim() === "")) throw new TypeError("agentId must be null or a non-empty string");
1930
+ if (sponsorId !== null && (typeof sponsorId !== "string" || sponsorId.trim() === "")) throw new TypeError("sponsorId must be null or a non-empty string");
1931
+ if (sponsorWalletRef !== null && (typeof sponsorWalletRef !== "string" || sponsorWalletRef.trim() === "")) {
1932
+ throw new TypeError("sponsorWalletRef must be null or a non-empty string");
1933
+ }
1934
+ if (toolId !== null && (typeof toolId !== "string" || toolId.trim() === "")) throw new TypeError("toolId must be null or a non-empty string");
1935
+ if (state !== null && (typeof state !== "string" || state.trim() === "")) throw new TypeError("state must be null or a non-empty string");
1936
+ if (from !== null && !Number.isFinite(Date.parse(String(from)))) throw new TypeError("from must be null or an ISO date-time");
1937
+ if (to !== null && !Number.isFinite(Date.parse(String(to)))) throw new TypeError("to must be null or an ISO date-time");
1938
+ if (!Number.isSafeInteger(limit) || limit <= 0) throw new TypeError("limit must be a positive safe integer");
1939
+ if (!Number.isSafeInteger(offset) || offset < 0) throw new TypeError("offset must be a non-negative safe integer");
1940
+
1941
+ const normalizedAgentId = agentId ? agentId.trim() : null;
1942
+ const normalizedSponsorId = sponsorId ? sponsorId.trim() : null;
1943
+ const normalizedSponsorWalletRef = sponsorWalletRef ? sponsorWalletRef.trim() : null;
1944
+ const normalizedToolId = toolId ? toolId.trim() : null;
1945
+ const normalizedState = state ? state.trim().toLowerCase() : null;
1946
+ const fromMs = from ? Date.parse(String(from)) : null;
1947
+ const toMs = to ? Date.parse(String(to)) : null;
1948
+ const decodedCursor = cursor === null ? null : decodeX402ReceiptCursor(cursor);
1949
+
1950
+ const all = listX402ReceiptCandidates({ tenantId });
1951
+ const filtered = all.filter((receipt) => {
1952
+ if (!receipt) return false;
1953
+ if (
1954
+ normalizedAgentId &&
1955
+ String(receipt.payerAgentId ?? "") !== normalizedAgentId &&
1956
+ String(receipt.providerId ?? "") !== normalizedAgentId &&
1957
+ String(receipt.agentKeyId ?? "") !== normalizedAgentId
1958
+ ) {
1959
+ return false;
1960
+ }
1961
+ if (normalizedSponsorId && String(receipt.sponsorRef ?? "") !== normalizedSponsorId) return false;
1962
+ if (normalizedSponsorWalletRef && String(receipt.sponsorWalletRef ?? "") !== normalizedSponsorWalletRef) return false;
1963
+ if (normalizedToolId && String(receipt.toolId ?? "") !== normalizedToolId) return false;
1964
+ if (normalizedState && String(receipt.settlementState ?? "").toLowerCase() !== normalizedState) return false;
1965
+ const settledAtMs = Number.isFinite(Date.parse(String(receipt.settledAt ?? ""))) ? Date.parse(String(receipt.settledAt)) : Number.NaN;
1966
+ if (fromMs !== null && (!Number.isFinite(settledAtMs) || settledAtMs < fromMs)) return false;
1967
+ if (toMs !== null && (!Number.isFinite(settledAtMs) || settledAtMs > toMs)) return false;
1968
+ return true;
1969
+ });
1970
+
1971
+ filtered.sort(compareX402ReceiptRecords);
1972
+ const cursorFiltered = decodedCursor ? filtered.filter((row) => isReceiptAfterCursor(row, decodedCursor)) : filtered;
1973
+ const paged = cursorFiltered.slice(offset, offset + Math.min(1000, limit));
1974
+ const hasMore = cursorFiltered.length > offset + paged.length;
1975
+ const nextCursor = hasMore && paged.length > 0 ? encodeX402ReceiptCursor(paged[paged.length - 1]) : null;
1976
+ return { receipts: paged, nextCursor };
1977
+ };
1978
+
1979
+ store.listX402Receipts = async function listX402Receipts(args = {}) {
1980
+ const page = await store.listX402ReceiptsPage(args);
1981
+ return page.receipts;
1982
+ };
1983
+
791
1984
  store.listArbitrationCases = async function listArbitrationCases({
792
1985
  tenantId = DEFAULT_TENANT_ID,
793
1986
  runId = null,
@@ -1299,6 +2492,55 @@ export function createStore({ persistenceDir = null, serverSignerKeypair = null
1299
2492
  return all;
1300
2493
  };
1301
2494
 
2495
+ store.listReputationEvents = async function listReputationEvents({
2496
+ tenantId = DEFAULT_TENANT_ID,
2497
+ agentId,
2498
+ toolId = null,
2499
+ occurredAtGte = null,
2500
+ occurredAtLte = null,
2501
+ limit = 1000,
2502
+ offset = 0
2503
+ } = {}) {
2504
+ tenantId = normalizeTenantId(tenantId);
2505
+ if (typeof agentId !== "string" || agentId.trim() === "") throw new TypeError("agentId is required");
2506
+ if (toolId !== null && toolId !== undefined && (typeof toolId !== "string" || toolId.trim() === "")) {
2507
+ throw new TypeError("toolId must be null or a non-empty string");
2508
+ }
2509
+ if (occurredAtGte !== null && occurredAtGte !== undefined && !Number.isFinite(Date.parse(String(occurredAtGte)))) {
2510
+ throw new TypeError("occurredAtGte must be an ISO date-time");
2511
+ }
2512
+ if (occurredAtLte !== null && occurredAtLte !== undefined && !Number.isFinite(Date.parse(String(occurredAtLte)))) {
2513
+ throw new TypeError("occurredAtLte must be an ISO date-time");
2514
+ }
2515
+ if (!Number.isSafeInteger(limit) || limit <= 0) throw new TypeError("limit must be a positive safe integer");
2516
+ if (!Number.isSafeInteger(offset) || offset < 0) throw new TypeError("offset must be a non-negative safe integer");
2517
+
2518
+ const minMs = occurredAtGte ? Date.parse(String(occurredAtGte)) : Number.NaN;
2519
+ const maxMs = occurredAtLte ? Date.parse(String(occurredAtLte)) : Number.NaN;
2520
+ const out = [];
2521
+ for (const art of store.artifacts.values()) {
2522
+ if (!art || typeof art !== "object" || Array.isArray(art)) continue;
2523
+ if (normalizeTenantId(art.tenantId ?? DEFAULT_TENANT_ID) !== tenantId) continue;
2524
+ if (String(art.schemaVersion ?? "") !== "ReputationEvent.v1") continue;
2525
+ const subject = art.subject && typeof art.subject === "object" && !Array.isArray(art.subject) ? art.subject : null;
2526
+ if (!subject) continue;
2527
+ if (String(subject.agentId ?? "") !== String(agentId)) continue;
2528
+ if (toolId !== null && toolId !== undefined && String(subject.toolId ?? "") !== String(toolId)) continue;
2529
+ const occurredAtMs = Date.parse(String(art.occurredAt ?? ""));
2530
+ if (!Number.isFinite(occurredAtMs)) continue;
2531
+ if (Number.isFinite(minMs) && occurredAtMs < minMs) continue;
2532
+ if (Number.isFinite(maxMs) && occurredAtMs > maxMs) continue;
2533
+ out.push(art);
2534
+ }
2535
+ out.sort((left, right) => {
2536
+ const leftMs = Date.parse(String(left?.occurredAt ?? ""));
2537
+ const rightMs = Date.parse(String(right?.occurredAt ?? ""));
2538
+ if (Number.isFinite(leftMs) && Number.isFinite(rightMs) && leftMs !== rightMs) return leftMs - rightMs;
2539
+ return String(left?.eventId ?? "").localeCompare(String(right?.eventId ?? ""));
2540
+ });
2541
+ return out.slice(offset, offset + Math.min(5000, limit));
2542
+ };
2543
+
1302
2544
  store.getArtifact = async function getArtifact({ tenantId = DEFAULT_TENANT_ID, artifactId }) {
1303
2545
  tenantId = normalizeTenantId(tenantId);
1304
2546
  if (typeof artifactId !== "string" || artifactId.trim() === "") throw new TypeError("artifactId is required");