x402-trust-layer 5.1.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 (293) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/DEPLOY.md +53 -0
  3. package/Dockerfile +30 -0
  4. package/LICENSE +21 -0
  5. package/README.md +294 -0
  6. package/dist/agents/a2a-payment.d.ts +37 -0
  7. package/dist/agents/a2a-payment.js +105 -0
  8. package/dist/agents/agent-escrow.d.ts +30 -0
  9. package/dist/agents/agent-escrow.js +23 -0
  10. package/dist/agents/agent-verify.d.ts +15 -0
  11. package/dist/agents/agent-verify.js +112 -0
  12. package/dist/agents/api-router.d.ts +32 -0
  13. package/dist/agents/api-router.js +228 -0
  14. package/dist/agents/attestation-registry.d.ts +35 -0
  15. package/dist/agents/attestation-registry.js +76 -0
  16. package/dist/agents/audition-coach.d.ts +45 -0
  17. package/dist/agents/audition-coach.js +257 -0
  18. package/dist/agents/bedrock-bridge.d.ts +3 -0
  19. package/dist/agents/bedrock-bridge.js +60 -0
  20. package/dist/agents/budget-allocator.d.ts +24 -0
  21. package/dist/agents/budget-allocator.js +31 -0
  22. package/dist/agents/compliance-ledger.d.ts +66 -0
  23. package/dist/agents/compliance-ledger.js +80 -0
  24. package/dist/agents/dispute-resolver.d.ts +62 -0
  25. package/dist/agents/dispute-resolver.js +124 -0
  26. package/dist/agents/evidence-locker.d.ts +30 -0
  27. package/dist/agents/evidence-locker.js +47 -0
  28. package/dist/agents/facilitator-failover.d.ts +15 -0
  29. package/dist/agents/facilitator-failover.js +18 -0
  30. package/dist/agents/identity-gate.d.ts +20 -0
  31. package/dist/agents/identity-gate.js +79 -0
  32. package/dist/agents/mandate-compiler.d.ts +51 -0
  33. package/dist/agents/mandate-compiler.js +73 -0
  34. package/dist/agents/mandate-diff.d.ts +41 -0
  35. package/dist/agents/mandate-diff.js +170 -0
  36. package/dist/agents/market-buy-advisor.d.ts +65 -0
  37. package/dist/agents/market-buy-advisor.js +234 -0
  38. package/dist/agents/merchant-trust.d.ts +38 -0
  39. package/dist/agents/merchant-trust.js +171 -0
  40. package/dist/agents/mpp-session-broker.d.ts +27 -0
  41. package/dist/agents/mpp-session-broker.js +29 -0
  42. package/dist/agents/mpp-session-v2.d.ts +76 -0
  43. package/dist/agents/mpp-session-v2.js +269 -0
  44. package/dist/agents/payment-intent-compiler.d.ts +21 -0
  45. package/dist/agents/payment-intent-compiler.js +45 -0
  46. package/dist/agents/pipeline-execute.d.ts +40 -0
  47. package/dist/agents/pipeline-execute.js +100 -0
  48. package/dist/agents/pipeline-trust-v2.d.ts +31 -0
  49. package/dist/agents/pipeline-trust-v2.js +111 -0
  50. package/dist/agents/pre-x402-guard.d.ts +35 -0
  51. package/dist/agents/pre-x402-guard.js +84 -0
  52. package/dist/agents/quality-escrow-semantic.d.ts +88 -0
  53. package/dist/agents/quality-escrow-semantic.js +137 -0
  54. package/dist/agents/quality-escrow.d.ts +65 -0
  55. package/dist/agents/quality-escrow.js +104 -0
  56. package/dist/agents/quality-monitor.d.ts +32 -0
  57. package/dist/agents/quality-monitor.js +77 -0
  58. package/dist/agents/rail-optimizer.d.ts +33 -0
  59. package/dist/agents/rail-optimizer.js +133 -0
  60. package/dist/agents/receipt-auditor.d.ts +14 -0
  61. package/dist/agents/receipt-auditor.js +145 -0
  62. package/dist/agents/refund-arbiter.d.ts +24 -0
  63. package/dist/agents/refund-arbiter.js +70 -0
  64. package/dist/agents/research-brief.d.ts +14 -0
  65. package/dist/agents/research-brief.js +66 -0
  66. package/dist/agents/risk-gate.d.ts +11 -0
  67. package/dist/agents/risk-gate.js +78 -0
  68. package/dist/agents/settlement-graph.d.ts +16 -0
  69. package/dist/agents/settlement-graph.js +38 -0
  70. package/dist/agents/spend-governor.d.ts +2 -0
  71. package/dist/agents/spend-governor.js +70 -0
  72. package/dist/agents/trust-network.d.ts +138 -0
  73. package/dist/agents/trust-network.js +244 -0
  74. package/dist/agents/x402-proxy.d.ts +32 -0
  75. package/dist/agents/x402-proxy.js +90 -0
  76. package/dist/client/demo-alchemy-live.d.ts +1 -0
  77. package/dist/client/demo-alchemy-live.js +226 -0
  78. package/dist/client/demo-tail.d.ts +1 -0
  79. package/dist/client/demo-tail.js +100 -0
  80. package/dist/client/demo.d.ts +1 -0
  81. package/dist/client/demo.js +293 -0
  82. package/dist/config.d.ts +94 -0
  83. package/dist/config.js +223 -0
  84. package/dist/index.d.ts +1 -0
  85. package/dist/index.js +389 -0
  86. package/dist/lib/agent-response.d.ts +14 -0
  87. package/dist/lib/agent-response.js +13 -0
  88. package/dist/lib/agentic-gateways.d.ts +5 -0
  89. package/dist/lib/agentic-gateways.js +15 -0
  90. package/dist/lib/agentic-probes.d.ts +10 -0
  91. package/dist/lib/agentic-probes.js +49 -0
  92. package/dist/lib/alchemy-x402-fetch.d.ts +16 -0
  93. package/dist/lib/alchemy-x402-fetch.js +95 -0
  94. package/dist/lib/apply-verifier-body.d.ts +7 -0
  95. package/dist/lib/apply-verifier-body.js +179 -0
  96. package/dist/lib/attestation.d.ts +30 -0
  97. package/dist/lib/attestation.js +107 -0
  98. package/dist/lib/bazaar-extension.d.ts +15 -0
  99. package/dist/lib/bazaar-extension.js +265 -0
  100. package/dist/lib/bazaar.d.ts +100 -0
  101. package/dist/lib/bazaar.js +341 -0
  102. package/dist/lib/certified-sellers.d.ts +41 -0
  103. package/dist/lib/certified-sellers.js +129 -0
  104. package/dist/lib/chains.d.ts +20 -0
  105. package/dist/lib/chains.js +78 -0
  106. package/dist/lib/db-persistence.d.ts +7 -0
  107. package/dist/lib/db-persistence.js +65 -0
  108. package/dist/lib/db.d.ts +5 -0
  109. package/dist/lib/db.js +113 -0
  110. package/dist/lib/discovery-page.d.ts +2 -0
  111. package/dist/lib/discovery-page.js +71 -0
  112. package/dist/lib/ecosystem-telemetry.d.ts +20 -0
  113. package/dist/lib/ecosystem-telemetry.js +80 -0
  114. package/dist/lib/erc8004/agent-card.d.ts +34 -0
  115. package/dist/lib/erc8004/agent-card.js +151 -0
  116. package/dist/lib/erc8004/cache.d.ts +3 -0
  117. package/dist/lib/erc8004/cache.js +17 -0
  118. package/dist/lib/erc8004/constants.d.ts +22 -0
  119. package/dist/lib/erc8004/constants.js +35 -0
  120. package/dist/lib/erc8004/registry.d.ts +19 -0
  121. package/dist/lib/erc8004/registry.js +171 -0
  122. package/dist/lib/erc8004/resolve-agent.d.ts +7 -0
  123. package/dist/lib/erc8004/resolve-agent.js +70 -0
  124. package/dist/lib/erc8004/trust-score.d.ts +33 -0
  125. package/dist/lib/erc8004/trust-score.js +136 -0
  126. package/dist/lib/escrow-ledger.d.ts +14 -0
  127. package/dist/lib/escrow-ledger.js +54 -0
  128. package/dist/lib/escrow-unified.d.ts +15 -0
  129. package/dist/lib/escrow-unified.js +28 -0
  130. package/dist/lib/facilitator-extra.d.ts +13 -0
  131. package/dist/lib/facilitator-extra.js +52 -0
  132. package/dist/lib/facilitators.d.ts +20 -0
  133. package/dist/lib/facilitators.js +89 -0
  134. package/dist/lib/host-policy.d.ts +4 -0
  135. package/dist/lib/host-policy.js +20 -0
  136. package/dist/lib/idempotency.d.ts +4 -0
  137. package/dist/lib/idempotency.js +120 -0
  138. package/dist/lib/ledger.d.ts +2 -0
  139. package/dist/lib/ledger.js +17 -0
  140. package/dist/lib/logger.d.ts +6 -0
  141. package/dist/lib/logger.js +24 -0
  142. package/dist/lib/mandate-vc.d.ts +20 -0
  143. package/dist/lib/mandate-vc.js +25 -0
  144. package/dist/lib/mandate.d.ts +44 -0
  145. package/dist/lib/mandate.js +190 -0
  146. package/dist/lib/marketplace.d.ts +7 -0
  147. package/dist/lib/marketplace.js +127 -0
  148. package/dist/lib/migrations.d.ts +2 -0
  149. package/dist/lib/migrations.js +130 -0
  150. package/dist/lib/nonce-store.d.ts +6 -0
  151. package/dist/lib/nonce-store.js +109 -0
  152. package/dist/lib/openapi-agentcash.d.ts +5 -0
  153. package/dist/lib/openapi-agentcash.js +288 -0
  154. package/dist/lib/openapi-meta.d.ts +5 -0
  155. package/dist/lib/openapi-meta.js +235 -0
  156. package/dist/lib/otel.d.ts +2 -0
  157. package/dist/lib/otel.js +25 -0
  158. package/dist/lib/paid-resource-url.d.ts +6 -0
  159. package/dist/lib/paid-resource-url.js +47 -0
  160. package/dist/lib/parse-with-verifier-fallback.d.ts +3 -0
  161. package/dist/lib/parse-with-verifier-fallback.js +13 -0
  162. package/dist/lib/payment-request-context.d.ts +10 -0
  163. package/dist/lib/payment-request-context.js +5 -0
  164. package/dist/lib/payment-response.d.ts +13 -0
  165. package/dist/lib/payment-response.js +39 -0
  166. package/dist/lib/payto-guard.d.ts +10 -0
  167. package/dist/lib/payto-guard.js +20 -0
  168. package/dist/lib/probe.d.ts +29 -0
  169. package/dist/lib/probe.js +157 -0
  170. package/dist/lib/problem-detail.d.ts +10 -0
  171. package/dist/lib/problem-detail.js +14 -0
  172. package/dist/lib/rate-limit.d.ts +12 -0
  173. package/dist/lib/rate-limit.js +126 -0
  174. package/dist/lib/replay-middleware.d.ts +3 -0
  175. package/dist/lib/replay-middleware.js +27 -0
  176. package/dist/lib/response-guard.d.ts +5 -0
  177. package/dist/lib/response-guard.js +40 -0
  178. package/dist/lib/safe-fetch.d.ts +5 -0
  179. package/dist/lib/safe-fetch.js +19 -0
  180. package/dist/lib/security.d.ts +13 -0
  181. package/dist/lib/security.js +61 -0
  182. package/dist/lib/semantic-judge.d.ts +14 -0
  183. package/dist/lib/semantic-judge.js +107 -0
  184. package/dist/lib/semantic-judge.test.d.ts +1 -0
  185. package/dist/lib/semantic-judge.test.js +11 -0
  186. package/dist/lib/ssrf.d.ts +10 -0
  187. package/dist/lib/ssrf.js +130 -0
  188. package/dist/lib/ssrf.test.d.ts +1 -0
  189. package/dist/lib/ssrf.test.js +16 -0
  190. package/dist/lib/suite-catalog.d.ts +83 -0
  191. package/dist/lib/suite-catalog.js +131 -0
  192. package/dist/lib/telemetry.d.ts +5 -0
  193. package/dist/lib/telemetry.js +37 -0
  194. package/dist/lib/verifier-fast-path.d.ts +10 -0
  195. package/dist/lib/verifier-fast-path.js +44 -0
  196. package/dist/lib/verifier-probe-protocol.d.ts +7 -0
  197. package/dist/lib/verifier-probe-protocol.js +115 -0
  198. package/dist/lib/verify-examples.d.ts +2 -0
  199. package/dist/lib/verify-examples.js +438 -0
  200. package/dist/lib/version.d.ts +2 -0
  201. package/dist/lib/version.js +2 -0
  202. package/dist/lib/webhook-auth.d.ts +3 -0
  203. package/dist/lib/webhook-auth.js +34 -0
  204. package/dist/lib/webhook-routes.d.ts +2 -0
  205. package/dist/lib/webhook-routes.js +112 -0
  206. package/dist/lib/webhooks.d.ts +23 -0
  207. package/dist/lib/webhooks.js +123 -0
  208. package/dist/lib/webhooks.test.d.ts +1 -0
  209. package/dist/lib/webhooks.test.js +16 -0
  210. package/dist/lib/x402-client-options.d.ts +28 -0
  211. package/dist/lib/x402-client-options.js +138 -0
  212. package/dist/lib/x402-headers.d.ts +10 -0
  213. package/dist/lib/x402-headers.js +27 -0
  214. package/dist/lib/x402-paid.d.ts +5 -0
  215. package/dist/lib/x402-paid.js +252 -0
  216. package/dist/lib/x402-payment-replay.d.ts +22 -0
  217. package/dist/lib/x402-payment-replay.js +57 -0
  218. package/dist/lib/x402gle-host-verify.d.ts +3 -0
  219. package/dist/lib/x402gle-host-verify.js +27 -0
  220. package/dist/protocol/agent-passport.d.ts +34 -0
  221. package/dist/protocol/agent-passport.js +44 -0
  222. package/dist/protocol/compliance-v2.d.ts +21 -0
  223. package/dist/protocol/compliance-v2.js +19 -0
  224. package/dist/protocol/credit-bureau.d.ts +18 -0
  225. package/dist/protocol/credit-bureau.js +44 -0
  226. package/dist/protocol/crypto.d.ts +6 -0
  227. package/dist/protocol/crypto.js +41 -0
  228. package/dist/protocol/escrow-fsm.d.ts +33 -0
  229. package/dist/protocol/escrow-fsm.js +99 -0
  230. package/dist/protocol/fraud-engine.d.ts +28 -0
  231. package/dist/protocol/fraud-engine.js +77 -0
  232. package/dist/protocol/observability.d.ts +14 -0
  233. package/dist/protocol/observability.js +21 -0
  234. package/dist/protocol/pipeline-full-trust.d.ts +40 -0
  235. package/dist/protocol/pipeline-full-trust.js +96 -0
  236. package/dist/protocol/proof-of-execution.d.ts +36 -0
  237. package/dist/protocol/proof-of-execution.js +48 -0
  238. package/dist/protocol/reasoning-audit.d.ts +27 -0
  239. package/dist/protocol/reasoning-audit.js +51 -0
  240. package/dist/protocol/replay-guard.d.ts +28 -0
  241. package/dist/protocol/replay-guard.js +76 -0
  242. package/dist/protocol/replay-guard.test.d.ts +1 -0
  243. package/dist/protocol/replay-guard.test.js +10 -0
  244. package/dist/protocol/security-audit.d.ts +18 -0
  245. package/dist/protocol/security-audit.js +45 -0
  246. package/dist/protocol/store.d.ts +5 -0
  247. package/dist/protocol/store.js +59 -0
  248. package/dist/protocol/threat-catalog.d.ts +13 -0
  249. package/dist/protocol/threat-catalog.js +75 -0
  250. package/dist/protocol/trust-oracle.d.ts +23 -0
  251. package/dist/protocol/trust-oracle.js +30 -0
  252. package/dist/protocol/trust-score-v2.d.ts +33 -0
  253. package/dist/protocol/trust-score-v2.js +78 -0
  254. package/dist/protocol/zk-proofs.d.ts +24 -0
  255. package/dist/protocol/zk-proofs.js +32 -0
  256. package/dist/routes/a2a-agent-card.d.ts +3 -0
  257. package/dist/routes/a2a-agent-card.js +28 -0
  258. package/dist/routes/catalog.d.ts +5 -0
  259. package/dist/routes/catalog.js +47 -0
  260. package/dist/routes/register-all.d.ts +3 -0
  261. package/dist/routes/register-all.js +1240 -0
  262. package/dist/routes/schemas.d.ts +83 -0
  263. package/dist/routes/schemas.js +38 -0
  264. package/dist/routes/shared.d.ts +16 -0
  265. package/dist/routes/shared.js +27 -0
  266. package/dist/routes-protocol.d.ts +10 -0
  267. package/dist/routes-protocol.js +322 -0
  268. package/dist/routes.d.ts +2 -0
  269. package/dist/routes.js +2 -0
  270. package/dist/types.d.ts +66 -0
  271. package/dist/types.js +1 -0
  272. package/openapi.json +7940 -0
  273. package/package.json +124 -0
  274. package/public/.well-known/ai-plugin.json +12 -0
  275. package/public/assets/aegis-logo-blue.png +0 -0
  276. package/public/assets/aegis-logo-gold.png +0 -0
  277. package/public/assets/aegis-logo-green.png +0 -0
  278. package/public/assets/aegis-logo-purple.png +0 -0
  279. package/public/assets/aegis-logo-red.png +0 -0
  280. package/public/assets/aegis-logo-white.png +0 -0
  281. package/public/assets/aegis-logo.png +0 -0
  282. package/public/assets/x402-trustlayer-logo.png +0 -0
  283. package/public/assets/x402-trustlayer-logo.svg +5 -0
  284. package/public/data/agents.json +1528 -0
  285. package/public/index.html +198 -0
  286. package/public/landing.css +342 -0
  287. package/public/landing.js +405 -0
  288. package/public/llms-full.txt +582 -0
  289. package/public/llms.txt +132 -0
  290. package/public/skill.md +135 -0
  291. package/railway.toml +9 -0
  292. package/scripts/docker-entrypoint.sh +7 -0
  293. package/scripts/patch-facilitator-timeout.mjs +61 -0
