settld 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (483) hide show
  1. package/README.md +93 -3
  2. package/SETTLD_VERSION +1 -1
  3. package/bin/settld-mcp +2 -0
  4. package/bin/settld.js +71 -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 +152 -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 +377 -0
  36. package/docs/QUICKSTART_MCP_HOSTS.md +210 -0
  37. package/docs/QUICKSTART_POLICY_PACKS.md +65 -0
  38. package/docs/QUICKSTART_PRODUCE.md +61 -0
  39. package/docs/QUICKSTART_PROFILES.md +198 -0
  40. package/docs/QUICKSTART_RELEASE_VERIFY.md +39 -0
  41. package/docs/QUICKSTART_SDK.md +125 -0
  42. package/docs/QUICKSTART_SDK_PYTHON.md +111 -0
  43. package/docs/QUICKSTART_VERIFY.md +54 -0
  44. package/docs/QUICKSTART_X402_GATEWAY.md +317 -0
  45. package/docs/README.md +33 -0
  46. package/docs/RELEASE_CHECKLIST.md +182 -0
  47. package/docs/RELEASING.md +82 -0
  48. package/docs/REPO_SETTINGS.md +37 -0
  49. package/docs/RUNBOOK.md +86 -0
  50. package/docs/SKILLS.md +42 -0
  51. package/docs/SKILL_BUNDLE_FORMAT.md +48 -0
  52. package/docs/SLO.md +131 -0
  53. package/docs/SUMMARY.md +17 -0
  54. package/docs/SUPPORT.md +31 -0
  55. package/docs/THREAT_MODEL.md +36 -0
  56. package/docs/TRUST.md +59 -0
  57. package/docs/WORKFLOW.md +35 -0
  58. package/docs/X402_BATCH_SETTLEMENT.md +126 -0
  59. package/docs/blog/2026-02-14-your-ai-agent-just-spent-500-where-is-the-receipt.md +73 -0
  60. package/docs/examples/x402-provider-payout-registry.example.json +14 -0
  61. package/docs/gitbook/README.md +64 -0
  62. package/docs/gitbook/SETUP.md +25 -0
  63. package/docs/gitbook/SUMMARY.md +15 -0
  64. package/docs/gitbook/api-reference.md +73 -0
  65. package/docs/gitbook/closepacks.md +55 -0
  66. package/docs/gitbook/conformance.md +59 -0
  67. package/docs/gitbook/core-primitives.md +85 -0
  68. package/docs/gitbook/dispute-lifecycle.md +33 -0
  69. package/docs/gitbook/faq.md +21 -0
  70. package/docs/gitbook/guides.md +49 -0
  71. package/docs/gitbook/operations-runbook.md +36 -0
  72. package/docs/gitbook/quickstart.md +103 -0
  73. package/docs/gitbook/replay-and-audit.md +30 -0
  74. package/docs/gitbook/sdk-reference.md +35 -0
  75. package/docs/gitbook/security-model.md +58 -0
  76. package/docs/integrations/README.md +15 -0
  77. package/docs/integrations/github-actions-verify.yml +31 -0
  78. package/docs/integrations/github-actions.md +34 -0
  79. package/docs/integrations/openclaw/CLAWHUB_PUBLISH_CHECKLIST.md +65 -0
  80. package/docs/integrations/openclaw/PUBLIC_QUICKSTART.md +95 -0
  81. package/docs/integrations/openclaw/settld-mcp-skill/SKILL.md +69 -0
  82. package/docs/integrations/openclaw/settld-mcp-skill/mcp-server.example.json +12 -0
  83. package/docs/kernel-compatible/capabilities.json +36 -0
  84. package/docs/marketing/agent-commerce-substrate.md +78 -0
  85. package/docs/marketing/hn-repost-2026-02-17.md +102 -0
  86. package/docs/marketing/show-hn-post.md +45 -0
  87. package/docs/ops/ARTIFACT_VERIFICATION_STATUS.md +43 -0
  88. package/docs/ops/BILLING_WEBHOOK_REPLAY.md +105 -0
  89. package/docs/ops/CI_FLAKE_BUDGET.md +31 -0
  90. package/docs/ops/DISPUTE_FINANCE_RECONCILIATION_PACKET.md +56 -0
  91. package/docs/ops/GO_LIVE_GATE_S13.md +27 -0
  92. package/docs/ops/HOSTED_BASELINE_R2.md +129 -0
  93. package/docs/ops/KERNEL_V0_SHIP_GATE.md +69 -0
  94. package/docs/ops/LIGHTHOUSE_PRODUCTION_CLOSE.md +51 -0
  95. package/docs/ops/MCP_COMPATIBILITY_MATRIX.md +30 -0
  96. package/docs/ops/MINIMUM_PRODUCTION_TOPOLOGY.md +89 -0
  97. package/docs/ops/P0_BACKEND_PROGRESS.md +150 -0
  98. package/docs/ops/PAYMENTS_ALPHA_R5.md +105 -0
  99. package/docs/ops/PILOT_ONBOARDING_RUNBOOK.md +112 -0
  100. package/docs/ops/PRODUCTION_DEPLOYMENT_CHECKLIST.md +140 -0
  101. package/docs/ops/R1_SLOS.md +66 -0
  102. package/docs/ops/RELEASE_SIGNING_INCIDENT.md +58 -0
  103. package/docs/ops/SELF_SERVE_LAUNCH_AUTOMATION.md +89 -0
  104. package/docs/ops/THROUGHPUT_DRILL_10X.md +48 -0
  105. package/docs/ops/TRUST_CONFIG_WIZARD.md +60 -0
  106. package/docs/ops/X402_PILOT_WEEKLY_METRICS.md +76 -0
  107. package/docs/ops/tool-call-disputes-holdback.md +52 -0
  108. package/docs/pilot-kit/PILOT_PACKAGE_SCORECARD_X402.md +46 -0
  109. package/docs/pilot-kit/README.md +29 -0
  110. package/docs/pilot-kit/architecture-one-pager.md +48 -0
  111. package/docs/pilot-kit/buyer-email.txt +19 -0
  112. package/docs/pilot-kit/buyer-one-pager.md +31 -0
  113. package/docs/pilot-kit/gtm-pilot-playbook.md +182 -0
  114. package/docs/pilot-kit/offline-verify.md +33 -0
  115. package/docs/pilot-kit/procurement-one-pager.md +50 -0
  116. package/docs/pilot-kit/rfp-clause.md +46 -0
  117. package/docs/pilot-kit/roi-calculator-template.csv +2 -0
  118. package/docs/pilot-kit/security-qa.md +153 -0
  119. package/docs/pilot-kit/security-summary.md +35 -0
  120. package/docs/plans/2026-02-13-mcp-spike-design.md +113 -0
  121. package/docs/plans/2026-02-20-trust-os-v1-jira-backlog.md +348 -0
  122. package/docs/plans/2026-02-21-agent-economic-actor-operating-model.md +169 -0
  123. package/docs/plans/2026-02-21-trust-os-v1-strategy.md +241 -0
  124. package/docs/research/2026-02-21-agent-spend-host-landscape.md +57 -0
  125. package/docs/spec/AcceptanceCriteria.v1.md +17 -0
  126. package/docs/spec/AcceptanceEvaluation.v1.md +10 -0
  127. package/docs/spec/AgentEvent.v1.md +47 -0
  128. package/docs/spec/AgentIdentity.v1.md +62 -0
  129. package/docs/spec/AgentPassport.v1.md +95 -0
  130. package/docs/spec/AgentReputation.v1.md +59 -0
  131. package/docs/spec/AgentReputation.v2.md +52 -0
  132. package/docs/spec/AgentRun.v1.md +47 -0
  133. package/docs/spec/AgentRunSettlement.v1.md +52 -0
  134. package/docs/spec/AgentWallet.v1.md +43 -0
  135. package/docs/spec/AgreementDelegation.v1.md +109 -0
  136. package/docs/spec/ArbitrationCase.v1.md +67 -0
  137. package/docs/spec/ArbitrationOutcomeMapping.v1.md +62 -0
  138. package/docs/spec/ArbitrationVerdict.v1.md +60 -0
  139. package/docs/spec/BundleHeadAttestation.v1.md +32 -0
  140. package/docs/spec/CANONICAL_JSON.md +31 -0
  141. package/docs/spec/CRYPTOGRAPHY.md +61 -0
  142. package/docs/spec/ClosePack.v1.md +49 -0
  143. package/docs/spec/ClosePackManifest.v1.md +24 -0
  144. package/docs/spec/DelegationGrant.v1.md +90 -0
  145. package/docs/spec/DisputeCaseLifecycle.v1.md +51 -0
  146. package/docs/spec/DisputeOpenEnvelope.v1.md +43 -0
  147. package/docs/spec/ERRORS.md +76 -0
  148. package/docs/spec/ESCROW_NETTING_INVARIANTS.md +71 -0
  149. package/docs/spec/EvidenceIndex.v1.md +20 -0
  150. package/docs/spec/ExecutionIntent.v1.md +90 -0
  151. package/docs/spec/FinancePackBundleManifest.v1.md +24 -0
  152. package/docs/spec/FundingHold.v1.md +60 -0
  153. package/docs/spec/GovernancePolicy.v1.md +34 -0
  154. package/docs/spec/GovernancePolicy.v2.md +30 -0
  155. package/docs/spec/INVARIANTS.md +389 -0
  156. package/docs/spec/InteractionDirectionMatrix.v1.md +30 -0
  157. package/docs/spec/InvoiceBundleManifest.v1.md +24 -0
  158. package/docs/spec/InvoiceClaim.v1.md +11 -0
  159. package/docs/spec/MONEY_RAIL_STATE_MACHINE.md +58 -0
  160. package/docs/spec/MarketplaceAcceptance.v2.md +46 -0
  161. package/docs/spec/MarketplaceOffer.v2.md +54 -0
  162. package/docs/spec/MeteringReport.v1.md +18 -0
  163. package/docs/spec/OperatorAction.v1.md +90 -0
  164. package/docs/spec/PRODUCER_ERRORS.md +42 -0
  165. package/docs/spec/PolicyDecision.v1.md +83 -0
  166. package/docs/spec/PricingMatrix.v1.md +20 -0
  167. package/docs/spec/PricingMatrixSignatures.v1.md +30 -0
  168. package/docs/spec/PricingMatrixSignatures.v2.md +29 -0
  169. package/docs/spec/ProduceCliOutput.v1.md +46 -0
  170. package/docs/spec/ProofBundleManifest.v1.md +24 -0
  171. package/docs/spec/README.md +109 -0
  172. package/docs/spec/REFERENCE_IMPLEMENTATIONS.md +29 -0
  173. package/docs/spec/REFERENCE_VERIFIER_BEHAVIOR.md +68 -0
  174. package/docs/spec/REMOTE_SIGNER.md +66 -0
  175. package/docs/spec/ReleaseIndex.v1.md +32 -0
  176. package/docs/spec/ReleaseIndexSignatures.v1.md +17 -0
  177. package/docs/spec/ReleaseTrust.v1.md +13 -0
  178. package/docs/spec/ReleaseTrust.v2.md +26 -0
  179. package/docs/spec/RemoteSignerRequest.v1.md +21 -0
  180. package/docs/spec/RemoteSignerResponse.v1.md +16 -0
  181. package/docs/spec/ReputationEvent.v1.md +63 -0
  182. package/docs/spec/RevocationList.v1.md +28 -0
  183. package/docs/spec/SIGNER_PROVIDER_PLUGIN.md +32 -0
  184. package/docs/spec/STRICTNESS.md +68 -0
  185. package/docs/spec/SUPPLY_CHAIN.md +33 -0
  186. package/docs/spec/SettlementAdjustment.v1.md +45 -0
  187. package/docs/spec/SettlementDecisionRecord.v1.md +48 -0
  188. package/docs/spec/SettlementDecisionRecord.v2.md +53 -0
  189. package/docs/spec/SettlementDecisionReport.v1.md +44 -0
  190. package/docs/spec/SettlementKernel.v1.md +59 -0
  191. package/docs/spec/SettlementReceipt.v1.md +63 -0
  192. package/docs/spec/SlaDefinition.v1.md +24 -0
  193. package/docs/spec/SlaEvaluation.v1.md +12 -0
  194. package/docs/spec/THREAT_MODEL.md +113 -0
  195. package/docs/spec/TOOL_PROVENANCE.md +30 -0
  196. package/docs/spec/TRUST_ANCHORS.md +84 -0
  197. package/docs/spec/TenantSettings.v1.md +90 -0
  198. package/docs/spec/TenantSettings.v2.md +99 -0
  199. package/docs/spec/TimestampProof.v1.md +25 -0
  200. package/docs/spec/ToolCallAgreement.v1.md +34 -0
  201. package/docs/spec/ToolCallEvidence.v1.md +47 -0
  202. package/docs/spec/ToolManifest.v1.md +47 -0
  203. package/docs/spec/VERIFIER_ENVIRONMENT.md +38 -0
  204. package/docs/spec/VERSIONING.md +107 -0
  205. package/docs/spec/VerificationReport.v1.md +50 -0
  206. package/docs/spec/VerifyAboutOutput.v1.md +10 -0
  207. package/docs/spec/VerifyCliOutput.v1.md +28 -0
  208. package/docs/spec/WARNINGS.md +83 -0
  209. package/docs/spec/error-codes.v1.txt +285 -0
  210. package/docs/spec/examples/agreement_delegation_v1.example.json +21 -0
  211. package/docs/spec/examples/arbitration_case_v1.example.json +26 -0
  212. package/docs/spec/examples/arbitration_verdict_v1.example.json +32 -0
  213. package/docs/spec/examples/dispute_open_envelope_v1.example.json +18 -0
  214. package/docs/spec/examples/produce_cli_output_v1.example.json +32 -0
  215. package/docs/spec/examples/release_index_signature_v1.example.json +9 -0
  216. package/docs/spec/examples/release_index_signatures_v1.example.json +14 -0
  217. package/docs/spec/examples/release_index_v1.example.json +15 -0
  218. package/docs/spec/examples/release_trust_v1.example.json +7 -0
  219. package/docs/spec/examples/release_trust_v2.example.json +22 -0
  220. package/docs/spec/examples/remote_signer_request_v1.example.json +18 -0
  221. package/docs/spec/examples/remote_signer_response_v1.example.json +8 -0
  222. package/docs/spec/examples/reputation_event_v1.example.json +29 -0
  223. package/docs/spec/examples/verification_report_v1.example.json +24 -0
  224. package/docs/spec/examples/verify_about_output_v1.example.json +29 -0
  225. package/docs/spec/examples/verify_cli_output_v1.example.json +13 -0
  226. package/docs/spec/legacy/MarketplaceAcceptance.v1.md +48 -0
  227. package/docs/spec/legacy/MarketplaceOffer.v1.md +56 -0
  228. package/docs/spec/legacy/schemas/MarketplaceAcceptance.v1.schema.json +53 -0
  229. package/docs/spec/legacy/schemas/MarketplaceOffer.v1.schema.json +61 -0
  230. package/docs/spec/producer-error-codes.v1.txt +14 -0
  231. package/docs/spec/schemas/AcceptanceCriteria.v1.schema.json +24 -0
  232. package/docs/spec/schemas/AcceptanceEvaluation.v1.schema.json +26 -0
  233. package/docs/spec/schemas/AgentEvent.v1.schema.json +49 -0
  234. package/docs/spec/schemas/AgentIdentity.v1.schema.json +129 -0
  235. package/docs/spec/schemas/AgentPassport.v1.schema.json +112 -0
  236. package/docs/spec/schemas/AgentReputation.v1.schema.json +151 -0
  237. package/docs/spec/schemas/AgentReputation.v2.schema.json +120 -0
  238. package/docs/spec/schemas/AgentRun.v1.schema.json +71 -0
  239. package/docs/spec/schemas/AgentRunSettlement.v1.schema.json +75 -0
  240. package/docs/spec/schemas/AgentWallet.v1.schema.json +54 -0
  241. package/docs/spec/schemas/AgreementDelegation.v1.schema.json +50 -0
  242. package/docs/spec/schemas/ArbitrationCase.v1.schema.json +133 -0
  243. package/docs/spec/schemas/ArbitrationVerdict.v1.schema.json +149 -0
  244. package/docs/spec/schemas/BundleHeadAttestation.v1.schema.json +21 -0
  245. package/docs/spec/schemas/ClosePackManifest.v1.schema.json +38 -0
  246. package/docs/spec/schemas/DelegationGrant.v1.schema.json +102 -0
  247. package/docs/spec/schemas/DisputeOpenEnvelope.v1.schema.json +78 -0
  248. package/docs/spec/schemas/EvidenceIndex.v1.schema.json +41 -0
  249. package/docs/spec/schemas/ExecutionIntent.v1.schema.json +85 -0
  250. package/docs/spec/schemas/FinancePackBundleManifest.v1.schema.json +38 -0
  251. package/docs/spec/schemas/FundingHold.v1.schema.json +46 -0
  252. package/docs/spec/schemas/GovernancePolicy.v1.schema.json +45 -0
  253. package/docs/spec/schemas/GovernancePolicy.v2.schema.json +70 -0
  254. package/docs/spec/schemas/InteractionDirectionMatrix.v1.schema.json +43 -0
  255. package/docs/spec/schemas/InvoiceBundleManifest.v1.schema.json +38 -0
  256. package/docs/spec/schemas/InvoiceClaim.v1.schema.json +39 -0
  257. package/docs/spec/schemas/MarketplaceAcceptance.v2.schema.json +53 -0
  258. package/docs/spec/schemas/MarketplaceOffer.v2.schema.json +61 -0
  259. package/docs/spec/schemas/MeteringReport.v1.schema.json +45 -0
  260. package/docs/spec/schemas/OperatorAction.v1.schema.json +113 -0
  261. package/docs/spec/schemas/PolicyDecision.v1.schema.json +74 -0
  262. package/docs/spec/schemas/PricingMatrix.v1.schema.json +24 -0
  263. package/docs/spec/schemas/PricingMatrixSignatures.v1.schema.json +24 -0
  264. package/docs/spec/schemas/PricingMatrixSignatures.v2.schema.json +24 -0
  265. package/docs/spec/schemas/ProduceCliOutput.v1.schema.json +107 -0
  266. package/docs/spec/schemas/ProofBundleManifest.v1.schema.json +37 -0
  267. package/docs/spec/schemas/PublicKeys.v1.schema.json +33 -0
  268. package/docs/spec/schemas/ReleaseIndex.v1.schema.json +45 -0
  269. package/docs/spec/schemas/ReleaseIndexSignature.v1.schema.json +16 -0
  270. package/docs/spec/schemas/ReleaseIndexSignatures.v1.schema.json +16 -0
  271. package/docs/spec/schemas/ReleaseTrust.v1.schema.json +15 -0
  272. package/docs/spec/schemas/ReleaseTrust.v2.schema.json +37 -0
  273. package/docs/spec/schemas/RemoteSignerPublicKeyResponse.v1.schema.json +14 -0
  274. package/docs/spec/schemas/RemoteSignerRequest.v1.schema.json +24 -0
  275. package/docs/spec/schemas/RemoteSignerResponse.v1.schema.json +10 -0
  276. package/docs/spec/schemas/RemoteSignerSignRequest.v1.schema.json +27 -0
  277. package/docs/spec/schemas/RemoteSignerSignResponse.v1.schema.json +16 -0
  278. package/docs/spec/schemas/ReputationEvent.v1.schema.json +164 -0
  279. package/docs/spec/schemas/RevocationList.v1.schema.json +51 -0
  280. package/docs/spec/schemas/SettlementAdjustment.v1.schema.json +44 -0
  281. package/docs/spec/schemas/SettlementDecisionRecord.v1.schema.json +66 -0
  282. package/docs/spec/schemas/SettlementDecisionRecord.v2.schema.json +149 -0
  283. package/docs/spec/schemas/SettlementDecisionReport.v1.schema.json +61 -0
  284. package/docs/spec/schemas/SettlementReceipt.v1.schema.json +135 -0
  285. package/docs/spec/schemas/SlaDefinition.v1.schema.json +33 -0
  286. package/docs/spec/schemas/SlaEvaluation.v1.schema.json +26 -0
  287. package/docs/spec/schemas/TenantSettings.v1.schema.json +90 -0
  288. package/docs/spec/schemas/TenantSettings.v2.schema.json +161 -0
  289. package/docs/spec/schemas/TimestampProof.v1.schema.json +17 -0
  290. package/docs/spec/schemas/ToolCallAgreement.v1.schema.json +34 -0
  291. package/docs/spec/schemas/ToolCallEvidence.v1.schema.json +45 -0
  292. package/docs/spec/schemas/ToolManifest.v1.schema.json +54 -0
  293. package/docs/spec/schemas/VerificationReport.v1.schema.json +83 -0
  294. package/docs/spec/schemas/VerifyAboutOutput.v1.schema.json +54 -0
  295. package/docs/spec/schemas/VerifyCliOutput.v1.schema.json +75 -0
  296. package/docs/spec/schemas/VerifyReleaseOutput.v1.schema.json +47 -0
  297. package/docs/spec/x402-error-codes.v1.txt +35 -0
  298. package/docs/templates/buyer-email.txt +18 -0
  299. package/docs/templates/buyer-one-pager.md +24 -0
  300. package/package.json +53 -6
  301. package/scripts/acceptance/full-stack.mjs +734 -0
  302. package/scripts/acceptance/full-stack.sh +99 -0
  303. package/scripts/audit/build-audit-packet.mjs +242 -0
  304. package/scripts/backup-pg.sh +45 -0
  305. package/scripts/backup-restore/README.md +18 -0
  306. package/scripts/backup-restore/capture-state.mjs +130 -0
  307. package/scripts/backup-restore/client.mjs +97 -0
  308. package/scripts/backup-restore/seed-workload.mjs +235 -0
  309. package/scripts/backup-restore/verify-state.mjs +139 -0
  310. package/scripts/backup-restore-test.sh +217 -0
  311. package/scripts/chaos.js +221 -0
  312. package/scripts/ci/build-launch-cutover-packet.mjs +304 -0
  313. package/scripts/ci/build-self-serve-benchmark-report.mjs +122 -0
  314. package/scripts/ci/changelog-guard.mjs +145 -0
  315. package/scripts/ci/check-kernel-v0-launch-gate.mjs +233 -0
  316. package/scripts/ci/check-secret-hygiene.mjs +78 -0
  317. package/scripts/ci/check-version-consistency.mjs +42 -0
  318. package/scripts/ci/cli-pack-smoke.mjs +160 -0
  319. package/scripts/ci/flake-budget-guard.mjs +68 -0
  320. package/scripts/ci/generate-error-codes.mjs +54 -0
  321. package/scripts/ci/lib/lighthouse-tracker.mjs +90 -0
  322. package/scripts/ci/lib/self-serve-launch-gate.mjs +89 -0
  323. package/scripts/ci/npm-pack-smoke.mjs +454 -0
  324. package/scripts/ci/run-10x-throughput-drill.mjs +318 -0
  325. package/scripts/ci/run-10x-throughput-incident-rehearsal.mjs +368 -0
  326. package/scripts/ci/run-arbitration-workspace-browser-e2e.sh +22 -0
  327. package/scripts/ci/run-circle-sandbox-smoke.mjs +237 -0
  328. package/scripts/ci/run-go-live-gate.mjs +150 -0
  329. package/scripts/ci/run-kernel-v0-ship-gate.mjs +97 -0
  330. package/scripts/ci/run-mcp-host-cert-matrix.mjs +201 -0
  331. package/scripts/ci/run-mcp-host-smoke.mjs +473 -0
  332. package/scripts/ci/run-offline-verification-parity-gate.mjs +762 -0
  333. package/scripts/ci/run-onboarding-host-success-gate.mjs +516 -0
  334. package/scripts/ci/run-onboarding-policy-slo-gate.mjs +537 -0
  335. package/scripts/ci/run-production-cutover-gate.mjs +540 -0
  336. package/scripts/ci/run-public-openclaw-npx-smoke.mjs +148 -0
  337. package/scripts/ci/run-release-promotion-guard.mjs +756 -0
  338. package/scripts/ci/run-self-serve-launch-gate.mjs +56 -0
  339. package/scripts/ci/runtime-import-smoke.mjs +58 -0
  340. package/scripts/ci/update-lighthouse-tracker.mjs +112 -0
  341. package/scripts/closepack/lib.mjs +286 -0
  342. package/scripts/collect-debug.sh +263 -0
  343. package/scripts/demo/compositional-settlement-3hop.mjs +237 -0
  344. package/scripts/demo/delivery-robot/export-ui-fixture.mjs +188 -0
  345. package/scripts/demo/delivery-robot/generate.mjs +377 -0
  346. package/scripts/demo/kernel-agent-goes-shopping.mjs +202 -0
  347. package/scripts/demo/magic-link-first-green.mjs +118 -0
  348. package/scripts/demo/magic-link-kind-smoke.mjs +577 -0
  349. package/scripts/demo/mcp-paid-exa.mjs +1110 -0
  350. package/scripts/dev/billing-doctor.sh +145 -0
  351. package/scripts/dev/billing-smoke-prod.sh +219 -0
  352. package/scripts/dev/billing-webhook-replay.sh +161 -0
  353. package/scripts/dev/env.dev.example +29 -0
  354. package/scripts/dev/env.sh +37 -0
  355. package/scripts/dev/new-sdk-key.sh +81 -0
  356. package/scripts/dev/sdk-first-run.sh +21 -0
  357. package/scripts/dev/smoke-x402-gateway.sh +115 -0
  358. package/scripts/dev/start-api.sh +24 -0
  359. package/scripts/doctor/mcp-host.mjs +120 -0
  360. package/scripts/examples/produce-and-verify-jobproof.mjs +191 -0
  361. package/scripts/examples/sdk-first-paid-rfq.py +105 -0
  362. package/scripts/examples/sdk-first-verified-run.mjs +85 -0
  363. package/scripts/examples/sdk-first-verified-run.py +99 -0
  364. package/scripts/examples/sdk-tenant-analytics.mjs +103 -0
  365. package/scripts/examples/sdk-tenant-analytics.py +118 -0
  366. package/scripts/finance-pack/bundle.mjs +284 -0
  367. package/scripts/fixtures/generate-bundle-fixtures.mjs +877 -0
  368. package/scripts/governance/export.mjs +169 -0
  369. package/scripts/load/delivery-stress.k6.js +183 -0
  370. package/scripts/load/ingest-burst.k6.js +236 -0
  371. package/scripts/load/run-delivery-load.js +66 -0
  372. package/scripts/load/webhook-receiver.js +131 -0
  373. package/scripts/magic-link/migrate-run-records-to-db.mjs +35 -0
  374. package/scripts/mcp/probe.mjs +238 -0
  375. package/scripts/mcp/settld-mcp-http-gateway.mjs +178 -0
  376. package/scripts/mcp/settld-mcp-server.mjs +1511 -0
  377. package/scripts/openapi/write.mjs +13 -0
  378. package/scripts/ops/bootstrap-tenant-conformance.mjs +185 -0
  379. package/scripts/ops/build-x402-pilot-reliability-report.mjs +489 -0
  380. package/scripts/ops/check-x402-receipt-sample.mjs +181 -0
  381. package/scripts/ops/design-partner-run-packet.mjs +466 -0
  382. package/scripts/ops/dispute-finance-reconciliation-packet.mjs +313 -0
  383. package/scripts/ops/hosted-baseline-evidence.mjs +890 -0
  384. package/scripts/ops/money-rails-chargeback-evidence.mjs +509 -0
  385. package/scripts/ops/money-rails-reconcile-evidence.mjs +180 -0
  386. package/scripts/ops/p0-seed-money-rail-operation.mjs +432 -0
  387. package/scripts/ops/run-x402-hitl-smoke.mjs +607 -0
  388. package/scripts/pilot/finance-pack.mjs +495 -0
  389. package/scripts/pilot/fixtures/robot-keypair.json +4 -0
  390. package/scripts/pilot/fixtures/server-signer.json +4 -0
  391. package/scripts/policy/cli.mjs +600 -0
  392. package/scripts/profile/cli.mjs +1324 -0
  393. package/scripts/proof-bundle/job.mjs +109 -0
  394. package/scripts/proof-bundle/lib.mjs +92 -0
  395. package/scripts/proof-bundle/month.mjs +103 -0
  396. package/scripts/provider/conformance-run.mjs +159 -0
  397. package/scripts/provider/keys-generate.mjs +135 -0
  398. package/scripts/provider/publish.mjs +420 -0
  399. package/scripts/quickstart/x402.mjs +334 -0
  400. package/scripts/register-entity-secret.mjs +102 -0
  401. package/scripts/release/build-artifacts.mjs +181 -0
  402. package/scripts/release/generate-release-index.mjs +112 -0
  403. package/scripts/release/release-index-lib.mjs +232 -0
  404. package/scripts/release/sign-release-index.mjs +85 -0
  405. package/scripts/release/validate-release-assets.mjs +170 -0
  406. package/scripts/release/verify-release.mjs +261 -0
  407. package/scripts/restore-pg.sh +34 -0
  408. package/scripts/scaffold/create-settld-paid-tool.mjs +19 -0
  409. package/scripts/sdk/smoke-python.py +30 -0
  410. package/scripts/sdk/smoke.mjs +16 -0
  411. package/scripts/settlement/x402-batch-worker.mjs +1091 -0
  412. package/scripts/setup/circle-bootstrap.mjs +310 -0
  413. package/scripts/setup/host-config.mjs +617 -0
  414. package/scripts/setup/onboard.mjs +1337 -0
  415. package/scripts/setup/openclaw-onboard.mjs +423 -0
  416. package/scripts/setup/wizard.mjs +986 -0
  417. package/scripts/slo/check.mjs +239 -0
  418. package/scripts/smoke/k8s-smoke.mjs +214 -0
  419. package/scripts/spec/generate-protocol-vectors.mjs +1019 -0
  420. package/scripts/test/check-no-generated-artifacts.sh +12 -0
  421. package/scripts/test/run.sh +59 -0
  422. package/scripts/trust/validate-trust-file.mjs +57 -0
  423. package/scripts/trust-config/rotate-settld-pay.mjs +277 -0
  424. package/scripts/trust-config/wizard.mjs +161 -0
  425. package/scripts/vendor-contract-test-lib.mjs +182 -0
  426. package/scripts/vendor-contract-test.mjs +55 -0
  427. package/scripts/vercel/build-mkdocs.sh +9 -0
  428. package/scripts/vercel/ignore-mkdocs.sh +25 -0
  429. package/scripts/vercel/install-mkdocs.sh +6 -0
  430. package/scripts/verify-pg.js +217 -0
  431. package/scripts/x402/receipt-verify.mjs +289 -0
  432. package/services/finance-sink/src/dedupe-store.js +29 -6
  433. package/services/receiver/src/dedupe-store.js +29 -5
  434. package/services/x402-gateway/Dockerfile +13 -0
  435. package/services/x402-gateway/README.md +58 -0
  436. package/services/x402-gateway/examples/upstream-mock.js +337 -0
  437. package/services/x402-gateway/src/server.js +1058 -0
  438. package/src/api/app.js +34658 -16940
  439. package/src/api/maintenance.js +70 -0
  440. package/src/api/middleware/trust-kernel.js +114 -0
  441. package/src/api/openapi.js +1778 -70
  442. package/src/api/persistence.js +456 -0
  443. package/src/api/server.js +81 -5
  444. package/src/api/store.js +1581 -62
  445. package/src/api/workers/deliveries.js +99 -4
  446. package/src/api/workers/insolvency-sweep.js +159 -0
  447. package/src/core/agent-card.js +69 -0
  448. package/src/core/agent-wallets.js +231 -0
  449. package/src/core/agreement-delegation.js +549 -0
  450. package/src/core/billing-plans.js +40 -6
  451. package/src/core/circle-reserve-adapter.js +845 -0
  452. package/src/core/event-policy.js +21 -2
  453. package/src/core/maintenance-locks.js +1 -0
  454. package/src/core/operator-action.js +303 -0
  455. package/src/core/paid-tool-manifest.js +318 -0
  456. package/src/core/policy-decision.js +322 -0
  457. package/src/core/policy-packs.js +207 -0
  458. package/src/core/profile-fingerprint.js +27 -0
  459. package/src/core/profile-simulation-reasons.js +84 -0
  460. package/src/core/profile-templates.js +242 -0
  461. package/src/core/provider-publish-conformance.js +525 -0
  462. package/src/core/provider-publish-proof.js +396 -0
  463. package/src/core/provider-quote-signature.js +170 -0
  464. package/src/core/settld-keys.js +112 -0
  465. package/src/core/settld-pay-token.js +344 -0
  466. package/src/core/settlement-kernel.js +239 -2
  467. package/src/core/settlement-verifier.js +335 -0
  468. package/src/core/tool-call-agreement.js +112 -0
  469. package/src/core/tool-call-evidence.js +144 -0
  470. package/src/core/tool-provider-signature.js +98 -0
  471. package/src/core/wallet-assignment-resolver.js +129 -0
  472. package/src/core/wallet-provider-bootstrap.js +365 -0
  473. package/src/core/x402-escalation-override.js +258 -0
  474. package/src/core/x402-gate.js +118 -0
  475. package/src/core/x402-provider-refund-decision.js +220 -0
  476. package/src/core/x402-receipt-verifier.js +708 -0
  477. package/src/core/x402-reversal-command.js +251 -0
  478. package/src/core/x402-wallet-issuer-decision.js +252 -0
  479. package/src/core/zk-verifier.js +300 -0
  480. package/src/db/migrations/029_reputation_event_index.sql +54 -0
  481. package/src/db/migrations/030_artifacts_source_event_unique_job_only.sql +15 -0
  482. package/src/db/pg.js +18 -7
  483. package/src/db/store-pg.js +1508 -111
