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,396 @@
1
+ import { createPublicKey, verify as nodeVerify, sign as nodeSign } from "node:crypto";
2
+
3
+ import { canonicalJsonStringify, normalizeForCanonicalJson } from "./canonical-json.js";
4
+ import { checkUrlSafety } from "./url-safety.js";
5
+ import { keyIdFromPublicKeyPem, sha256Hex } from "./crypto.js";
6
+ import { keyMapFromSettldKeyset } from "./settld-keys.js";
7
+
8
+ export const PROVIDER_PUBLISH_PROOF_AUDIENCE = "settld.marketplace.publish";
9
+ export const PROVIDER_PUBLISH_PROOF_TYPE = "settld.marketplace.publish_proof.v1";
10
+ export const PROVIDER_PUBLISH_PROOF_SCHEMA_VERSION = "ProviderPublishProofPayload.v1";
11
+
12
+ function assertNonEmptyString(value, name) {
13
+ if (typeof value !== "string" || value.trim() === "") throw new TypeError(`${name} must be a non-empty string`);
14
+ return String(value).trim();
15
+ }
16
+
17
+ function assertNonEmptyPem(value, name) {
18
+ if (typeof value !== "string" || value.trim() === "") throw new TypeError(`${name} must be a non-empty string`);
19
+ return String(value);
20
+ }
21
+
22
+ function normalizeUnixSeconds(value, name) {
23
+ const n = Number(value);
24
+ if (!Number.isSafeInteger(n) || n <= 0) throw new TypeError(`${name} must be a positive safe integer unix timestamp`);
25
+ return n;
26
+ }
27
+
28
+ function normalizeSha256Hex(value, name) {
29
+ const out = assertNonEmptyString(value, name).toLowerCase();
30
+ if (!/^[0-9a-f]{64}$/.test(out)) throw new TypeError(`${name} must be sha256 hex`);
31
+ return out;
32
+ }
33
+
34
+ function normalizeOptionalText(value, name, { max = 256 } = {}) {
35
+ if (value === null || value === undefined || String(value).trim() === "") return null;
36
+ const out = String(value).trim();
37
+ if (out.length > max) throw new TypeError(`${name} must be <= ${max} chars`);
38
+ return out;
39
+ }
40
+
41
+ function b64urlJson(value) {
42
+ return Buffer.from(canonicalJsonStringify(normalizeForCanonicalJson(value, { path: "$" })), "utf8").toString("base64url");
43
+ }
44
+
45
+ function parseCompactJws(token) {
46
+ const raw = assertNonEmptyString(token, "publishProof");
47
+ const parts = raw.split(".");
48
+ if (parts.length !== 3) throw new TypeError("publishProof must be compact JWS with 3 segments");
49
+ const [headerB64, payloadB64, sigB64] = parts;
50
+ if (!headerB64 || !payloadB64 || !sigB64) throw new TypeError("publishProof contains empty JWS segment");
51
+
52
+ let header = null;
53
+ let payload = null;
54
+ let signature = null;
55
+ try {
56
+ header = JSON.parse(Buffer.from(headerB64, "base64url").toString("utf8"));
57
+ } catch (err) {
58
+ throw new TypeError(`publishProof header is invalid: ${err?.message ?? String(err ?? "")}`);
59
+ }
60
+ try {
61
+ payload = JSON.parse(Buffer.from(payloadB64, "base64url").toString("utf8"));
62
+ } catch (err) {
63
+ throw new TypeError(`publishProof payload is invalid: ${err?.message ?? String(err ?? "")}`);
64
+ }
65
+ try {
66
+ signature = Buffer.from(sigB64, "base64url");
67
+ } catch (err) {
68
+ throw new TypeError(`publishProof signature is invalid: ${err?.message ?? String(err ?? "")}`);
69
+ }
70
+ if (!header || typeof header !== "object" || Array.isArray(header)) throw new TypeError("publishProof header must be an object");
71
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) throw new TypeError("publishProof payload must be an object");
72
+ if (signature.length === 0) throw new TypeError("publishProof signature must be non-empty");
73
+ return {
74
+ token: raw,
75
+ header,
76
+ payload,
77
+ signature,
78
+ signingInput: `${headerB64}.${payloadB64}`
79
+ };
80
+ }
81
+
82
+ function normalizeOkpEd25519Jwk(input, fieldPath = "jwk") {
83
+ if (!input || typeof input !== "object" || Array.isArray(input)) throw new TypeError(`${fieldPath} must be an object`);
84
+ const kty = assertNonEmptyString(input.kty, `${fieldPath}.kty`);
85
+ const crv = assertNonEmptyString(input.crv, `${fieldPath}.crv`);
86
+ const x = assertNonEmptyString(input.x, `${fieldPath}.x`);
87
+ if (kty !== "OKP") throw new TypeError(`${fieldPath}.kty must be OKP`);
88
+ if (crv !== "Ed25519") throw new TypeError(`${fieldPath}.crv must be Ed25519`);
89
+ return normalizeForCanonicalJson({ kty: "OKP", crv: "Ed25519", x }, { path: "$" });
90
+ }
91
+
92
+ function keyEntryToKeyEvidence(keyEntry, expectedKid) {
93
+ if (!keyEntry || typeof keyEntry !== "object" || Array.isArray(keyEntry)) {
94
+ throw new TypeError("keyEntry must be an object");
95
+ }
96
+ const publicKeyPem = assertNonEmptyPem(keyEntry.publicKeyPem, "keyEntry.publicKeyPem");
97
+ const derivedKid = keyIdFromPublicKeyPem(publicKeyPem);
98
+ const kid = expectedKid ? assertNonEmptyString(expectedKid, "kid") : derivedKid;
99
+ if (kid !== derivedKid) throw new TypeError("publish proof kid does not match resolved public key");
100
+
101
+ let jwk = null;
102
+ if (keyEntry.kty || keyEntry.crv || keyEntry.x) {
103
+ jwk = normalizeOkpEd25519Jwk(keyEntry, "jwks.keys[]");
104
+ } else {
105
+ const exported = createPublicKey(publicKeyPem).export({ format: "jwk" });
106
+ jwk = normalizeOkpEd25519Jwk(exported, "publicKeyPem.jwk");
107
+ }
108
+ const jwkThumbprintSha256 = sha256Hex(canonicalJsonStringify(jwk));
109
+ return normalizeForCanonicalJson(
110
+ {
111
+ schemaVersion: "VerificationKeyEvidence.v1",
112
+ keyId: kid,
113
+ publicKeyPem,
114
+ jwk,
115
+ jwkThumbprintSha256
116
+ },
117
+ { path: "$" }
118
+ );
119
+ }
120
+
121
+ export function computeProviderRefFromPublishProofJwk(jwkInput) {
122
+ const jwk = normalizeOkpEd25519Jwk(jwkInput, "jwk");
123
+ const thumbprint = sha256Hex(canonicalJsonStringify(jwk));
124
+ return `jwk:${thumbprint}`;
125
+ }
126
+
127
+ export function buildProviderPublishProofPayloadV1({
128
+ aud = PROVIDER_PUBLISH_PROOF_AUDIENCE,
129
+ typ = PROVIDER_PUBLISH_PROOF_TYPE,
130
+ manifestHash,
131
+ providerId,
132
+ iat,
133
+ exp,
134
+ nonce = null
135
+ } = {}) {
136
+ const normalizedIat = normalizeUnixSeconds(iat, "iat");
137
+ const normalizedExp = normalizeUnixSeconds(exp, "exp");
138
+ if (normalizedExp <= normalizedIat) throw new TypeError("exp must be greater than iat");
139
+ return normalizeForCanonicalJson(
140
+ {
141
+ schemaVersion: PROVIDER_PUBLISH_PROOF_SCHEMA_VERSION,
142
+ aud: assertNonEmptyString(aud, "aud"),
143
+ typ: assertNonEmptyString(typ, "typ"),
144
+ manifestHash: normalizeSha256Hex(manifestHash, "manifestHash"),
145
+ providerId: assertNonEmptyString(providerId, "providerId"),
146
+ iat: normalizedIat,
147
+ exp: normalizedExp,
148
+ ...(normalizeOptionalText(nonce, "nonce", { max: 256 }) ? { nonce: normalizeOptionalText(nonce, "nonce", { max: 256 }) } : {})
149
+ },
150
+ { path: "$" }
151
+ );
152
+ }
153
+
154
+ export function mintProviderPublishProofTokenV1({ payload, keyId = null, publicKeyPem = null, privateKeyPem } = {}) {
155
+ const normalizedPayload = buildProviderPublishProofPayloadV1(payload ?? {});
156
+ const privatePem = assertNonEmptyPem(privateKeyPem, "privateKeyPem");
157
+ const normalizedPublicKeyPem =
158
+ publicKeyPem === null || publicKeyPem === undefined ? null : assertNonEmptyPem(publicKeyPem, "publicKeyPem");
159
+ const derivedKid = normalizedPublicKeyPem ? keyIdFromPublicKeyPem(normalizedPublicKeyPem) : null;
160
+ const normalizedKid = keyId === null || keyId === undefined || String(keyId).trim() === "" ? derivedKid : String(keyId).trim();
161
+ if (!normalizedKid) throw new TypeError("keyId is required (or provide publicKeyPem)");
162
+ if (derivedKid && normalizedKid !== derivedKid) throw new TypeError("keyId does not match publicKeyPem");
163
+
164
+ const header = normalizeForCanonicalJson(
165
+ {
166
+ alg: "EdDSA",
167
+ kid: normalizedKid,
168
+ typ: "JWT"
169
+ },
170
+ { path: "$" }
171
+ );
172
+ const headerB64 = b64urlJson(header);
173
+ const payloadB64 = b64urlJson(normalizedPayload);
174
+ const signingInput = `${headerB64}.${payloadB64}`;
175
+ const signature = nodeSign(null, Buffer.from(signingInput, "utf8"), privatePem);
176
+ const token = `${signingInput}.${signature.toString("base64url")}`;
177
+
178
+ return {
179
+ token,
180
+ tokenSha256: sha256Hex(token),
181
+ header,
182
+ payload: normalizedPayload,
183
+ kid: normalizedKid
184
+ };
185
+ }
186
+
187
+ export function verifyProviderPublishProofTokenV1({
188
+ token,
189
+ jwks,
190
+ expectedManifestHash,
191
+ expectedProviderId,
192
+ expectedAudience = PROVIDER_PUBLISH_PROOF_AUDIENCE,
193
+ expectedType = PROVIDER_PUBLISH_PROOF_TYPE,
194
+ nowUnixSeconds = Math.floor(Date.now() / 1000)
195
+ } = {}) {
196
+ try {
197
+ const parsed = parseCompactJws(token);
198
+ const alg = assertNonEmptyString(parsed.header.alg, "publishProof.header.alg");
199
+ if (alg !== "EdDSA") {
200
+ return { ok: false, code: "PROVIDER_PUBLISH_PROOF_ALG_INVALID", message: "publishProof.header.alg must be EdDSA" };
201
+ }
202
+ const kid = assertNonEmptyString(parsed.header.kid, "publishProof.header.kid");
203
+ if (!Number.isSafeInteger(nowUnixSeconds) || nowUnixSeconds <= 0) {
204
+ throw new TypeError("nowUnixSeconds must be a positive safe integer");
205
+ }
206
+
207
+ const payload = buildProviderPublishProofPayloadV1(parsed.payload);
208
+ if (payload.aud !== expectedAudience) {
209
+ return {
210
+ ok: false,
211
+ code: "PROVIDER_PUBLISH_PROOF_AUD_MISMATCH",
212
+ message: "publish proof aud mismatch",
213
+ expected: expectedAudience,
214
+ actual: payload.aud
215
+ };
216
+ }
217
+ if (payload.typ !== expectedType) {
218
+ return {
219
+ ok: false,
220
+ code: "PROVIDER_PUBLISH_PROOF_TYPE_MISMATCH",
221
+ message: "publish proof typ mismatch",
222
+ expected: expectedType,
223
+ actual: payload.typ
224
+ };
225
+ }
226
+
227
+ const expectedManifest = normalizeSha256Hex(expectedManifestHash, "expectedManifestHash");
228
+ if (payload.manifestHash !== expectedManifest) {
229
+ return {
230
+ ok: false,
231
+ code: "PROVIDER_PUBLISH_PROOF_MANIFEST_HASH_MISMATCH",
232
+ message: "publish proof manifest hash mismatch",
233
+ expected: expectedManifest,
234
+ actual: payload.manifestHash
235
+ };
236
+ }
237
+
238
+ const expectedProvider = assertNonEmptyString(expectedProviderId, "expectedProviderId");
239
+ if (payload.providerId !== expectedProvider) {
240
+ return {
241
+ ok: false,
242
+ code: "PROVIDER_PUBLISH_PROOF_PROVIDER_MISMATCH",
243
+ message: "publish proof providerId mismatch",
244
+ expected: expectedProvider,
245
+ actual: payload.providerId
246
+ };
247
+ }
248
+
249
+ if (payload.exp <= nowUnixSeconds) {
250
+ return { ok: false, code: "PROVIDER_PUBLISH_PROOF_EXPIRED", message: "publish proof is expired" };
251
+ }
252
+ if (payload.iat > nowUnixSeconds + 300) {
253
+ return { ok: false, code: "PROVIDER_PUBLISH_PROOF_IAT_FUTURE", message: "publish proof iat is too far in the future" };
254
+ }
255
+
256
+ const keyMap = keyMapFromSettldKeyset(jwks);
257
+ const keyEntry = keyMap.get(kid) ?? null;
258
+ if (!keyEntry?.publicKeyPem) {
259
+ return { ok: false, code: "PROVIDER_PUBLISH_PROOF_UNKNOWN_KID", message: "publish proof kid not found in jwks", kid };
260
+ }
261
+ if (keyEntry.alg && String(keyEntry.alg).trim() !== "" && String(keyEntry.alg).trim() !== "EdDSA") {
262
+ return {
263
+ ok: false,
264
+ code: "PROVIDER_PUBLISH_PROOF_KEY_ALG_INVALID",
265
+ message: "jwks key alg must be EdDSA when provided",
266
+ kid
267
+ };
268
+ }
269
+
270
+ const signatureValid = nodeVerify(
271
+ null,
272
+ Buffer.from(parsed.signingInput, "utf8"),
273
+ keyEntry.publicKeyPem,
274
+ parsed.signature
275
+ );
276
+ if (!signatureValid) {
277
+ return { ok: false, code: "PROVIDER_PUBLISH_PROOF_SIGNATURE_INVALID", message: "publish proof signature verification failed", kid };
278
+ }
279
+
280
+ const keyEvidence = keyEntryToKeyEvidence(keyEntry, kid);
281
+ const providerRef = computeProviderRefFromPublishProofJwk(keyEvidence.jwk);
282
+ return {
283
+ ok: true,
284
+ code: null,
285
+ header: parsed.header,
286
+ payload,
287
+ kid,
288
+ keyEvidence,
289
+ providerRef,
290
+ tokenSha256: sha256Hex(assertNonEmptyString(token, "token"))
291
+ };
292
+ } catch (err) {
293
+ return {
294
+ ok: false,
295
+ code: "PROVIDER_PUBLISH_PROOF_INVALID",
296
+ message: err?.message ?? String(err ?? "")
297
+ };
298
+ }
299
+ }
300
+
301
+ function makeProofError(code, message, details = null, { statusCode = 400 } = {}) {
302
+ const err = new Error(message);
303
+ err.code = code;
304
+ err.statusCode = statusCode;
305
+ if (details !== null && details !== undefined) err.details = details;
306
+ return err;
307
+ }
308
+
309
+ export async function fetchProviderPublishProofJwks({
310
+ jwksUrl,
311
+ fetchFn = globalThis.fetch,
312
+ timeoutMs = 8_000,
313
+ maxBytes = 256 * 1024,
314
+ allowHttp = false,
315
+ allowPrivate = false,
316
+ allowLoopback = false
317
+ } = {}) {
318
+ const urlText = assertNonEmptyString(jwksUrl, "publishProofJwksUrl");
319
+ const safe = await checkUrlSafety(urlText, {
320
+ allowHttp,
321
+ allowPrivate,
322
+ allowLoopback,
323
+ allowedSchemes: ["https"]
324
+ });
325
+ if (!safe.ok) {
326
+ throw makeProofError(
327
+ "PROVIDER_PUBLISH_PROOF_JWKS_URL_UNSAFE",
328
+ "publish proof jwks url is unsafe",
329
+ { code: safe.code, message: safe.message, hostname: safe.hostname ?? null }
330
+ );
331
+ }
332
+
333
+ if (typeof fetchFn !== "function") {
334
+ throw makeProofError("PROVIDER_PUBLISH_PROOF_FETCH_UNAVAILABLE", "fetch is unavailable in this runtime");
335
+ }
336
+
337
+ const timeout = Number(timeoutMs);
338
+ const controller = new AbortController();
339
+ const timer = Number.isFinite(timeout) && timeout > 0 ? setTimeout(() => controller.abort(), timeout) : null;
340
+ let response = null;
341
+ try {
342
+ response = await fetchFn(urlText, {
343
+ method: "GET",
344
+ headers: {
345
+ accept: "application/json"
346
+ },
347
+ redirect: "error",
348
+ signal: controller.signal
349
+ });
350
+ } catch (err) {
351
+ throw makeProofError(
352
+ "PROVIDER_PUBLISH_PROOF_JWKS_FETCH_FAILED",
353
+ `publish proof jwks fetch failed: ${err?.message ?? String(err ?? "")}`,
354
+ null,
355
+ { statusCode: 502 }
356
+ );
357
+ } finally {
358
+ if (timer) clearTimeout(timer);
359
+ }
360
+
361
+ if (!response?.ok) {
362
+ throw makeProofError(
363
+ "PROVIDER_PUBLISH_PROOF_JWKS_FETCH_FAILED",
364
+ `publish proof jwks fetch returned ${Number(response?.status ?? 0)}`,
365
+ { statusCode: Number(response?.status ?? 0) || null },
366
+ { statusCode: 502 }
367
+ );
368
+ }
369
+
370
+ let text = "";
371
+ try {
372
+ text = await response.text();
373
+ } catch (err) {
374
+ throw makeProofError(
375
+ "PROVIDER_PUBLISH_PROOF_JWKS_BODY_INVALID",
376
+ `publish proof jwks body read failed: ${err?.message ?? String(err ?? "")}`
377
+ );
378
+ }
379
+ if (Buffer.byteLength(text, "utf8") > Number(maxBytes)) {
380
+ throw makeProofError("PROVIDER_PUBLISH_PROOF_JWKS_BODY_TOO_LARGE", `publish proof jwks body must be <= ${Number(maxBytes)} bytes`);
381
+ }
382
+
383
+ let parsed = null;
384
+ try {
385
+ parsed = JSON.parse(text);
386
+ } catch (err) {
387
+ throw makeProofError("PROVIDER_PUBLISH_PROOF_JWKS_JSON_INVALID", `publish proof jwks must be valid JSON: ${err?.message ?? String(err ?? "")}`);
388
+ }
389
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
390
+ throw makeProofError("PROVIDER_PUBLISH_PROOF_JWKS_JSON_INVALID", "publish proof jwks must be an object");
391
+ }
392
+ if (!Array.isArray(parsed.keys) || parsed.keys.length === 0) {
393
+ throw makeProofError("PROVIDER_PUBLISH_PROOF_JWKS_KEYS_MISSING", "publish proof jwks.keys must be a non-empty array");
394
+ }
395
+ return normalizeForCanonicalJson(parsed, { path: "$" });
396
+ }
@@ -0,0 +1,170 @@
1
+ import { canonicalJsonStringify, normalizeForCanonicalJson } from "./canonical-json.js";
2
+ import { keyIdFromPublicKeyPem, sha256Hex, signHashHexEd25519, verifyHashHexEd25519 } from "./crypto.js";
3
+
4
+ export const TOOL_PROVIDER_QUOTE_PAYLOAD_SCHEMA_VERSION = "ToolProviderQuotePayload.v1";
5
+ export const TOOL_PROVIDER_QUOTE_SIGNATURE_SCHEMA_VERSION = "ToolProviderQuoteSignature.v1";
6
+
7
+ function assertNonEmptyString(v, name) {
8
+ if (typeof v !== "string" || v.trim() === "") throw new TypeError(`${name} must be a non-empty string`);
9
+ return v.trim();
10
+ }
11
+
12
+ function assertIsoDate(v, name) {
13
+ const value = assertNonEmptyString(v, name);
14
+ const t = Date.parse(value);
15
+ if (!Number.isFinite(t)) throw new TypeError(`${name} must be an ISO date-time`);
16
+ return value;
17
+ }
18
+
19
+ function assertPositiveSafeInt(v, name) {
20
+ const n = Number(v);
21
+ if (!Number.isSafeInteger(n) || n <= 0) throw new TypeError(`${name} must be a positive safe integer`);
22
+ return n;
23
+ }
24
+
25
+ function assertOptionalId(v, name) {
26
+ if (v === null || v === undefined || String(v).trim() === "") return null;
27
+ const out = String(v).trim();
28
+ if (!/^[A-Za-z0-9:._/-]+$/.test(out)) throw new TypeError(`${name} must match ^[A-Za-z0-9:._/-]+$`);
29
+ if (out.length > 200) throw new TypeError(`${name} must be <= 200 chars`);
30
+ return out;
31
+ }
32
+
33
+ function assertCurrency(v, name) {
34
+ const out = assertNonEmptyString(v, name).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 assertRequestBindingMode(v, name) {
40
+ const out = assertNonEmptyString(v, name).toLowerCase();
41
+ if (out !== "none" && out !== "strict") throw new TypeError(`${name} must be none|strict`);
42
+ return out;
43
+ }
44
+
45
+ function assertOptionalSha256Hex(v, name) {
46
+ if (v === null || v === undefined || String(v).trim() === "") return null;
47
+ const out = String(v).trim().toLowerCase();
48
+ if (!/^[0-9a-f]{64}$/.test(out)) throw new TypeError(`${name} must be sha256 hex`);
49
+ return out;
50
+ }
51
+
52
+ function assertSha256Hex(v, name) {
53
+ const out = assertNonEmptyString(v, name).toLowerCase();
54
+ if (!/^[0-9a-f]{64}$/.test(out)) throw new TypeError(`${name} must be sha256 hex`);
55
+ return out;
56
+ }
57
+
58
+ function assertNonceHex(v, name) {
59
+ const out = assertNonEmptyString(v, name).toLowerCase();
60
+ if (!/^[0-9a-f]{16,128}$/.test(out)) throw new TypeError(`${name} must be hex (16..128 chars)`);
61
+ return out;
62
+ }
63
+
64
+ function normalizeBoolean(v) {
65
+ if (v === true) return true;
66
+ if (v === false) return false;
67
+ if (v === null || v === undefined) return false;
68
+ const raw = String(v).trim().toLowerCase();
69
+ return raw === "1" || raw === "true" || raw === "yes" || raw === "on";
70
+ }
71
+
72
+ export function buildToolProviderQuotePayloadV1({
73
+ providerId,
74
+ toolId,
75
+ amountCents,
76
+ currency,
77
+ address,
78
+ network,
79
+ requestBindingMode = "none",
80
+ requestBindingSha256 = null,
81
+ quoteRequired = false,
82
+ quoteId = null,
83
+ spendAuthorizationMode = "optional",
84
+ quotedAt,
85
+ expiresAt
86
+ } = {}) {
87
+ const normalizedRequestBindingMode = assertRequestBindingMode(requestBindingMode, "requestBindingMode");
88
+ const normalizedRequestBindingSha256 = assertOptionalSha256Hex(requestBindingSha256, "requestBindingSha256");
89
+ if (normalizedRequestBindingMode === "strict" && !normalizedRequestBindingSha256) {
90
+ throw new TypeError("requestBindingSha256 is required when requestBindingMode=strict");
91
+ }
92
+ const normalizedSpendAuthorizationMode = assertNonEmptyString(spendAuthorizationMode, "spendAuthorizationMode").toLowerCase();
93
+ if (normalizedSpendAuthorizationMode !== "optional" && normalizedSpendAuthorizationMode !== "required") {
94
+ throw new TypeError("spendAuthorizationMode must be optional|required");
95
+ }
96
+ const normalizedQuoteId = assertOptionalId(quoteId, "quoteId");
97
+ const payload = normalizeForCanonicalJson(
98
+ {
99
+ schemaVersion: TOOL_PROVIDER_QUOTE_PAYLOAD_SCHEMA_VERSION,
100
+ providerId: assertOptionalId(providerId, "providerId") ?? (() => {
101
+ throw new TypeError("providerId is required");
102
+ })(),
103
+ toolId: assertOptionalId(toolId, "toolId") ?? (() => {
104
+ throw new TypeError("toolId is required");
105
+ })(),
106
+ amountCents: assertPositiveSafeInt(amountCents, "amountCents"),
107
+ currency: assertCurrency(currency, "currency"),
108
+ address: assertNonEmptyString(address, "address"),
109
+ network: assertNonEmptyString(network, "network"),
110
+ requestBindingMode: normalizedRequestBindingMode,
111
+ ...(normalizedRequestBindingSha256 ? { requestBindingSha256: normalizedRequestBindingSha256 } : {}),
112
+ quoteRequired: normalizeBoolean(quoteRequired),
113
+ ...(normalizedQuoteId ? { quoteId: normalizedQuoteId } : {}),
114
+ spendAuthorizationMode: normalizedSpendAuthorizationMode,
115
+ quotedAt: assertIsoDate(quotedAt, "quotedAt"),
116
+ expiresAt: assertIsoDate(expiresAt, "expiresAt")
117
+ },
118
+ { path: "$" }
119
+ );
120
+ if (Date.parse(payload.expiresAt) <= Date.parse(payload.quotedAt)) {
121
+ throw new TypeError("expiresAt must be after quotedAt");
122
+ }
123
+ return payload;
124
+ }
125
+
126
+ export function computeToolProviderQuotePayloadHashV1({ quote } = {}) {
127
+ const payload = buildToolProviderQuotePayloadV1(quote);
128
+ return sha256Hex(canonicalJsonStringify(payload));
129
+ }
130
+
131
+ export function signToolProviderQuoteSignatureV1({ quote, nonce, signedAt, publicKeyPem, privateKeyPem } = {}) {
132
+ assertNonEmptyString(publicKeyPem, "publicKeyPem");
133
+ assertNonEmptyString(privateKeyPem, "privateKeyPem");
134
+ const keyId = keyIdFromPublicKeyPem(publicKeyPem);
135
+ const payload = buildToolProviderQuotePayloadV1(quote);
136
+ const payloadHashHex = computeToolProviderQuotePayloadHashV1({ quote: payload });
137
+ const signatureBase64 = signHashHexEd25519(payloadHashHex, privateKeyPem);
138
+ return normalizeForCanonicalJson(
139
+ {
140
+ schemaVersion: TOOL_PROVIDER_QUOTE_SIGNATURE_SCHEMA_VERSION,
141
+ algorithm: "ed25519",
142
+ keyId,
143
+ signedAt: assertIsoDate(signedAt, "signedAt"),
144
+ nonce: assertNonceHex(nonce, "nonce"),
145
+ payloadHash: payloadHashHex,
146
+ signatureBase64
147
+ },
148
+ { path: "$" }
149
+ );
150
+ }
151
+
152
+ export function verifyToolProviderQuoteSignatureV1({ quote, signature, publicKeyPem } = {}) {
153
+ if (!signature || typeof signature !== "object" || Array.isArray(signature)) throw new TypeError("signature must be an object");
154
+ assertNonEmptyString(publicKeyPem, "publicKeyPem");
155
+
156
+ if (signature.schemaVersion !== TOOL_PROVIDER_QUOTE_SIGNATURE_SCHEMA_VERSION) {
157
+ throw new TypeError(`signature.schemaVersion must be ${TOOL_PROVIDER_QUOTE_SIGNATURE_SCHEMA_VERSION}`);
158
+ }
159
+ if (String(signature.algorithm ?? "").toLowerCase() !== "ed25519") {
160
+ throw new TypeError("signature.algorithm must be ed25519");
161
+ }
162
+ const expectedKeyId = keyIdFromPublicKeyPem(publicKeyPem);
163
+ if (String(signature.keyId ?? "").trim() !== expectedKeyId) return false;
164
+
165
+ const payloadHashHex = computeToolProviderQuotePayloadHashV1({ quote });
166
+ if (assertSha256Hex(signature.payloadHash, "signature.payloadHash") !== payloadHashHex) return false;
167
+ const signatureBase64 = assertNonEmptyString(signature.signatureBase64, "signature.signatureBase64");
168
+
169
+ return verifyHashHexEd25519({ hashHex: payloadHashHex, signatureBase64, publicKeyPem });
170
+ }
@@ -0,0 +1,112 @@
1
+ import { createPublicKey } from "node:crypto";
2
+
3
+ import { normalizeForCanonicalJson } from "./canonical-json.js";
4
+ import { keyIdFromPublicKeyPem } from "./crypto.js";
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 assertIsoDate(value, name) {
12
+ assertNonEmptyString(value, name);
13
+ if (!Number.isFinite(Date.parse(value))) throw new TypeError(`${name} must be an ISO date-time`);
14
+ }
15
+
16
+ function normalizeKeyId({ keyId, publicKeyPem, fieldName = "keyId" } = {}) {
17
+ const derived = keyIdFromPublicKeyPem(publicKeyPem);
18
+ if (keyId === null || keyId === undefined || String(keyId).trim() === "") return derived;
19
+ const normalized = assertNonEmptyString(keyId, fieldName);
20
+ if (normalized !== derived) throw new TypeError(`${fieldName} does not match publicKeyPem`);
21
+ return normalized;
22
+ }
23
+
24
+ export function publicKeyPemToEd25519X(publicKeyPem) {
25
+ if (typeof publicKeyPem !== "string" || publicKeyPem.trim() === "") throw new TypeError("publicKeyPem must be a non-empty string");
26
+ const pem = publicKeyPem;
27
+ let jwk;
28
+ try {
29
+ jwk = createPublicKey(pem).export({ format: "jwk" });
30
+ } catch (err) {
31
+ throw new TypeError(`publicKeyPem is not a valid Ed25519 key: ${err?.message ?? String(err ?? "")}`);
32
+ }
33
+ if (!jwk || typeof jwk !== "object") throw new TypeError("publicKeyPem did not export as JWK");
34
+ if (String(jwk.kty ?? "") !== "OKP") throw new TypeError("publicKeyPem must export to JWK kty=OKP");
35
+ if (String(jwk.crv ?? "") !== "Ed25519") throw new TypeError("publicKeyPem must export to JWK crv=Ed25519");
36
+ const x = assertNonEmptyString(jwk.x, "jwk.x");
37
+ return x;
38
+ }
39
+
40
+ export function ed25519XToPublicKeyPem(x) {
41
+ const normalizedX = assertNonEmptyString(x, "x");
42
+ try {
43
+ const keyObj = createPublicKey({
44
+ key: { kty: "OKP", crv: "Ed25519", x: normalizedX },
45
+ format: "jwk"
46
+ });
47
+ return keyObj.export({ format: "pem", type: "spki" }).toString();
48
+ } catch (err) {
49
+ throw new TypeError(`x is not a valid Ed25519 JWK coordinate: ${err?.message ?? String(err ?? "")}`);
50
+ }
51
+ }
52
+
53
+ export function buildSettldPayKeysetV1({ activeKey, fallbackKeys = [], refreshedAt = new Date().toISOString() } = {}) {
54
+ if (!activeKey || typeof activeKey !== "object" || Array.isArray(activeKey)) {
55
+ throw new TypeError("activeKey must be an object");
56
+ }
57
+ assertIsoDate(refreshedAt, "refreshedAt");
58
+
59
+ const keyRows = [activeKey, ...(Array.isArray(fallbackKeys) ? fallbackKeys : [])];
60
+ const byKid = new Map();
61
+ for (const row of keyRows) {
62
+ if (!row || typeof row !== "object" || Array.isArray(row)) continue;
63
+ if (typeof row.publicKeyPem !== "string" || row.publicKeyPem.trim() === "") throw new TypeError("publicKeyPem must be a non-empty string");
64
+ const publicKeyPem = row.publicKeyPem;
65
+ const kid = normalizeKeyId({ keyId: row.keyId ?? row.kid ?? null, publicKeyPem, fieldName: "keyId" });
66
+ if (byKid.has(kid)) continue;
67
+ byKid.set(
68
+ kid,
69
+ normalizeForCanonicalJson(
70
+ {
71
+ kty: "OKP",
72
+ crv: "Ed25519",
73
+ x: publicKeyPemToEd25519X(publicKeyPem),
74
+ kid,
75
+ use: "sig",
76
+ alg: "EdDSA"
77
+ },
78
+ { path: "$" }
79
+ )
80
+ );
81
+ }
82
+
83
+ return normalizeForCanonicalJson(
84
+ {
85
+ keys: Array.from(byKid.values()),
86
+ refreshedAt
87
+ },
88
+ { path: "$" }
89
+ );
90
+ }
91
+
92
+ export function publicKeyPemFromSettldKeysetEntry(entry) {
93
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) throw new TypeError("entry must be an object");
94
+ if (typeof entry.publicKeyPem === "string" && entry.publicKeyPem.trim() !== "") return entry.publicKeyPem;
95
+ const kty = assertNonEmptyString(entry.kty, "entry.kty");
96
+ const crv = assertNonEmptyString(entry.crv, "entry.crv");
97
+ if (kty !== "OKP" || crv !== "Ed25519") throw new TypeError("entry must be an Ed25519 OKP key");
98
+ return ed25519XToPublicKeyPem(entry.x);
99
+ }
100
+
101
+ export function keyMapFromSettldKeyset(keyset) {
102
+ if (!keyset || typeof keyset !== "object" || Array.isArray(keyset)) throw new TypeError("keyset must be an object");
103
+ const rows = Array.isArray(keyset.keys) ? keyset.keys : [];
104
+ const out = new Map();
105
+ for (const row of rows) {
106
+ if (!row || typeof row !== "object" || Array.isArray(row)) continue;
107
+ const kid = assertNonEmptyString(row.kid, "keyset.keys[].kid");
108
+ const publicKeyPem = publicKeyPemFromSettldKeysetEntry(row);
109
+ out.set(kid, { ...row, kid, publicKeyPem });
110
+ }
111
+ return out;
112
+ }