@@ -0,0 +1,127 @@
1
+ function normalizeQuery(q) {
2
+ return q.toLowerCase().trim();
3
+ }
4
+ function matchesQuery(resource, query) {
5
+ const q = normalizeQuery(query);
6
+ const haystack = [resource.name, resource.description, ...(resource.tags ?? [])]
7
+ .filter(Boolean)
8
+ .join(" ")
9
+ .toLowerCase();
10
+ const terms = q.split(/\s+/).filter(Boolean);
11
+ if (terms.length === 0)
12
+ return true;
13
+ return terms.some((t) => haystack.includes(t));
14
+ }
15
+ function mapLabResource(r) {
16
+ return {
17
+ name: r.name,
18
+ description: r.description,
19
+ url: r.public_url,
20
+ priceUsdc: r.base_price_usdc,
21
+ network: "solana",
22
+ };
23
+ }
24
+ function mergeResources(body) {
25
+ const nested = body.data;
26
+ const fromData = Array.isArray(nested)
27
+ ? nested
28
+ : nested && typeof nested === "object"
29
+ ? nested.resources
30
+ : undefined;
31
+ const merged = [
32
+ ...(body.resources ?? []),
33
+ ...(fromData ?? []),
34
+ ...(body.strongResults ?? []),
35
+ ...(body.relatedResults ?? []),
36
+ ...(body.items ?? []),
37
+ ];
38
+ const seen = new Set();
39
+ return merged.filter((r) => {
40
+ if (!r.url || seen.has(r.url))
41
+ return false;
42
+ seen.add(r.url);
43
+ return true;
44
+ });
45
+ }
46
+ async function searchFacilitatorCatalog(query, options) {
47
+ const url = new URL("https://api.dexter.cash/api/facilitator/marketplace/resources");
48
+ url.searchParams.set("search", query);
49
+ url.searchParams.set("sort", "quality_score");
50
+ url.searchParams.set("limit", String(options.limit ?? 15));
51
+ if (options.verified !== false)
52
+ url.searchParams.set("verified", "true");
53
+ if (options.maxPriceUsdc != null) {
54
+ url.searchParams.set("maxPrice", String(options.maxPriceUsdc));
55
+ }
56
+ const controller = new AbortController();
57
+ const timer = setTimeout(() => controller.abort(), 20_000);
58
+ const res = await fetch(url, {
59
+ headers: { accept: "application/json" },
60
+ signal: controller.signal,
61
+ });
62
+ clearTimeout(timer);
63
+ if (!res.ok) {
64
+ throw new Error(`facilitator catalog HTTP ${res.status}`);
65
+ }
66
+ const body = (await res.json());
67
+ return mergeResources(body);
68
+ }
69
+ async function searchLabCatalog(query, options) {
70
+ const url = new URL("https://api.dexter.cash/api/dexter-lab/resources/public");
71
+ url.searchParams.set("limit", String(Math.min(options.limit ?? 15, 50)));
72
+ const controller = new AbortController();
73
+ const timer = setTimeout(() => controller.abort(), 20_000);
74
+ const res = await fetch(url, {
75
+ headers: { accept: "application/json" },
76
+ signal: controller.signal,
77
+ });
78
+ clearTimeout(timer);
79
+ if (!res.ok) {
80
+ throw new Error(`lab catalog HTTP ${res.status}`);
81
+ }
82
+ const body = (await res.json());
83
+ let list = (body.resources ?? []).map(mapLabResource);
84
+ list = list.filter((r) => matchesQuery({ name: r.name, description: r.description }, query));
85
+ if (options.maxPriceUsdc != null) {
86
+ list = list.filter((r) => (r.priceUsdc ?? 999) <= options.maxPriceUsdc);
87
+ }
88
+ return list.slice(0, options.limit ?? 15);
89
+ }
90
+ export async function searchMarketplace(query, options = {}) {
91
+ try {
92
+ const primary = await searchFacilitatorCatalog(query, options);
93
+ if (primary.length > 0)
94
+ return primary;
95
+ }
96
+ catch (err) {
97
+ console.warn(`[marketplace] facilitator catalog:`, err);
98
+ }
99
+ try {
100
+ return await searchLabCatalog(query, options);
101
+ }
102
+ catch (err) {
103
+ console.warn(`[marketplace] lab catalog fallback failed for "${query}":`, err);
104
+ return [];
105
+ }
106
+ }
107
+ export function pickBestResource(resources, preferNetwork, query) {
108
+ if (resources.length === 0)
109
+ return null;
110
+ const scored = resources
111
+ .map((r) => {
112
+ const quality = r.qualityScore ?? 50;
113
+ const price = r.priceUsdc ?? 1;
114
+ const latencyPenalty = (r.latencyP50Ms ?? 0) / 100_000;
115
+ const networkBoost = preferNetwork && r.network?.toLowerCase().includes(preferNetwork.toLowerCase()) ? 5 : 0;
116
+ const haystack = [r.name, r.description, r.url].filter(Boolean).join(" ").toLowerCase();
117
+ const q = (query ?? "").toLowerCase();
118
+ const wantsOracle = /eth|ethereum|oracle|price|usd|btc|bitcoin/.test(q);
119
+ const oracleBoost = wantsOracle && /mycelia|oracle\/price/.test(haystack) ? 12 : 0;
120
+ return {
121
+ r,
122
+ score: quality * 2 - price * 10 - latencyPenalty + networkBoost + oracleBoost,
123
+ };
124
+ })
125
+ .sort((a, b) => b.score - a.score);
126
+ return scored[0]?.r ?? null;
127
+ }
@@ -0,0 +1,2 @@
1
+ import type { Database as SqliteDatabase } from "better-sqlite3";
2
+ export declare function runMigrations(db: SqliteDatabase): void;
@@ -0,0 +1,130 @@
1
+ const MIGRATIONS = [
2
+ {
3
+ version: 1,
4
+ sql: `
5
+ CREATE TABLE IF NOT EXISTS schema_version (version INTEGER PRIMARY KEY);
6
+ `,
7
+ },
8
+ {
9
+ version: 2,
10
+ sql: `
11
+ CREATE TABLE IF NOT EXISTS mandates (
12
+ mandate_id TEXT PRIMARY KEY,
13
+ principal TEXT NOT NULL,
14
+ agent_id TEXT NOT NULL,
15
+ intent TEXT NOT NULL,
16
+ intent_hash TEXT NOT NULL,
17
+ scope JSON NOT NULL,
18
+ signature TEXT NOT NULL,
19
+ issued_at TEXT NOT NULL,
20
+ expires_at INTEGER,
21
+ suite_version TEXT NOT NULL
22
+ );
23
+ CREATE INDEX IF NOT EXISTS idx_mandates_agent ON mandates(agent_id);
24
+ CREATE INDEX IF NOT EXISTS idx_mandates_expires ON mandates(expires_at);
25
+ `,
26
+ },
27
+ {
28
+ version: 3,
29
+ sql: `
30
+ CREATE TABLE IF NOT EXISTS protocol_kv (
31
+ store TEXT NOT NULL,
32
+ key TEXT NOT NULL,
33
+ value JSON NOT NULL,
34
+ updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
35
+ PRIMARY KEY (store, key)
36
+ );
37
+ CREATE INDEX IF NOT EXISTS idx_kv_store ON protocol_kv(store, updated_at);
38
+ `,
39
+ },
40
+ {
41
+ version: 4,
42
+ sql: `
43
+ CREATE TABLE IF NOT EXISTS idempotency_cache (
44
+ cache_key TEXT PRIMARY KEY,
45
+ status INTEGER NOT NULL,
46
+ body JSON NOT NULL,
47
+ body_hash TEXT NOT NULL,
48
+ route TEXT NOT NULL,
49
+ created_at INTEGER NOT NULL DEFAULT (unixepoch())
50
+ );
51
+ CREATE TABLE IF NOT EXISTS idempotency_inflight (
52
+ cache_key TEXT PRIMARY KEY,
53
+ created_at INTEGER NOT NULL DEFAULT (unixepoch())
54
+ );
55
+ `,
56
+ },
57
+ {
58
+ version: 5,
59
+ sql: `
60
+ CREATE TABLE IF NOT EXISTS webhook_subscriptions (
61
+ id TEXT PRIMARY KEY,
62
+ fleet_id TEXT NOT NULL,
63
+ url TEXT NOT NULL,
64
+ events JSON NOT NULL,
65
+ secret TEXT NOT NULL,
66
+ created_at TEXT NOT NULL,
67
+ active INTEGER NOT NULL DEFAULT 1
68
+ );
69
+ CREATE INDEX IF NOT EXISTS idx_webhooks_fleet ON webhook_subscriptions(fleet_id, active);
70
+ `,
71
+ },
72
+ {
73
+ version: 6,
74
+ sql: `
75
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_spend_tx_hash ON spend_ledger(tx_hash)
76
+ WHERE tx_hash IS NOT NULL;
77
+ CREATE INDEX IF NOT EXISTS idx_spend_wallet ON spend_ledger(wallet_address, day_key);
78
+ `,
79
+ },
80
+ {
81
+ version: 7,
82
+ sql: `
83
+ CREATE TABLE IF NOT EXISTS telemetry_counters (
84
+ name TEXT PRIMARY KEY,
85
+ value INTEGER NOT NULL DEFAULT 0,
86
+ updated_at INTEGER NOT NULL DEFAULT (unixepoch())
87
+ );
88
+ `,
89
+ },
90
+ {
91
+ version: 8,
92
+ sql: `
93
+ CREATE TABLE IF NOT EXISTS escrows (
94
+ escrow_id TEXT PRIMARY KEY,
95
+ payer_agent_id TEXT NOT NULL,
96
+ payee_id TEXT NOT NULL,
97
+ amount_usdc REAL NOT NULL,
98
+ state TEXT NOT NULL DEFAULT 'CREATED',
99
+ resource_hash TEXT,
100
+ session_id TEXT,
101
+ release_condition TEXT,
102
+ quality_score REAL,
103
+ created_at INTEGER NOT NULL DEFAULT (unixepoch()),
104
+ updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
105
+ settled_at INTEGER,
106
+ state_proof TEXT NOT NULL,
107
+ metadata JSON
108
+ );
109
+ CREATE TABLE IF NOT EXISTS escrow_transitions (
110
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
111
+ escrow_id TEXT NOT NULL,
112
+ from_state TEXT NOT NULL,
113
+ to_state TEXT NOT NULL,
114
+ note TEXT,
115
+ transitioned_at INTEGER NOT NULL DEFAULT (unixepoch()),
116
+ proof TEXT
117
+ );
118
+ CREATE INDEX IF NOT EXISTS idx_escrow_state ON escrows(state, updated_at);
119
+ `,
120
+ },
121
+ ];
122
+ export function runMigrations(db) {
123
+ db.exec("CREATE TABLE IF NOT EXISTS schema_version (version INTEGER PRIMARY KEY)");
124
+ const row = db.prepare("SELECT MAX(version) AS v FROM schema_version").get();
125
+ const current = row?.v ?? 0;
126
+ for (const m of MIGRATIONS.filter((x) => x.version > current)) {
127
+ db.exec(m.sql);
128
+ db.prepare("INSERT INTO schema_version (version) VALUES (?)").run(m.version);
129
+ }
130
+ }
@@ -0,0 +1,6 @@
1
+ /** Claim a nonce/idempotency key once (payment, protocol replay, idempotency). */
2
+ export declare function claimNonceKey(rawKey: string, network?: string, ttlSec?: number): Promise<boolean>;
3
+ export declare function isNonceKeyUsed(rawKey: string): boolean;
4
+ export declare function extractIdempotencyKey(req: {
5
+ headers: Record<string, unknown>;
6
+ }): string | undefined;
@@ -0,0 +1,109 @@
1
+ import { db } from "./db.js";
2
+ import { assertSafeOutboundUrl } from "./ssrf.js";
3
+ const checkNonce = db.prepare("SELECT 1 AS ok FROM used_nonces WHERE nonce = ?");
4
+ const insertNonce = db.prepare("INSERT OR IGNORE INTO used_nonces (nonce, network) VALUES (?, ?)");
5
+ const cleanOld = db.prepare("DELETE FROM used_nonces WHERE used_at < ?");
6
+ const REDIS_REST_URL = (process.env.UPSTASH_REDIS_REST_URL ?? "").trim();
7
+ const REDIS_REST_TOKEN = (process.env.UPSTASH_REDIS_REST_TOKEN ?? "").trim();
8
+ const REDIS_URL = (process.env.REDIS_URL ?? "").trim();
9
+ let redisSetNx = null;
10
+ let redisInit = null;
11
+ async function ensureRedis() {
12
+ if (redisSetNx)
13
+ return true;
14
+ if (!REDIS_URL)
15
+ return false;
16
+ if (!redisInit) {
17
+ redisInit = (async () => {
18
+ try {
19
+ const mod = await import("redis");
20
+ const client = mod.createClient({ url: REDIS_URL });
21
+ client.on("error", (err) => console.warn("[nonce-store] redis:", err.message));
22
+ await client.connect();
23
+ redisSetNx = async (key, ttlSec) => {
24
+ const r = await client.set(key, "1", { NX: true, EX: ttlSec });
25
+ return r === "OK";
26
+ };
27
+ }
28
+ catch (err) {
29
+ console.warn("[nonce-store] REDIS_URL set but redis package unavailable — using SQLite only:", err instanceof Error ? err.message : err);
30
+ }
31
+ })();
32
+ }
33
+ await redisInit;
34
+ return !!redisSetNx;
35
+ }
36
+ async function redisRestSetNx(key, ttlSec) {
37
+ if (!REDIS_REST_URL || !REDIS_REST_TOKEN)
38
+ return false;
39
+ assertSafeOutboundUrl(REDIS_REST_URL);
40
+ if (!REDIS_REST_URL.startsWith("https://")) {
41
+ throw new Error("Redis REST must be HTTPS");
42
+ }
43
+ const res = await fetch(REDIS_REST_URL, {
44
+ method: "POST",
45
+ headers: {
46
+ Authorization: `Bearer ${REDIS_REST_TOKEN}`,
47
+ "Content-Type": "application/json",
48
+ },
49
+ body: JSON.stringify(["SET", key, "1", "NX", "EX", String(ttlSec)]),
50
+ });
51
+ if (!res.ok)
52
+ return false;
53
+ const data = (await res.json());
54
+ return data.result === "OK";
55
+ }
56
+ function sqliteClaim(key, network) {
57
+ if (checkNonce.get(key))
58
+ return false;
59
+ insertNonce.run(key, network);
60
+ return true;
61
+ }
62
+ function maybeCleanSqlite() {
63
+ if (Math.random() < 0.02) {
64
+ cleanOld.run(Math.floor(Date.now() / 1000) - 86_400 * 7);
65
+ }
66
+ }
67
+ /** Claim a nonce/idempotency key once (payment, protocol replay, idempotency). */
68
+ export async function claimNonceKey(rawKey, network = "unknown", ttlSec = 86_400 * 7) {
69
+ const key = rawKey.trim();
70
+ if (!key || key.length < 8)
71
+ return true;
72
+ const storeKey = key.length > 200 ? key.slice(0, 200) : key;
73
+ if (await ensureRedis()) {
74
+ const ok = await redisSetNx(`x402:nonce:${storeKey}`, ttlSec);
75
+ if (ok) {
76
+ sqliteClaim(storeKey, network);
77
+ return true;
78
+ }
79
+ return false;
80
+ }
81
+ if (REDIS_REST_URL && REDIS_REST_TOKEN) {
82
+ const ok = await redisRestSetNx(`x402:nonce:${storeKey}`, ttlSec);
83
+ if (ok) {
84
+ sqliteClaim(storeKey, network);
85
+ return true;
86
+ }
87
+ if (checkNonce.get(storeKey))
88
+ return false;
89
+ return false;
90
+ }
91
+ maybeCleanSqlite();
92
+ if (checkNonce.get(storeKey))
93
+ return false;
94
+ insertNonce.run(storeKey, network);
95
+ return true;
96
+ }
97
+ export function isNonceKeyUsed(rawKey) {
98
+ const key = rawKey.trim();
99
+ if (!key || key.length < 8)
100
+ return false;
101
+ const storeKey = key.length > 200 ? key.slice(0, 200) : key;
102
+ return !!checkNonce.get(storeKey);
103
+ }
104
+ export function extractIdempotencyKey(req) {
105
+ const raw = req.headers["idempotency-key"] ??
106
+ req.headers["x-idempotency-key"];
107
+ const v = Array.isArray(raw) ? raw[0] : raw;
108
+ return typeof v === "string" && v.trim().length >= 8 ? v.trim() : undefined;
109
+ }
@@ -0,0 +1,5 @@
1
+ export declare function buildAgentCashOpenApi(): Record<string, unknown>;
2
+ /** AgentCash / x402scan 2026 spec v2 — per-resource accepts with micro-units. */
3
+ export declare function buildWellKnownX402V2(): Record<string, unknown>;
4
+ /** x402scan / AgentCash compatibility fan-out */
5
+ export declare function buildWellKnownX402Resources(): Record<string, unknown>;
@@ -0,0 +1,288 @@
1
+ import { config } from "../config.js";
2
+ import { SUITE_VERSION } from "./version.js";
3
+ import { listEndpoints } from "../routes/catalog.js";
4
+ import { pricing } from "../config.js";
5
+ import { defaultOutputExample } from "./bazaar-extension.js";
6
+ import { ENDPOINT_META } from "./openapi-meta.js";
7
+ import { VERIFY_EXAMPLES } from "./verify-examples.js";
8
+ const X402_PROTOCOLS = [{ x402: {} }];
9
+ const MPP_SESSION_PROTOCOLS = [
10
+ { x402: {} },
11
+ { mpp: { method: "POST", intent: "session", currency: "0x20c000000000000000000000b9537d11c60e8b50" } },
12
+ ];
13
+ const AGENT_GUIDANCE = `x402 Trust Layer — 58 paid agent payment infrastructure APIs on Base, Solana, and Polygon via Dexter facilitator.
14
+
15
+ Typical flow:
16
+ 1. POST /api/guard/pre-x402 or POST /api/x402/proxy before any downstream x402 payment.
17
+ 2. POST /api/merchant-trust/score for Know-Your-Merchant preflight on unknown hosts.
18
+ 3. POST /api/mandate/compile for AP2-style signed intent; POST /api/mandate/diff + /api/mandate/verify before spend.
19
+ 4. POST /api/trust-network/buyer-gate when paying certified sellers; POST /api/merchant-trust/certify to join network.
20
+ 5. POST /api/quality-escrow/semantic-settle after delivery for auto-refund on bad responses.
21
+ 6. POST /api/payment-intent/compile or POST /api/pipeline/execute for multi-step orchestration.
22
+ 7. POST /api/mpp/session with action open|voucher|close for batch settlement savings.
23
+ 8. POST /api/attestation/issue then pass X-Suite-Attestation on partner calls.
24
+ 9. POST /api/receipt-auditor/verify after external settlements; POST /api/compliance/ledger for audit.
25
+
26
+ Pay with x402 (USDC). Unpaid GET probes return 402; send Payment-Signature on POST for full JSON responses.
27
+
28
+ Free (not in this catalog): GET /health — monitoring only, returns 200 without payment.`;
29
+ function formatUsdAmount(priceStr) {
30
+ const n = Number(priceStr.replace(/^\$/, ""));
31
+ if (!Number.isFinite(n))
32
+ return "0.010000";
33
+ return n.toFixed(6);
34
+ }
35
+ function exampleToSchema(value) {
36
+ if (value === null)
37
+ return { type: "null" };
38
+ if (Array.isArray(value)) {
39
+ const items = value.length ? exampleToSchema(value[0]) : { type: "object" };
40
+ return { type: "array", items };
41
+ }
42
+ switch (typeof value) {
43
+ case "string":
44
+ return { type: "string" };
45
+ case "number":
46
+ return { type: "number" };
47
+ case "boolean":
48
+ return { type: "boolean" };
49
+ case "object": {
50
+ const obj = value;
51
+ const properties = {};
52
+ for (const [k, v] of Object.entries(obj)) {
53
+ properties[k] = exampleToSchema(v);
54
+ }
55
+ return {
56
+ type: "object",
57
+ properties,
58
+ required: Object.keys(obj),
59
+ };
60
+ }
61
+ default:
62
+ return { type: "string" };
63
+ }
64
+ }
65
+ function operationId(path, method) {
66
+ const slug = path.replace(/^\/api\//, "").replace(/\//g, "_").replace(/-/g, "_");
67
+ return `${method}_${slug}`;
68
+ }
69
+ function paymentProtocols(path) {
70
+ if (path === "/api/mpp/session" || path === "/api/mpp/session-plan") {
71
+ return MPP_SESSION_PROTOCOLS;
72
+ }
73
+ return X402_PROTOCOLS;
74
+ }
75
+ function paidResponseSchema() {
76
+ return {
77
+ type: "object",
78
+ description: "Successful response after x402 settlement",
79
+ properties: {
80
+ ok: { type: "boolean" },
81
+ allowed: { type: "boolean" },
82
+ summary: { type: "string" },
83
+ confidence: { type: "number" },
84
+ checks_passed: { type: "array", items: { type: "string" } },
85
+ },
86
+ additionalProperties: true,
87
+ };
88
+ }
89
+ function paid200Response(path) {
90
+ const example = defaultOutputExample(path);
91
+ return {
92
+ description: "Successful response after x402 settlement",
93
+ content: {
94
+ "application/json": {
95
+ schema: paidResponseSchema(),
96
+ example,
97
+ },
98
+ },
99
+ };
100
+ }
101
+ function paymentRequiredResponse() {
102
+ return {
103
+ description: "Payment Required (x402 v2). Unpaid requests must receive HTTP 402 with Payment-Required header and non-empty accepts.",
104
+ headers: {
105
+ "Payment-Required": {
106
+ description: "Base64-encoded x402 payment requirements (v2)",
107
+ schema: { type: "string" },
108
+ },
109
+ },
110
+ };
111
+ }
112
+ function buildOperation(path, method, priceDisplay, tier) {
113
+ const meta = ENDPOINT_META[path] ?? { summary: path, tags: ["x402"] };
114
+ const priceUsd = formatUsdAmount(priceDisplay);
115
+ const upper = method.toUpperCase();
116
+ const example = VERIFY_EXAMPLES[path];
117
+ const op = {
118
+ operationId: operationId(path, method),
119
+ summary: meta.summary,
120
+ description: `${meta.summary} — ${priceDisplay} USDC via x402 (Dexter facilitator ${config.facilitatorUrl}).`,
121
+ tags: [tier, ...(meta.tags ?? [])],
122
+ security: [{ x402: [] }],
123
+ "x-payment-info": {
124
+ price: { mode: "fixed", currency: "USD", amount: priceUsd },
125
+ protocols: paymentProtocols(path),
126
+ },
127
+ responses: {
128
+ "200": paid200Response(path),
129
+ "402": paymentRequiredResponse(),
130
+ },
131
+ };
132
+ if (upper === "GET") {
133
+ if (path === "/api/attestation/registry") {
134
+ op.parameters = [
135
+ { name: "minGrade", in: "query", schema: { type: "string" }, required: false },
136
+ { name: "agentId", in: "query", schema: { type: "string" }, required: false },
137
+ { name: "limit", in: "query", schema: { type: "integer" }, required: false },
138
+ ];
139
+ op.responses = {
140
+ "200": {
141
+ description: "Registry records after payment",
142
+ content: {
143
+ "application/json": {
144
+ schema: paidResponseSchema(),
145
+ example: defaultOutputExample(path),
146
+ },
147
+ },
148
+ },
149
+ "402": paymentRequiredResponse(),
150
+ };
151
+ }
152
+ }
153
+ else if (example && typeof example === "object") {
154
+ op.requestBody = {
155
+ required: true,
156
+ content: {
157
+ "application/json": {
158
+ schema: exampleToSchema(example),
159
+ example,
160
+ },
161
+ },
162
+ };
163
+ }
164
+ else {
165
+ op.requestBody = {
166
+ required: true,
167
+ content: {
168
+ "application/json": {
169
+ schema: { type: "object", additionalProperties: true },
170
+ },
171
+ },
172
+ };
173
+ }
174
+ return op;
175
+ }
176
+ export function buildAgentCashOpenApi() {
177
+ const base = config.publicBaseUrl.replace(/\/$/, "");
178
+ const paths = {};
179
+ for (const entry of listEndpoints()) {
180
+ const [method, route] = entry.path.split(" ");
181
+ const m = (method ?? "POST").toLowerCase();
182
+ if (!paths[route])
183
+ paths[route] = {};
184
+ paths[route][m] = buildOperation(route, m, entry.price, entry.tier);
185
+ }
186
+ const ownershipProofs = [config.payToEvm, config.payTo].filter((v) => typeof v === "string" && v.length > 0);
187
+ return {
188
+ openapi: "3.1.0",
189
+ components: {
190
+ securitySchemes: {
191
+ x402: {
192
+ type: "apiKey",
193
+ in: "header",
194
+ name: "Payment-Signature",
195
+ description: "x402 v2 payment payload (base64)",
196
+ },
197
+ },
198
+ },
199
+ info: {
200
+ title: "x402 Trust Layer",
201
+ version: SUITE_VERSION,
202
+ description: "36 paid x402 trust infrastructure APIs: guard, semantic escrow, mandate diff, certified seller network, KYM, mandates, compliance, disputes, and orchestration.",
203
+ "x-guidance": AGENT_GUIDANCE,
204
+ },
205
+ "x-discovery": {
206
+ ownershipProofs,
207
+ publicEndpoints: [`${base}/health`, `${base}/.well-known/x402`],
208
+ freeEndpoints: [
209
+ { path: "/health", method: "GET", purpose: "Monitoring — not in OpenAPI paths" },
210
+ {
211
+ path: "/.well-known/x402",
212
+ method: "GET",
213
+ purpose: "Paid URL catalog — register /api/* from resources[]",
214
+ },
215
+ ],
216
+ },
217
+ "x-x402scan": {
218
+ discoveryMode: "openapi-first",
219
+ paidRouteCount: listEndpoints().length,
220
+ note: `OpenAPI lists ${listEndpoints().length} paid /api/* operations. Free routes documented under x-discovery.freeEndpoints.`,
221
+ },
222
+ servers: [{ url: config.publicBaseUrl }],
223
+ paths,
224
+ };
225
+ }
226
+ const BASE_USDC = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
227
+ function priceToMicro(priceStr) {
228
+ const n = Number(priceStr.replace(/^\$/, ""));
229
+ if (!Number.isFinite(n) || n <= 0)
230
+ return "10000";
231
+ return String(Math.round(n * 1_000_000));
232
+ }
233
+ function endpointAccepts(priceLabel) {
234
+ const payTo = config.payToEvm || config.payTo;
235
+ return {
236
+ scheme: "exact",
237
+ network: "eip155:8453",
238
+ asset: { address: BASE_USDC, decimals: 6 },
239
+ maxAmountRequired: priceToMicro(priceLabel),
240
+ payTo,
241
+ extra: { name: "USDC on Base" },
242
+ };
243
+ }
244
+ /** AgentCash / x402scan 2026 spec v2 — per-resource accepts with micro-units. */
245
+ export function buildWellKnownX402V2() {
246
+ const base = config.publicBaseUrl.replace(/\/$/, "");
247
+ const resources = listEndpoints()
248
+ .filter((e) => e.path.startsWith("POST "))
249
+ .map((e) => {
250
+ const [, route] = e.path.split(" ");
251
+ return {
252
+ url: `${base}${route}`,
253
+ method: "POST",
254
+ description: `${route} — ${e.tier} tier trust API`,
255
+ accepts: [endpointAccepts(e.price)],
256
+ tags: ["x402", "trust", e.tier],
257
+ "x-agent-hint": "Call before any external x402 payment when using guard or proxy flows",
258
+ };
259
+ });
260
+ return {
261
+ x402Version: 2,
262
+ protocolVersion: "2.14.0",
263
+ resources,
264
+ capabilities: ["guard", "mandate", "escrow", "attestation", "receipt-audit"],
265
+ pricing: {
266
+ preX402Guard: pricing.preX402Guard,
267
+ x402Proxy: pricing.x402Proxy,
268
+ },
269
+ };
270
+ }
271
+ /** x402scan / AgentCash compatibility fan-out */
272
+ export function buildWellKnownX402Resources() {
273
+ const ownershipProofs = [config.payToEvm, config.payTo].filter((v) => typeof v === "string" && v.length > 0);
274
+ const base = config.publicBaseUrl.replace(/\/$/, "");
275
+ const resources = listEndpoints().map((e) => {
276
+ const [, route] = e.path.split(" ");
277
+ return `${base}${route}`;
278
+ });
279
+ return {
280
+ x402Version: 2,
281
+ protocolVersion: "2.14.0",
282
+ version: 1,
283
+ resources,
284
+ ownershipProofs,
285
+ instructions: "Free catalog endpoint (HTTP 200). Register paid resource URLs from resources[] — not this URL. Paid routes: POST with Payment-Signature; GET /api/* returns 402 when unpaid.",
286
+ v2: `${base}/.well-known/x402/v2`,
287
+ };
288
+ }
@@ -0,0 +1,5 @@
1
+ /** OpenAPI / Bazaar summaries per route */
2
+ export declare const ENDPOINT_META: Record<string, {
3
+ summary: string;
4
+ tags: string[];
5
+ }>;