@@ -0,0 +1,251 @@
1
+ import { canonicalJsonStringify, normalizeForCanonicalJson } from "./canonical-json.js";
2
+ import { keyIdFromPublicKeyPem, sha256Hex, signHashHexEd25519, verifyHashHexEd25519 } from "./crypto.js";
3
+
4
+ export const X402_REVERSAL_COMMAND_PAYLOAD_SCHEMA_VERSION = "X402ReversalCommandPayload.v1";
5
+ export const X402_REVERSAL_COMMAND_SCHEMA_VERSION = "X402ReversalCommand.v1";
6
+ export const X402_REVERSAL_COMMAND_SIGNATURE_SCHEMA_VERSION = "X402ReversalCommandSignature.v1";
7
+
8
+ function assertNonEmptyString(value, name) {
9
+ if (typeof value !== "string" || value.trim() === "") throw new TypeError(`${name} must be a non-empty string`);
10
+ return value.trim();
11
+ }
12
+
13
+ function assertPemString(value, name) {
14
+ if (typeof value !== "string" || value.trim() === "") throw new TypeError(`${name} must be a non-empty PEM string`);
15
+ return value;
16
+ }
17
+
18
+ function assertIsoDateTime(value, name) {
19
+ const out = assertNonEmptyString(value, name);
20
+ if (!Number.isFinite(Date.parse(out))) throw new TypeError(`${name} must be an ISO date-time`);
21
+ return new Date(out).toISOString();
22
+ }
23
+
24
+ function assertSha256Hex(value, name) {
25
+ const out = assertNonEmptyString(value, name).toLowerCase();
26
+ if (!/^[0-9a-f]{64}$/.test(out)) throw new TypeError(`${name} must be sha256 hex`);
27
+ return out;
28
+ }
29
+
30
+ function assertOptionalSha256Hex(value, name) {
31
+ if (value === null || value === undefined || String(value).trim() === "") return null;
32
+ return assertSha256Hex(value, name);
33
+ }
34
+
35
+ function assertOptionalId(value, name, { max = 200 } = {}) {
36
+ if (value === null || value === undefined || String(value).trim() === "") return null;
37
+ const out = String(value).trim();
38
+ if (out.length > max) throw new TypeError(`${name} must be <= ${max} chars`);
39
+ if (!/^[A-Za-z0-9:._/-]+$/.test(out)) throw new TypeError(`${name} must match ^[A-Za-z0-9:._/-]+$`);
40
+ return out;
41
+ }
42
+
43
+ function assertAction(value, name = "action") {
44
+ const out = assertNonEmptyString(value, name).toLowerCase();
45
+ if (out !== "void_authorization" && out !== "request_refund" && out !== "resolve_refund") {
46
+ throw new TypeError(`${name} must be void_authorization|request_refund|resolve_refund`);
47
+ }
48
+ return out;
49
+ }
50
+
51
+ function assertTarget(value, name = "target") {
52
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new TypeError(`${name} must be an object`);
53
+ const gateId = assertOptionalId(value.gateId, `${name}.gateId`, { max: 200 });
54
+ const receiptId = assertOptionalId(value.receiptId, `${name}.receiptId`, { max: 200 });
55
+ if (!gateId) throw new TypeError(`${name}.gateId is required`);
56
+ if (!receiptId) throw new TypeError(`${name}.receiptId is required`);
57
+ const quoteId = assertOptionalId(value.quoteId, `${name}.quoteId`, { max: 200 });
58
+ const requestSha256 = assertOptionalSha256Hex(value.requestSha256, `${name}.requestSha256`);
59
+ return normalizeForCanonicalJson(
60
+ {
61
+ gateId,
62
+ receiptId,
63
+ ...(quoteId ? { quoteId } : {}),
64
+ ...(requestSha256 ? { requestSha256 } : {})
65
+ },
66
+ { path: "$" }
67
+ );
68
+ }
69
+
70
+ export function buildX402ReversalCommandPayloadV1({
71
+ commandId,
72
+ sponsorRef,
73
+ agentKeyId = null,
74
+ target,
75
+ action,
76
+ nonce,
77
+ idempotencyKey,
78
+ exp
79
+ } = {}) {
80
+ const payload = normalizeForCanonicalJson(
81
+ {
82
+ schemaVersion: X402_REVERSAL_COMMAND_PAYLOAD_SCHEMA_VERSION,
83
+ commandId: assertOptionalId(commandId, "commandId", { max: 200 }) ?? (() => {
84
+ throw new TypeError("commandId is required");
85
+ })(),
86
+ sponsorRef: assertOptionalId(sponsorRef, "sponsorRef", { max: 200 }) ?? (() => {
87
+ throw new TypeError("sponsorRef is required");
88
+ })(),
89
+ ...(assertOptionalId(agentKeyId, "agentKeyId", { max: 200 }) ? { agentKeyId: assertOptionalId(agentKeyId, "agentKeyId", { max: 200 }) } : {}),
90
+ target: assertTarget(target, "target"),
91
+ action: assertAction(action, "action"),
92
+ nonce: assertOptionalId(nonce, "nonce", { max: 256 }) ?? (() => {
93
+ throw new TypeError("nonce is required");
94
+ })(),
95
+ idempotencyKey: assertOptionalId(idempotencyKey, "idempotencyKey", { max: 256 }) ?? (() => {
96
+ throw new TypeError("idempotencyKey is required");
97
+ })(),
98
+ exp: assertIsoDateTime(exp, "exp")
99
+ },
100
+ { path: "$" }
101
+ );
102
+ return payload;
103
+ }
104
+
105
+ export function computeX402ReversalCommandPayloadHashV1({ payload } = {}) {
106
+ const normalizedPayload = buildX402ReversalCommandPayloadV1(payload ?? {});
107
+ return sha256Hex(canonicalJsonStringify(normalizedPayload));
108
+ }
109
+
110
+ function normalizeCommandEnvelope(command) {
111
+ if (!command || typeof command !== "object" || Array.isArray(command)) throw new TypeError("command must be an object");
112
+ const payload = buildX402ReversalCommandPayloadV1(command);
113
+ const signature = command.signature;
114
+ if (!signature || typeof signature !== "object" || Array.isArray(signature)) throw new TypeError("command.signature must be an object");
115
+ if (String(signature.schemaVersion ?? "") !== X402_REVERSAL_COMMAND_SIGNATURE_SCHEMA_VERSION) {
116
+ throw new TypeError(`command.signature.schemaVersion must be ${X402_REVERSAL_COMMAND_SIGNATURE_SCHEMA_VERSION}`);
117
+ }
118
+ if (String(signature.algorithm ?? "").toLowerCase() !== "ed25519") throw new TypeError("command.signature.algorithm must be ed25519");
119
+ return {
120
+ schemaVersion: command.schemaVersion ?? X402_REVERSAL_COMMAND_SCHEMA_VERSION,
121
+ payload,
122
+ signature: normalizeForCanonicalJson(
123
+ {
124
+ schemaVersion: X402_REVERSAL_COMMAND_SIGNATURE_SCHEMA_VERSION,
125
+ algorithm: "ed25519",
126
+ keyId: assertNonEmptyString(signature.keyId, "command.signature.keyId"),
127
+ signedAt: assertIsoDateTime(signature.signedAt, "command.signature.signedAt"),
128
+ payloadHash: assertSha256Hex(signature.payloadHash, "command.signature.payloadHash"),
129
+ signatureBase64: assertNonEmptyString(signature.signatureBase64, "command.signature.signatureBase64")
130
+ },
131
+ { path: "$" }
132
+ )
133
+ };
134
+ }
135
+
136
+ export function signX402ReversalCommandV1({ command, signedAt, publicKeyPem, privateKeyPem } = {}) {
137
+ const payload = buildX402ReversalCommandPayloadV1(command ?? {});
138
+ const signerPublicKeyPem = assertPemString(publicKeyPem, "publicKeyPem");
139
+ const signerPrivateKeyPem = assertPemString(privateKeyPem, "privateKeyPem");
140
+ const payloadHash = computeX402ReversalCommandPayloadHashV1({ payload });
141
+ const signatureBase64 = signHashHexEd25519(payloadHash, signerPrivateKeyPem);
142
+ const payloadFields = { ...payload };
143
+ delete payloadFields.schemaVersion;
144
+ return normalizeForCanonicalJson(
145
+ {
146
+ schemaVersion: X402_REVERSAL_COMMAND_SCHEMA_VERSION,
147
+ ...payloadFields,
148
+ signature: {
149
+ schemaVersion: X402_REVERSAL_COMMAND_SIGNATURE_SCHEMA_VERSION,
150
+ algorithm: "ed25519",
151
+ keyId: keyIdFromPublicKeyPem(signerPublicKeyPem),
152
+ signedAt: assertIsoDateTime(signedAt, "signedAt"),
153
+ payloadHash,
154
+ signatureBase64
155
+ }
156
+ },
157
+ { path: "$" }
158
+ );
159
+ }
160
+
161
+ export function verifyX402ReversalCommandV1({
162
+ command,
163
+ publicKeyPem,
164
+ nowAt = new Date().toISOString(),
165
+ expectedAction = null,
166
+ expectedSponsorRef = null,
167
+ expectedGateId = null,
168
+ expectedReceiptId = null,
169
+ expectedQuoteId = null,
170
+ expectedRequestSha256 = null
171
+ } = {}) {
172
+ try {
173
+ const signerPublicKeyPem = assertPemString(publicKeyPem, "publicKeyPem");
174
+ const normalized = normalizeCommandEnvelope(command);
175
+ if (String(normalized.schemaVersion ?? "") !== X402_REVERSAL_COMMAND_SCHEMA_VERSION) {
176
+ return { ok: false, code: "X402_REVERSAL_COMMAND_SCHEMA_INVALID", error: "invalid schemaVersion" };
177
+ }
178
+ const expectedKeyId = keyIdFromPublicKeyPem(signerPublicKeyPem);
179
+ if (normalized.signature.keyId !== expectedKeyId) {
180
+ return { ok: false, code: "X402_REVERSAL_COMMAND_KEY_ID_MISMATCH", error: "signature keyId mismatch" };
181
+ }
182
+
183
+ const payloadHash = computeX402ReversalCommandPayloadHashV1({ payload: normalized.payload });
184
+ if (normalized.signature.payloadHash !== payloadHash) {
185
+ return { ok: false, code: "X402_REVERSAL_COMMAND_PAYLOAD_HASH_MISMATCH", error: "payload hash mismatch" };
186
+ }
187
+ const signatureValid = verifyHashHexEd25519({
188
+ hashHex: payloadHash,
189
+ signatureBase64: normalized.signature.signatureBase64,
190
+ publicKeyPem: signerPublicKeyPem
191
+ });
192
+ if (!signatureValid) {
193
+ return { ok: false, code: "X402_REVERSAL_COMMAND_SIGNATURE_INVALID", error: "signature invalid" };
194
+ }
195
+
196
+ const nowMs = Date.parse(assertIsoDateTime(nowAt, "nowAt"));
197
+ const expMs = Date.parse(normalized.payload.exp);
198
+ if (!Number.isFinite(expMs) || expMs <= nowMs) {
199
+ return { ok: false, code: "X402_REVERSAL_COMMAND_EXPIRED", error: "command expired" };
200
+ }
201
+
202
+ if (expectedAction !== null && assertAction(expectedAction, "expectedAction") !== normalized.payload.action) {
203
+ return { ok: false, code: "X402_REVERSAL_COMMAND_ACTION_MISMATCH", error: "action mismatch" };
204
+ }
205
+ if (expectedSponsorRef !== null) {
206
+ const expected = assertOptionalId(expectedSponsorRef, "expectedSponsorRef", { max: 200 });
207
+ if (expected !== normalized.payload.sponsorRef) {
208
+ return { ok: false, code: "X402_REVERSAL_COMMAND_SPONSOR_MISMATCH", error: "sponsorRef mismatch" };
209
+ }
210
+ }
211
+ if (expectedGateId !== null) {
212
+ const expected = assertOptionalId(expectedGateId, "expectedGateId", { max: 200 });
213
+ if (expected !== normalized.payload.target.gateId) {
214
+ return { ok: false, code: "X402_REVERSAL_COMMAND_GATE_MISMATCH", error: "target.gateId mismatch" };
215
+ }
216
+ }
217
+ if (expectedReceiptId !== null) {
218
+ const expected = assertOptionalId(expectedReceiptId, "expectedReceiptId", { max: 200 });
219
+ if (expected !== normalized.payload.target.receiptId) {
220
+ return { ok: false, code: "X402_REVERSAL_COMMAND_RECEIPT_MISMATCH", error: "target.receiptId mismatch" };
221
+ }
222
+ }
223
+ if (expectedQuoteId !== null) {
224
+ const expected = assertOptionalId(expectedQuoteId, "expectedQuoteId", { max: 200 });
225
+ if (expected !== normalized.payload.target.quoteId) {
226
+ return { ok: false, code: "X402_REVERSAL_COMMAND_QUOTE_MISMATCH", error: "target.quoteId mismatch" };
227
+ }
228
+ }
229
+ if (expectedRequestSha256 !== null) {
230
+ const expected = assertOptionalSha256Hex(expectedRequestSha256, "expectedRequestSha256");
231
+ if (expected !== normalized.payload.target.requestSha256) {
232
+ return { ok: false, code: "X402_REVERSAL_COMMAND_REQUEST_HASH_MISMATCH", error: "target.requestSha256 mismatch" };
233
+ }
234
+ }
235
+
236
+ return {
237
+ ok: true,
238
+ code: null,
239
+ error: null,
240
+ payload: normalized.payload,
241
+ payloadHash,
242
+ keyId: normalized.signature.keyId
243
+ };
244
+ } catch (err) {
245
+ return {
246
+ ok: false,
247
+ code: "X402_REVERSAL_COMMAND_SCHEMA_INVALID",
248
+ error: err?.message ?? String(err ?? "")
249
+ };
250
+ }
251
+ }
@@ -0,0 +1,252 @@
1
+ import { canonicalJsonStringify, normalizeForCanonicalJson } from "./canonical-json.js";
2
+ import { keyIdFromPublicKeyPem, sha256Hex, signHashHexEd25519, verifyHashHexEd25519 } from "./crypto.js";
3
+
4
+ export const X402_WALLET_ISSUER_DECISION_TOKEN_VERSION = 1;
5
+
6
+ function assertNonEmptyString(value, name) {
7
+ if (typeof value !== "string" || value.trim() === "") throw new TypeError(`${name} must be a non-empty string`);
8
+ return String(value).trim();
9
+ }
10
+
11
+ function assertPositiveSafeInt(value, name) {
12
+ const n = Number(value);
13
+ if (!Number.isSafeInteger(n) || n <= 0) throw new TypeError(`${name} must be a positive safe integer`);
14
+ return n;
15
+ }
16
+
17
+ function assertOptionalId(value, name, { max = 200 } = {}) {
18
+ if (value === null || value === undefined || String(value).trim() === "") return null;
19
+ const out = String(value).trim();
20
+ if (out.length > max) throw new TypeError(`${name} must be <= ${max} chars`);
21
+ if (!/^[A-Za-z0-9:._/-]+$/.test(out)) throw new TypeError(`${name} must match ^[A-Za-z0-9:._/-]+$`);
22
+ return out;
23
+ }
24
+
25
+ function assertOptionalSha256Hex(value, name) {
26
+ if (value === null || value === undefined || String(value).trim() === "") return null;
27
+ const out = String(value).trim().toLowerCase();
28
+ if (!/^[0-9a-f]{64}$/.test(out)) throw new TypeError(`${name} must be sha256 hex`);
29
+ return out;
30
+ }
31
+
32
+ function normalizeCurrency(value, name) {
33
+ const raw = typeof value === "string" && value.trim() !== "" ? value : "USD";
34
+ const out = raw.trim().toUpperCase();
35
+ if (!/^[A-Z][A-Z0-9_]{2,11}$/.test(out)) throw new TypeError(`${name} must match ^[A-Z][A-Z0-9_]{2,11}$`);
36
+ return out;
37
+ }
38
+
39
+ function normalizeOptionalRequestBindingMode(value, name) {
40
+ if (value === null || value === undefined || String(value).trim() === "") return null;
41
+ const mode = String(value).trim().toLowerCase();
42
+ if (mode !== "strict") throw new TypeError(`${name} must be strict when provided`);
43
+ return mode;
44
+ }
45
+
46
+ function normalizeUnixSeconds(value, name) {
47
+ const n = Number(value);
48
+ if (!Number.isSafeInteger(n) || n <= 0) throw new TypeError(`${name} must be a positive safe integer unix timestamp`);
49
+ return n;
50
+ }
51
+
52
+ function decodeEnvelope(token) {
53
+ const raw = assertNonEmptyString(token, "token");
54
+ let decoded = null;
55
+ try {
56
+ decoded = Buffer.from(raw, "base64url").toString("utf8");
57
+ } catch (err) {
58
+ throw new TypeError(`token is not valid base64url: ${err?.message ?? String(err ?? "")}`);
59
+ }
60
+ let parsed = null;
61
+ try {
62
+ parsed = JSON.parse(decoded);
63
+ } catch (err) {
64
+ throw new TypeError(`token is not valid JSON envelope: ${err?.message ?? String(err ?? "")}`);
65
+ }
66
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new TypeError("token envelope must be an object");
67
+ if (Number(parsed.v) !== X402_WALLET_ISSUER_DECISION_TOKEN_VERSION) {
68
+ throw new TypeError(`token envelope version must be ${X402_WALLET_ISSUER_DECISION_TOKEN_VERSION}`);
69
+ }
70
+ const kid = assertNonEmptyString(parsed.kid, "token.kid");
71
+ if (!parsed.payload || typeof parsed.payload !== "object" || Array.isArray(parsed.payload)) {
72
+ throw new TypeError("token.payload must be an object");
73
+ }
74
+ const sig = assertNonEmptyString(parsed.sig, "token.sig");
75
+ return { envelope: parsed, kid, payload: parsed.payload, sig };
76
+ }
77
+
78
+ export function buildX402WalletIssuerDecisionPayloadV1({
79
+ decisionId,
80
+ gateId,
81
+ sponsorRef,
82
+ sponsorWalletRef,
83
+ policyRef,
84
+ policyVersion,
85
+ policyFingerprint,
86
+ amountCents,
87
+ currency = "USD",
88
+ payeeProviderId,
89
+ quoteId = null,
90
+ quoteSha256 = null,
91
+ requestBindingMode = null,
92
+ requestBindingSha256 = null,
93
+ idempotencyKey,
94
+ nonce,
95
+ iat,
96
+ exp
97
+ } = {}) {
98
+ const normalizedIat = normalizeUnixSeconds(iat, "iat");
99
+ const normalizedExp = normalizeUnixSeconds(exp, "exp");
100
+ if (normalizedExp <= normalizedIat) throw new TypeError("exp must be greater than iat");
101
+ const normalizedRequestBindingSha256 = assertOptionalSha256Hex(requestBindingSha256, "requestBindingSha256");
102
+ const normalizedRequestBindingMode =
103
+ normalizeOptionalRequestBindingMode(requestBindingMode, "requestBindingMode") ??
104
+ (normalizedRequestBindingSha256 ? "strict" : null);
105
+ if (normalizedRequestBindingMode === "strict" && !normalizedRequestBindingSha256) {
106
+ throw new TypeError("requestBindingSha256 is required when requestBindingMode=strict");
107
+ }
108
+
109
+ return normalizeForCanonicalJson(
110
+ {
111
+ schemaVersion: "X402WalletIssuerDecisionPayload.v1",
112
+ decisionId: assertOptionalId(decisionId, "decisionId", { max: 200 }) ?? (() => {
113
+ throw new TypeError("decisionId is required");
114
+ })(),
115
+ gateId: assertOptionalId(gateId, "gateId", { max: 200 }) ?? (() => {
116
+ throw new TypeError("gateId is required");
117
+ })(),
118
+ sponsorRef: assertOptionalId(sponsorRef, "sponsorRef", { max: 200 }) ?? (() => {
119
+ throw new TypeError("sponsorRef is required");
120
+ })(),
121
+ sponsorWalletRef: assertOptionalId(sponsorWalletRef, "sponsorWalletRef", { max: 200 }) ?? (() => {
122
+ throw new TypeError("sponsorWalletRef is required");
123
+ })(),
124
+ policyRef: assertOptionalId(policyRef, "policyRef", { max: 200 }) ?? (() => {
125
+ throw new TypeError("policyRef is required");
126
+ })(),
127
+ policyVersion: assertPositiveSafeInt(policyVersion, "policyVersion"),
128
+ policyFingerprint: assertOptionalSha256Hex(policyFingerprint, "policyFingerprint") ?? (() => {
129
+ throw new TypeError("policyFingerprint is required");
130
+ })(),
131
+ amountCents: assertPositiveSafeInt(amountCents, "amountCents"),
132
+ currency: normalizeCurrency(currency, "currency"),
133
+ payeeProviderId: assertOptionalId(payeeProviderId, "payeeProviderId", { max: 200 }) ?? (() => {
134
+ throw new TypeError("payeeProviderId is required");
135
+ })(),
136
+ ...(assertOptionalId(quoteId, "quoteId", { max: 200 }) ? { quoteId: assertOptionalId(quoteId, "quoteId", { max: 200 }) } : {}),
137
+ ...(assertOptionalSha256Hex(quoteSha256, "quoteSha256") ? { quoteSha256: assertOptionalSha256Hex(quoteSha256, "quoteSha256") } : {}),
138
+ ...(normalizedRequestBindingMode ? { requestBindingMode: normalizedRequestBindingMode } : {}),
139
+ ...(normalizedRequestBindingSha256 ? { requestBindingSha256: normalizedRequestBindingSha256 } : {}),
140
+ idempotencyKey: assertOptionalId(idempotencyKey, "idempotencyKey", { max: 256 }) ?? (() => {
141
+ throw new TypeError("idempotencyKey is required");
142
+ })(),
143
+ nonce: assertOptionalId(nonce, "nonce", { max: 256 }) ?? (() => {
144
+ throw new TypeError("nonce is required");
145
+ })(),
146
+ iat: normalizedIat,
147
+ exp: normalizedExp
148
+ },
149
+ { path: "$" }
150
+ );
151
+ }
152
+
153
+ export function computeX402WalletIssuerDecisionPayloadHashV1(payload) {
154
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) throw new TypeError("payload must be an object");
155
+ return sha256Hex(canonicalJsonStringify(payload));
156
+ }
157
+
158
+ export function mintX402WalletIssuerDecisionTokenV1({ payload, keyId = null, publicKeyPem = null, privateKeyPem } = {}) {
159
+ const normalizedPayload = buildX402WalletIssuerDecisionPayloadV1(payload ?? {});
160
+ const privatePem = assertNonEmptyString(privateKeyPem, "privateKeyPem");
161
+ const publicPem = publicKeyPem === null || publicKeyPem === undefined ? null : assertNonEmptyString(publicKeyPem, "publicKeyPem");
162
+ const derivedKeyId = publicPem ? keyIdFromPublicKeyPem(publicPem) : null;
163
+ const normalizedKeyId = keyId === null || keyId === undefined || String(keyId).trim() === "" ? derivedKeyId : String(keyId).trim();
164
+ if (!normalizedKeyId) throw new TypeError("keyId is required (or provide publicKeyPem)");
165
+ if (derivedKeyId && normalizedKeyId !== derivedKeyId) throw new TypeError("keyId does not match publicKeyPem");
166
+
167
+ const payloadHashHex = computeX402WalletIssuerDecisionPayloadHashV1(normalizedPayload);
168
+ const signatureBase64 = signHashHexEd25519(payloadHashHex, privatePem);
169
+ const envelope = normalizeForCanonicalJson(
170
+ {
171
+ v: X402_WALLET_ISSUER_DECISION_TOKEN_VERSION,
172
+ kid: normalizedKeyId,
173
+ payload: normalizedPayload,
174
+ sig: Buffer.from(signatureBase64, "base64").toString("base64url")
175
+ },
176
+ { path: "$" }
177
+ );
178
+ const token = Buffer.from(canonicalJsonStringify(envelope), "utf8").toString("base64url");
179
+ return {
180
+ token,
181
+ envelope,
182
+ kid: normalizedKeyId,
183
+ payload: normalizedPayload,
184
+ payloadHashHex,
185
+ tokenSha256: sha256Hex(token)
186
+ };
187
+ }
188
+
189
+ export function verifyX402WalletIssuerDecisionTokenV1({
190
+ token,
191
+ publicKeyPem,
192
+ nowUnixSeconds = Math.floor(Date.now() / 1000),
193
+ expected = {}
194
+ } = {}) {
195
+ try {
196
+ const { kid, payload, sig } = decodeEnvelope(token);
197
+ const normalizedPayload = buildX402WalletIssuerDecisionPayloadV1(payload);
198
+ const expectedKeyId = keyIdFromPublicKeyPem(assertNonEmptyString(publicKeyPem, "publicKeyPem"));
199
+ if (kid !== expectedKeyId) return { ok: false, code: "X402_WALLET_ISSUER_DECISION_KEY_MISMATCH", kid };
200
+ const payloadHashHex = computeX402WalletIssuerDecisionPayloadHashV1(normalizedPayload);
201
+ const signatureBase64 = Buffer.from(sig, "base64url").toString("base64");
202
+ if (!verifyHashHexEd25519({ hashHex: payloadHashHex, signatureBase64, publicKeyPem })) {
203
+ return { ok: false, code: "X402_WALLET_ISSUER_DECISION_SIGNATURE_INVALID", kid };
204
+ }
205
+ if (!Number.isSafeInteger(nowUnixSeconds) || nowUnixSeconds <= 0) {
206
+ throw new TypeError("nowUnixSeconds must be a positive safe integer");
207
+ }
208
+ if (normalizedPayload.exp <= nowUnixSeconds) {
209
+ return { ok: false, code: "X402_WALLET_ISSUER_DECISION_EXPIRED", kid };
210
+ }
211
+
212
+ const expectedFields = [
213
+ "gateId",
214
+ "sponsorRef",
215
+ "sponsorWalletRef",
216
+ "policyRef",
217
+ "policyVersion",
218
+ "policyFingerprint",
219
+ "amountCents",
220
+ "currency",
221
+ "payeeProviderId",
222
+ "quoteId",
223
+ "quoteSha256",
224
+ "requestBindingMode",
225
+ "requestBindingSha256"
226
+ ];
227
+ for (const field of expectedFields) {
228
+ if (!Object.prototype.hasOwnProperty.call(expected, field)) continue;
229
+ const expectedValueRaw = expected[field];
230
+ const expectedValue = expectedValueRaw === null ? null : String(expectedValueRaw);
231
+ const actualValue = normalizedPayload[field] === undefined || normalizedPayload[field] === null ? null : String(normalizedPayload[field]);
232
+ if (expectedValue !== actualValue) {
233
+ return { ok: false, code: "X402_WALLET_ISSUER_DECISION_MISMATCH", field, expected: expectedValue, actual: actualValue, kid };
234
+ }
235
+ }
236
+
237
+ return {
238
+ ok: true,
239
+ code: null,
240
+ kid,
241
+ payload: normalizedPayload,
242
+ payloadHashHex,
243
+ tokenSha256: sha256Hex(assertNonEmptyString(token, "token"))
244
+ };
245
+ } catch (err) {
246
+ return {
247
+ ok: false,
248
+ code: "X402_WALLET_ISSUER_DECISION_SCHEMA_INVALID",
249
+ error: err?.message ?? String(err ?? "")
250
+ };
251
+ }
252
+ }