@absol-labs/agent 0.11.0 → 0.12.0-rc.2

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 (366) hide show
  1. package/README.md +43 -51
  2. package/dist/capability/invocation-capability.d.ts +2 -2
  3. package/dist/capability/probe-capability.d.ts +225 -0
  4. package/dist/capability/probe-capability.d.ts.map +1 -0
  5. package/dist/capability/probe-capability.js +248 -0
  6. package/dist/capability/probe-capability.js.map +1 -0
  7. package/dist/cli/args.d.ts +11 -0
  8. package/dist/cli/args.d.ts.map +1 -1
  9. package/dist/cli/args.js +23 -0
  10. package/dist/cli/args.js.map +1 -1
  11. package/dist/cli/commands/claim.d.ts +32 -0
  12. package/dist/cli/commands/claim.d.ts.map +1 -1
  13. package/dist/cli/commands/claim.js +116 -28
  14. package/dist/cli/commands/claim.js.map +1 -1
  15. package/dist/cli/commands/close.d.ts.map +1 -1
  16. package/dist/cli/commands/close.js +35 -3
  17. package/dist/cli/commands/close.js.map +1 -1
  18. package/dist/cli/commands/invoke.d.ts +2 -0
  19. package/dist/cli/commands/invoke.d.ts.map +1 -1
  20. package/dist/cli/commands/invoke.js +2 -2
  21. package/dist/cli/commands/invoke.js.map +1 -1
  22. package/dist/cli/commands/mcp.d.ts.map +1 -1
  23. package/dist/cli/commands/mcp.js +15 -2
  24. package/dist/cli/commands/mcp.js.map +1 -1
  25. package/dist/cli/commands/open.d.ts.map +1 -1
  26. package/dist/cli/commands/open.js +58 -4
  27. package/dist/cli/commands/open.js.map +1 -1
  28. package/dist/cli/commands/pay.d.ts +34 -0
  29. package/dist/cli/commands/pay.d.ts.map +1 -0
  30. package/dist/cli/commands/pay.js +479 -0
  31. package/dist/cli/commands/pay.js.map +1 -0
  32. package/dist/cli/commands/reclaim-unverified.d.ts.map +1 -1
  33. package/dist/cli/commands/reclaim-unverified.js +3 -2
  34. package/dist/cli/commands/reclaim-unverified.js.map +1 -1
  35. package/dist/cli/commands/reclaim.d.ts +23 -2
  36. package/dist/cli/commands/reclaim.d.ts.map +1 -1
  37. package/dist/cli/commands/reclaim.js +204 -20
  38. package/dist/cli/commands/reclaim.js.map +1 -1
  39. package/dist/cli/commands/refund.d.ts +31 -0
  40. package/dist/cli/commands/refund.d.ts.map +1 -0
  41. package/dist/cli/commands/refund.js +397 -0
  42. package/dist/cli/commands/refund.js.map +1 -0
  43. package/dist/cli/commands/status.d.ts.map +1 -1
  44. package/dist/cli/commands/status.js +21 -2
  45. package/dist/cli/commands/status.js.map +1 -1
  46. package/dist/cli/commands/streams.js +8 -12
  47. package/dist/cli/commands/streams.js.map +1 -1
  48. package/dist/cli/commands/watch.d.ts.map +1 -1
  49. package/dist/cli/commands/watch.js +4 -1
  50. package/dist/cli/commands/watch.js.map +1 -1
  51. package/dist/cli/config.d.ts +44 -26
  52. package/dist/cli/config.d.ts.map +1 -1
  53. package/dist/cli/config.js +88 -38
  54. package/dist/cli/config.js.map +1 -1
  55. package/dist/cli/context.d.ts +19 -0
  56. package/dist/cli/context.d.ts.map +1 -1
  57. package/dist/cli/deps.d.ts +53 -0
  58. package/dist/cli/deps.d.ts.map +1 -1
  59. package/dist/cli/deps.js +51 -1
  60. package/dist/cli/deps.js.map +1 -1
  61. package/dist/cli/errors.d.ts.map +1 -1
  62. package/dist/cli/errors.js +21 -1
  63. package/dist/cli/errors.js.map +1 -1
  64. package/dist/cli/escape-hatch.d.ts +6 -4
  65. package/dist/cli/escape-hatch.d.ts.map +1 -1
  66. package/dist/cli/escape-hatch.js +6 -2
  67. package/dist/cli/escape-hatch.js.map +1 -1
  68. package/dist/cli/listings.d.ts +18 -0
  69. package/dist/cli/listings.d.ts.map +1 -1
  70. package/dist/cli/listings.js +22 -12
  71. package/dist/cli/listings.js.map +1 -1
  72. package/dist/cli/preflight.d.ts +20 -14
  73. package/dist/cli/preflight.d.ts.map +1 -1
  74. package/dist/cli/preflight.js +34 -20
  75. package/dist/cli/preflight.js.map +1 -1
  76. package/dist/cli/privy.d.ts.map +1 -1
  77. package/dist/cli/privy.js +4 -2
  78. package/dist/cli/privy.js.map +1 -1
  79. package/dist/cli/progress.d.ts +13 -1
  80. package/dist/cli/progress.d.ts.map +1 -1
  81. package/dist/cli/progress.js +7 -1
  82. package/dist/cli/progress.js.map +1 -1
  83. package/dist/cli/reclaimability.d.ts +82 -0
  84. package/dist/cli/reclaimability.d.ts.map +1 -0
  85. package/dist/cli/reclaimability.js +80 -0
  86. package/dist/cli/reclaimability.js.map +1 -0
  87. package/dist/cli/run.d.ts +2 -1
  88. package/dist/cli/run.d.ts.map +1 -1
  89. package/dist/cli/run.js +62 -21
  90. package/dist/cli/run.js.map +1 -1
  91. package/dist/cli/scan-range.d.ts +2 -2
  92. package/dist/cli/scan-range.js +2 -2
  93. package/dist/cli/status.d.ts +106 -1
  94. package/dist/cli/status.d.ts.map +1 -1
  95. package/dist/cli/status.js +325 -44
  96. package/dist/cli/status.js.map +1 -1
  97. package/dist/cli/wallet.d.ts +2 -2
  98. package/dist/cli/wallet.d.ts.map +1 -1
  99. package/dist/cli/wallet.js +29 -5
  100. package/dist/cli/wallet.js.map +1 -1
  101. package/dist/discovery/rate-band.d.ts +74 -0
  102. package/dist/discovery/rate-band.d.ts.map +1 -0
  103. package/dist/discovery/rate-band.js +114 -0
  104. package/dist/discovery/rate-band.js.map +1 -0
  105. package/dist/escrow-generation.d.ts +81 -0
  106. package/dist/escrow-generation.d.ts.map +1 -0
  107. package/dist/escrow-generation.js +76 -0
  108. package/dist/escrow-generation.js.map +1 -0
  109. package/dist/frameworks/agentkit.d.ts +8 -4
  110. package/dist/frameworks/agentkit.d.ts.map +1 -1
  111. package/dist/frameworks/agentkit.js +27 -10
  112. package/dist/frameworks/agentkit.js.map +1 -1
  113. package/dist/frameworks/eliza.d.ts +3 -3
  114. package/dist/frameworks/eliza.d.ts.map +1 -1
  115. package/dist/frameworks/eliza.js +15 -6
  116. package/dist/frameworks/eliza.js.map +1 -1
  117. package/dist/frameworks/langchain.d.ts.map +1 -1
  118. package/dist/frameworks/langchain.js +8 -0
  119. package/dist/frameworks/langchain.js.map +1 -1
  120. package/dist/gateway/caller-auth-gateway.d.ts +83 -31
  121. package/dist/gateway/caller-auth-gateway.d.ts.map +1 -1
  122. package/dist/gateway/caller-auth-gateway.js +180 -27
  123. package/dist/gateway/caller-auth-gateway.js.map +1 -1
  124. package/dist/gateway/http-server.d.ts +128 -44
  125. package/dist/gateway/http-server.d.ts.map +1 -1
  126. package/dist/gateway/http-server.js +506 -155
  127. package/dist/gateway/http-server.js.map +1 -1
  128. package/dist/gateway/probe-auth.d.ts +112 -0
  129. package/dist/gateway/probe-auth.d.ts.map +1 -0
  130. package/dist/gateway/probe-auth.js +127 -0
  131. package/dist/gateway/probe-auth.js.map +1 -0
  132. package/dist/gateway/signed-rate-bounds.d.ts +51 -0
  133. package/dist/gateway/signed-rate-bounds.d.ts.map +1 -0
  134. package/dist/gateway/signed-rate-bounds.js +94 -0
  135. package/dist/gateway/signed-rate-bounds.js.map +1 -0
  136. package/dist/gateway/x402-opener-mode.d.ts +252 -0
  137. package/dist/gateway/x402-opener-mode.d.ts.map +1 -0
  138. package/dist/gateway/x402-opener-mode.js +772 -0
  139. package/dist/gateway/x402-opener-mode.js.map +1 -0
  140. package/dist/index.d.ts +6 -2
  141. package/dist/index.d.ts.map +1 -1
  142. package/dist/index.js +10 -5
  143. package/dist/index.js.map +1 -1
  144. package/dist/mcp/server.d.ts +64 -1
  145. package/dist/mcp/server.d.ts.map +1 -1
  146. package/dist/mcp/server.js +247 -37
  147. package/dist/mcp/server.js.map +1 -1
  148. package/dist/mcp/x402-tools.d.ts +109 -0
  149. package/dist/mcp/x402-tools.d.ts.map +1 -0
  150. package/dist/mcp/x402-tools.js +554 -0
  151. package/dist/mcp/x402-tools.js.map +1 -0
  152. package/dist/network.d.ts +119 -0
  153. package/dist/network.d.ts.map +1 -0
  154. package/dist/network.js +199 -0
  155. package/dist/network.js.map +1 -0
  156. package/dist/sdk/client.d.ts +13 -0
  157. package/dist/sdk/client.d.ts.map +1 -1
  158. package/dist/sdk/client.js +15 -0
  159. package/dist/sdk/client.js.map +1 -1
  160. package/dist/sdk/invoke.d.ts +4 -0
  161. package/dist/sdk/invoke.d.ts.map +1 -1
  162. package/dist/sdk/invoke.js +2 -5
  163. package/dist/sdk/invoke.js.map +1 -1
  164. package/dist/wallet/autonomous-wallet-broker.d.ts +3 -0
  165. package/dist/wallet/autonomous-wallet-broker.d.ts.map +1 -1
  166. package/dist/wallet/autonomous-wallet-broker.js +27 -23
  167. package/dist/wallet/autonomous-wallet-broker.js.map +1 -1
  168. package/dist/wallet/autonomous-wallet-protocol.d.ts +8 -2
  169. package/dist/wallet/autonomous-wallet-protocol.d.ts.map +1 -1
  170. package/dist/wallet/autonomous-wallet-protocol.js +9 -2
  171. package/dist/wallet/autonomous-wallet-protocol.js.map +1 -1
  172. package/dist/wallet/autonomous-wallet.d.ts.map +1 -1
  173. package/dist/wallet/autonomous-wallet.js +3 -2
  174. package/dist/wallet/autonomous-wallet.js.map +1 -1
  175. package/dist/wallet/broker-escrows.d.ts +222 -0
  176. package/dist/wallet/broker-escrows.d.ts.map +1 -0
  177. package/dist/wallet/broker-escrows.js +36 -0
  178. package/dist/wallet/broker-escrows.js.map +1 -0
  179. package/dist/wallet/lifecycle.d.ts +21 -5
  180. package/dist/wallet/lifecycle.d.ts.map +1 -1
  181. package/dist/wallet/lifecycle.js +32 -12
  182. package/dist/wallet/lifecycle.js.map +1 -1
  183. package/dist/wallet/privy-broker-server.d.ts.map +1 -1
  184. package/dist/wallet/privy-broker-server.js +31 -26
  185. package/dist/wallet/privy-broker-server.js.map +1 -1
  186. package/dist/wallet/privy-session-broker.d.ts +14 -5
  187. package/dist/wallet/privy-session-broker.d.ts.map +1 -1
  188. package/dist/wallet/privy-session-broker.js +29 -17
  189. package/dist/wallet/privy-session-broker.js.map +1 -1
  190. package/dist/wallet/privy-session-provider.d.ts +3 -1
  191. package/dist/wallet/privy-session-provider.d.ts.map +1 -1
  192. package/dist/wallet/privy-session-provider.js +5 -3
  193. package/dist/wallet/privy-session-provider.js.map +1 -1
  194. package/dist/wallet/provider.d.ts.map +1 -1
  195. package/dist/wallet/provider.js +15 -8
  196. package/dist/wallet/provider.js.map +1 -1
  197. package/dist/x402/facilitator.d.ts +3 -30
  198. package/dist/x402/facilitator.d.ts.map +1 -1
  199. package/dist/x402/facilitator.js +0 -27
  200. package/dist/x402/facilitator.js.map +1 -1
  201. package/dist/x402-buyer/guarded-fetch.d.ts +51 -0
  202. package/dist/x402-buyer/guarded-fetch.d.ts.map +1 -0
  203. package/dist/x402-buyer/guarded-fetch.js +147 -0
  204. package/dist/x402-buyer/guarded-fetch.js.map +1 -0
  205. package/dist/x402-buyer/index.d.ts +10 -0
  206. package/dist/x402-buyer/index.d.ts.map +1 -0
  207. package/dist/x402-buyer/index.js +10 -0
  208. package/dist/x402-buyer/index.js.map +1 -0
  209. package/dist/x402-buyer/pay.d.ts +157 -0
  210. package/dist/x402-buyer/pay.d.ts.map +1 -0
  211. package/dist/x402-buyer/pay.js +366 -0
  212. package/dist/x402-buyer/pay.js.map +1 -0
  213. package/dist/x402-opener/abi.d.ts +684 -0
  214. package/dist/x402-opener/abi.d.ts.map +1 -0
  215. package/dist/x402-opener/abi.js +880 -0
  216. package/dist/x402-opener/abi.js.map +1 -0
  217. package/dist/x402-opener/facilitator-entry.d.ts +3 -0
  218. package/dist/x402-opener/facilitator-entry.d.ts.map +1 -0
  219. package/dist/x402-opener/facilitator-entry.js +40 -0
  220. package/dist/x402-opener/facilitator-entry.js.map +1 -0
  221. package/dist/x402-opener/facilitator-server.d.ts +209 -0
  222. package/dist/x402-opener/facilitator-server.d.ts.map +1 -0
  223. package/dist/x402-opener/facilitator-server.js +762 -0
  224. package/dist/x402-opener/facilitator-server.js.map +1 -0
  225. package/dist/x402-opener/index.d.ts +14 -0
  226. package/dist/x402-opener/index.d.ts.map +1 -0
  227. package/dist/x402-opener/index.js +14 -0
  228. package/dist/x402-opener/index.js.map +1 -0
  229. package/dist/x402-opener/listing-resolver.d.ts +55 -0
  230. package/dist/x402-opener/listing-resolver.d.ts.map +1 -0
  231. package/dist/x402-opener/listing-resolver.js +125 -0
  232. package/dist/x402-opener/listing-resolver.js.map +1 -0
  233. package/dist/x402-opener/refund-relay.d.ts +266 -0
  234. package/dist/x402-opener/refund-relay.d.ts.map +1 -0
  235. package/dist/x402-opener/refund-relay.js +1341 -0
  236. package/dist/x402-opener/refund-relay.js.map +1 -0
  237. package/dist/x402-opener/relayer-queue.d.ts +14 -0
  238. package/dist/x402-opener/relayer-queue.d.ts.map +1 -0
  239. package/dist/x402-opener/relayer-queue.js +18 -0
  240. package/dist/x402-opener/relayer-queue.js.map +1 -0
  241. package/dist/x402-opener/scheme.d.ts +296 -0
  242. package/dist/x402-opener/scheme.d.ts.map +1 -0
  243. package/dist/x402-opener/scheme.js +1035 -0
  244. package/dist/x402-opener/scheme.js.map +1 -0
  245. package/dist/x402-opener/terms.d.ts +165 -0
  246. package/dist/x402-opener/terms.d.ts.map +1 -0
  247. package/dist/x402-opener/terms.js +304 -0
  248. package/dist/x402-opener/terms.js.map +1 -0
  249. package/dist/zktls/reclaim.d.ts +2 -2
  250. package/dist/zktls/t2-delivery-proof.d.ts +6 -6
  251. package/docs/agent-layer.md +3 -2
  252. package/docs/autonomous-privy-wallet.md +188 -0
  253. package/docs/cli.md +265 -34
  254. package/docs/langchain.md +5 -0
  255. package/docs/mcp-reference.md +91 -5
  256. package/docs/probe-capability.md +191 -0
  257. package/docs/quickstart.md +39 -4
  258. package/docs/threat-model.md +20 -0
  259. package/docs/x402.md +766 -593
  260. package/package.json +19 -17
  261. package/src/capability/probe-capability.ts +355 -0
  262. package/src/cli/args.ts +29 -0
  263. package/src/cli/commands/claim.ts +168 -33
  264. package/src/cli/commands/close.ts +36 -3
  265. package/src/cli/commands/invoke.ts +5 -2
  266. package/src/cli/commands/mcp.ts +18 -2
  267. package/src/cli/commands/open.ts +75 -4
  268. package/src/cli/commands/pay.ts +584 -0
  269. package/src/cli/commands/reclaim-unverified.ts +8 -2
  270. package/src/cli/commands/reclaim.ts +277 -19
  271. package/src/cli/commands/refund.ts +475 -0
  272. package/src/cli/commands/status.ts +28 -2
  273. package/src/cli/commands/streams.ts +10 -14
  274. package/src/cli/commands/watch.ts +11 -1
  275. package/src/cli/config.ts +139 -52
  276. package/src/cli/context.ts +16 -0
  277. package/src/cli/deps.ts +111 -1
  278. package/src/cli/errors.ts +24 -1
  279. package/src/cli/escape-hatch.ts +19 -5
  280. package/src/cli/listings.ts +43 -10
  281. package/src/cli/preflight.ts +36 -21
  282. package/src/cli/privy.ts +4 -2
  283. package/src/cli/progress.ts +21 -2
  284. package/src/cli/reclaimability.ts +154 -0
  285. package/src/cli/run.ts +77 -21
  286. package/src/cli/scan-range.ts +2 -2
  287. package/src/cli/status.ts +454 -44
  288. package/src/cli/wallet.ts +45 -8
  289. package/src/discovery/rate-band.ts +172 -0
  290. package/src/escrow-generation.ts +135 -0
  291. package/src/frameworks/agentkit.ts +45 -11
  292. package/src/frameworks/eliza.ts +27 -5
  293. package/src/frameworks/langchain.ts +14 -0
  294. package/src/gateway/caller-auth-gateway.ts +320 -68
  295. package/src/gateway/http-server.ts +717 -220
  296. package/src/gateway/probe-auth.ts +191 -0
  297. package/src/gateway/signed-rate-bounds.ts +164 -0
  298. package/src/gateway/x402-opener-mode.ts +1171 -0
  299. package/src/index.ts +82 -19
  300. package/src/mcp/server.ts +351 -42
  301. package/src/mcp/x402-tools.ts +785 -0
  302. package/src/network.ts +302 -0
  303. package/src/sdk/client.ts +25 -0
  304. package/src/sdk/invoke.ts +6 -5
  305. package/src/wallet/autonomous-wallet-broker.ts +46 -20
  306. package/src/wallet/autonomous-wallet-protocol.ts +11 -2
  307. package/src/wallet/autonomous-wallet.ts +4 -2
  308. package/src/wallet/broker-escrows.ts +66 -0
  309. package/src/wallet/lifecycle.ts +53 -18
  310. package/src/wallet/privy-broker-server.ts +35 -25
  311. package/src/wallet/privy-session-broker.ts +58 -25
  312. package/src/wallet/privy-session-provider.ts +7 -3
  313. package/src/wallet/provider.ts +20 -15
  314. package/src/x402/facilitator.ts +3 -43
  315. package/src/x402-buyer/guarded-fetch.ts +213 -0
  316. package/src/x402-buyer/index.ts +9 -0
  317. package/src/x402-buyer/pay.ts +555 -0
  318. package/src/x402-opener/abi.ts +881 -0
  319. package/src/x402-opener/facilitator-entry.ts +48 -0
  320. package/src/x402-opener/facilitator-server.ts +1114 -0
  321. package/src/x402-opener/index.ts +13 -0
  322. package/src/x402-opener/listing-resolver.ts +202 -0
  323. package/src/x402-opener/refund-relay.ts +1873 -0
  324. package/src/x402-opener/relayer-queue.ts +18 -0
  325. package/src/x402-opener/scheme.ts +1551 -0
  326. package/src/x402-opener/terms.ts +453 -0
  327. package/dist/gateway/x402-mode.d.ts +0 -123
  328. package/dist/gateway/x402-mode.d.ts.map +0 -1
  329. package/dist/gateway/x402-mode.js +0 -212
  330. package/dist/gateway/x402-mode.js.map +0 -1
  331. package/dist/x402/delivery-oracle.d.ts +0 -108
  332. package/dist/x402/delivery-oracle.d.ts.map +0 -1
  333. package/dist/x402/delivery-oracle.js +0 -174
  334. package/dist/x402/delivery-oracle.js.map +0 -1
  335. package/dist/x402/facilitator-server-entry.d.ts +0 -3
  336. package/dist/x402/facilitator-server-entry.d.ts.map +0 -1
  337. package/dist/x402/facilitator-server-entry.js +0 -27
  338. package/dist/x402/facilitator-server-entry.js.map +0 -1
  339. package/dist/x402/facilitator-server.d.ts +0 -73
  340. package/dist/x402/facilitator-server.d.ts.map +0 -1
  341. package/dist/x402/facilitator-server.js +0 -305
  342. package/dist/x402/facilitator-server.js.map +0 -1
  343. package/dist/x402/payment-requirements.d.ts +0 -106
  344. package/dist/x402/payment-requirements.d.ts.map +0 -1
  345. package/dist/x402/payment-requirements.js +0 -138
  346. package/dist/x402/payment-requirements.js.map +0 -1
  347. package/dist/x402/relayer.d.ts +0 -41
  348. package/dist/x402/relayer.d.ts.map +0 -1
  349. package/dist/x402/relayer.js +0 -64
  350. package/dist/x402/relayer.js.map +0 -1
  351. package/dist/x402/resource-index.d.ts +0 -75
  352. package/dist/x402/resource-index.d.ts.map +0 -1
  353. package/dist/x402/resource-index.js +0 -126
  354. package/dist/x402/resource-index.js.map +0 -1
  355. package/dist/x402/verified-delivery-facilitator.d.ts +0 -285
  356. package/dist/x402/verified-delivery-facilitator.d.ts.map +0 -1
  357. package/dist/x402/verified-delivery-facilitator.js +0 -423
  358. package/dist/x402/verified-delivery-facilitator.js.map +0 -1
  359. package/src/gateway/x402-mode.ts +0 -350
  360. package/src/x402/delivery-oracle.ts +0 -285
  361. package/src/x402/facilitator-server-entry.ts +0 -35
  362. package/src/x402/facilitator-server.ts +0 -445
  363. package/src/x402/payment-requirements.ts +0 -231
  364. package/src/x402/relayer.ts +0 -122
  365. package/src/x402/resource-index.ts +0 -228
  366. package/src/x402/verified-delivery-facilitator.ts +0 -744
@@ -1,13 +1,5 @@
1
- import { MetrikClient } from "@absol-labs/sdk";
2
1
  import { isAddress, isHex, type Address, type Hex } from "viem";
3
2
 
4
- import {
5
- evaluateX402Request,
6
- X402_PAYMENT_HEADER,
7
- type AcceptedX402Payment,
8
- type GatewayX402Mode,
9
- } from "./x402-mode.js";
10
- import type { X402PaymentRequiredBody } from "../x402/payment-requirements.js";
11
3
  import {
12
4
  CAPABILITY_HEADER_NAME,
13
5
  decodeCapabilityHeader,
@@ -17,6 +9,29 @@ import {
17
9
  type InvocationCapabilityDomainInput,
18
10
  type SignedInvocationCapability,
19
11
  } from "../capability/invocation-capability.js";
12
+ import {
13
+ decodeProbeCapabilityHeader,
14
+ hashProbePath,
15
+ InvalidProbeCapabilityHeaderError,
16
+ PROBE_CAPABILITY_HEADER_NAME,
17
+ recoverProbeCapabilitySigner,
18
+ type ProbeCapabilityDomainInput,
19
+ type SignedProbeCapability,
20
+ } from "../capability/probe-capability.js";
21
+ import {
22
+ CachedOracleSignerSet,
23
+ createSdkOracleSignerSetReader,
24
+ FixedWindowProbeRateLimiter,
25
+ type GatewayProbeMode,
26
+ type ProbeAuthorization,
27
+ type ProbeRateLimiter,
28
+ } from "./probe-auth.js";
29
+ import { defaultNetwork, readOnlyMetrikClient } from "../network.js";
30
+ import {
31
+ isVerifiedSignedRateBounds,
32
+ rateOutsideBounds,
33
+ type SignedRateBounds,
34
+ } from "./signed-rate-bounds.js";
20
35
 
21
36
  /**
22
37
  * Seller-side caller-auth gateway (metrik-agent#63, impl of #62 part 1/2).
@@ -78,19 +93,43 @@ export type CallerAuthDenialReason =
78
93
  | "stream-not-funded"
79
94
  | "stream-state-stale"
80
95
  /**
81
- * No Metrik capability, and x402 mode is enabled: the caller may pay per call
82
- * instead. Carries an x402 `402` body in
83
- * {@link CallerAuthDecision.x402PaymentRequired}. Emitted ONLY when
84
- * {@link CallerAuthGatewayConfig.x402} is configured — without it, a missing
85
- * capability is still `missing-capability-header` / `403`, unchanged.
96
+ * The stream's on-chain `ratePerSecond` is outside the operator-SIGNED
97
+ * `minRatePerSecond`/`maxRatePerSecond` of this service's descriptor
98
+ * (metrik-contracts#41: the escrow accepts any non-zero rate, so a buyer
99
+ * calling it directly could otherwise open an underpriced stream and be
100
+ * served). Irreversible: the rate is fixed at open.
86
101
  */
87
- | "x402-payment-required"
102
+ | "stream-rate-out-of-bounds"
88
103
  /**
89
- * The request carried BOTH a Metrik capability and an `X-PAYMENT` header.
90
- * Refused rather than guessed: serving it would charge the caller through one
91
- * path while they believe they paid through the other.
104
+ * Signed rate bounds are configured but the stream view carries no
105
+ * `ratePerSecond`, so the band cannot be checked. Fail closed.
92
106
  */
93
- | "ambiguous-payment-mode";
107
+ | "stream-rate-unknown"
108
+ /**
109
+ * The request carried an oracle probe capability AND a buyer capability or an
110
+ * `X-PAYMENT` header. Refused rather than guessed: a probe is free and unbilled,
111
+ * a buyer call is neither, and the two must never be conflated.
112
+ */
113
+ | "ambiguous-probe-mode"
114
+ /**
115
+ * A probe capability was presented but this gateway has probe verification
116
+ * turned off. Distinct from the malformed/invalid reasons: it tells the
117
+ * oracle the paid route is UNVERIFIABLE here, not that it failed.
118
+ */
119
+ | "probe-not-enabled"
120
+ | "malformed-probe-capability"
121
+ | "probe-capability-expired"
122
+ | "probe-invalid-signature"
123
+ | "probe-method-mismatch"
124
+ | "probe-path-mismatch"
125
+ | "probe-service-ref-mismatch"
126
+ | "probe-nonce-replayed"
127
+ /** The recovered signer is not in the escrow's `getOracleSigners()` set. */
128
+ | "probe-signer-not-authorized"
129
+ /** The signer set could not be read fresh enough to decide. Fail closed. */
130
+ | "probe-signer-set-unavailable"
131
+ /** The free-probe budget for this window is spent. */
132
+ | "probe-rate-limited";
94
133
 
95
134
  /**
96
135
  * Default freshness bound for on-chain stream state, in seconds. Base blocks
@@ -113,7 +152,9 @@ const DENIAL_PRECEDENCE: readonly CallerAuthDenialReason[] = [
113
152
  "stream-expired",
114
153
  "buyer-mismatch",
115
154
  "service-ref-mismatch",
155
+ "stream-rate-out-of-bounds",
116
156
  "stream-not-funded",
157
+ "stream-rate-unknown",
117
158
  "stream-state-stale",
118
159
  "stream-not-found",
119
160
  ];
@@ -131,28 +172,38 @@ const DENIAL_PRECEDENCE: readonly CallerAuthDenialReason[] = [
131
172
  const TERMINAL_DENIALS: ReadonlySet<CallerAuthDenialReason> = new Set([
132
173
  "stream-not-active",
133
174
  "stream-not-funded",
175
+ // `ratePerSecond` is fixed at open and the signed band is this process's
176
+ // configuration, so an out-of-band stream stays out of band.
177
+ "stream-rate-out-of-bounds",
134
178
  ]);
135
179
 
180
+ /**
181
+ * A probe carrying an `X-PAYMENT` header is refused as `ambiguous-probe-mode`.
182
+ * This gateway implements no per-call payment mode (the x402 v1 integration was
183
+ * removed in metrik-agent#115), but the refusal is kept deliberately: a probe
184
+ * is free, unbilled verification traffic and must never be mixed with anything
185
+ * that looks like a payment, and keeping it leaves the deployed gateway's
186
+ * behaviour byte-for-byte unchanged.
187
+ */
188
+ const PAYMENT_HEADER_REFUSED_ON_PROBES = "x-payment";
189
+
136
190
  export interface CallerAuthDecision {
137
191
  readonly authorized: boolean;
138
192
  readonly reason?: CallerAuthDenialReason;
139
193
  /** Set only when `authorized === false`. */
140
- readonly httpStatus?: 400 | 402 | 403;
194
+ readonly httpStatus?: 400 | 402 | 403 | 429;
141
195
  /** Set only when `authorized === true` via the Metrik stream path. */
142
196
  readonly stream?: GatewayStreamView;
143
- /** The decoded (but not necessarily valid) capability, when one was present. */
144
- readonly capability?: SignedInvocationCapability;
145
197
  /**
146
- * The x402 `402` body to return verbatim. Set only with
147
- * `reason === "x402-payment-required"`.
198
+ * Set only when `authorized === true` via the ORACLE PROBE path. Mutually
199
+ * exclusive with {@link stream} by construction: the probe branch returns
200
+ * before a stream is ever produced, so an authorized probe can never draw on
201
+ * a stream's budget. It is
202
+ * verification traffic and MUST NOT be metered or billed.
148
203
  */
149
- readonly x402PaymentRequired?: X402PaymentRequiredBody;
150
- /**
151
- * A verified x402 payment. Set only when `authorized === true` via the x402
152
- * path. The caller MUST settle it (see `./x402-mode.ts`) — verification alone
153
- * moves no money.
154
- */
155
- readonly x402Payment?: AcceptedX402Payment;
204
+ readonly probe?: ProbeAuthorization;
205
+ /** The decoded (but not necessarily valid) capability, when one was present. */
206
+ readonly capability?: SignedInvocationCapability;
156
207
  }
157
208
 
158
209
  /** The minimal on-chain stream fields the gateway needs to authorize a call. */
@@ -163,6 +214,13 @@ export interface GatewayStreamView {
163
214
  readonly claimedCumulative: bigint;
164
215
  readonly expiresAt: number;
165
216
  readonly status: "active" | "closed";
217
+ /**
218
+ * The stream's contracted `ratePerSecond` (USDC base units per verified
219
+ * second), fixed at open. Required when the gateway enforces operator-signed
220
+ * rate bounds; a view without it is refused (`stream-rate-unknown`) there.
221
+ * The default SDK reader always reports it.
222
+ */
223
+ readonly ratePerSecond?: bigint;
166
224
  /**
167
225
  * The chain head this view was observed against. Readers SHOULD report it:
168
226
  * when present, the gateway rejects the view outright if the block is older
@@ -235,11 +293,10 @@ export class UnknownStreamGatewayError extends Error {
235
293
  export function createSdkStreamReader(options: {
236
294
  readonly escrowAddress: Address;
237
295
  readonly rpcUrl: string;
296
+ /** Chain of the escrow; must be a registered network. Default: the registry default. */
297
+ readonly chainId?: number;
238
298
  }): StreamReader {
239
- const metrik = MetrikClient.baseSepolia({
240
- escrow: options.escrowAddress,
241
- rpcUrl: options.rpcUrl,
242
- });
299
+ const metrik = readOnlyMetrikClient(options);
243
300
  return {
244
301
  async getStream(streamId) {
245
302
  try {
@@ -258,6 +315,7 @@ export function createSdkStreamReader(options: {
258
315
  claimedCumulative: stream.claimedCumulative,
259
316
  expiresAt: stream.expiresAt,
260
317
  status: stream.status,
318
+ ratePerSecond: stream.ratePerSecond,
261
319
  observedAt: {
262
320
  blockNumber: block.number,
263
321
  blockTimestamp: Number(block.timestamp),
@@ -316,7 +374,7 @@ export interface CallerAuthGatewayConfig {
316
374
  readonly serviceRef: Hex;
317
375
  /** Additional service refs accepted during signed-descriptor migrations. */
318
376
  readonly serviceRefs?: readonly Hex[];
319
- /** Chain id for EIP-712 domain separation. Default `84532` (Base Sepolia). */
377
+ /** Chain id for EIP-712 domain separation and the default readers. Default: the registry's default network. */
320
378
  readonly chainId?: number;
321
379
  /** Capability header name. Default {@link CAPABILITY_HEADER_NAME}. */
322
380
  readonly headerName?: string;
@@ -349,12 +407,27 @@ export interface CallerAuthGatewayConfig {
349
407
  /** Injectable clock (unix seconds), for tests. */
350
408
  readonly now?: () => number;
351
409
  /**
352
- * Optional standard-x402 mode. When set, a request with NO Metrik capability
353
- * gets a real x402 `402` challenge instead of a `403`, so a caller holding
354
- * only `x402-fetch` can pay per call. Leaving it unset preserves today's
355
- * behaviour byte for byte.
410
+ * Optional ORACLE PROBE mode. When set, a request carrying a valid
411
+ * oracle-signed `ProbeCapability` is authorized and proxied WITHOUT any
412
+ * stream, payment or metering, so the neutral verifier can exercise this
413
+ * gateway's PAID route even though the listing is gated.
414
+ *
415
+ * OFF by default. A gateway that leaves it unset behaves byte for byte as
416
+ * before and answers a probe with `probe-not-enabled` / `403` — which the
417
+ * oracle reports as UNVERIFIABLE (health-route-only), never as passing.
418
+ */
419
+ readonly probe?: GatewayProbeMode;
420
+ /**
421
+ * Operator-SIGNED rate bounds to enforce on the capability path, one per
422
+ * served serviceRef (metrik-contracts#41). Each entry must come from
423
+ * {@link verifySignedRateBounds} (or `loadSignedRateBoundsFile`) and name one
424
+ * of this gateway's service refs. A stream whose serviceRef has bounds is
425
+ * served only while its on-chain `ratePerSecond` lies inside them.
426
+ *
427
+ * Unset = no rate enforcement here (the previous behaviour); the reference
428
+ * server warns when it starts without them.
356
429
  */
357
- readonly x402?: GatewayX402Mode;
430
+ readonly signedRateBounds?: readonly SignedRateBounds[];
358
431
  }
359
432
 
360
433
  export interface CallerAuthRequestInput {
@@ -380,7 +453,11 @@ export class CallerAuthGateway {
380
453
  private readonly domain: InvocationCapabilityDomainInput;
381
454
  private readonly serviceRefs: ReadonlySet<string>;
382
455
  private readonly now: () => number;
383
- private readonly x402: GatewayX402Mode | undefined;
456
+ private readonly probeHeaderName: string;
457
+ private readonly probeDomain: ProbeCapabilityDomainInput;
458
+ private readonly probeSigners: CachedOracleSignerSet | undefined;
459
+ private readonly probeRateLimiter: ProbeRateLimiter | undefined;
460
+ private readonly rateBounds: ReadonlyMap<string, SignedRateBounds>;
384
461
 
385
462
  constructor(config: CallerAuthGatewayConfig) {
386
463
  if (!isAddress(config.escrowAddress)) {
@@ -398,7 +475,29 @@ export class CallerAuthGateway {
398
475
  );
399
476
  }
400
477
 
478
+ const chainId = config.chainId ?? defaultNetwork().chain.id;
401
479
  this.serviceRefs = new Set(serviceRefs.map((value) => value.toLowerCase()));
480
+ const rateBounds = new Map<string, SignedRateBounds>();
481
+ for (const bounds of config.signedRateBounds ?? []) {
482
+ if (!isVerifiedSignedRateBounds(bounds)) {
483
+ throw new Error(
484
+ "signedRateBounds entries must come from verifySignedRateBounds() / loadSignedRateBoundsFile(); an unverified object is not operator-signed",
485
+ );
486
+ }
487
+ const key = bounds.serviceRef.toLowerCase();
488
+ if (!this.serviceRefs.has(key)) {
489
+ throw new Error(
490
+ `signed rate bounds for ${bounds.serviceRef} are not a service ref this gateway serves`,
491
+ );
492
+ }
493
+ if (rateBounds.has(key)) {
494
+ throw new Error(
495
+ `more than one set of signed rate bounds for ${bounds.serviceRef}`,
496
+ );
497
+ }
498
+ rateBounds.set(key, bounds);
499
+ }
500
+ this.rateBounds = rateBounds;
402
501
  this.headerName = (
403
502
  config.headerName ?? CAPABILITY_HEADER_NAME
404
503
  ).toLowerCase();
@@ -407,6 +506,7 @@ export class CallerAuthGateway {
407
506
  createSdkStreamReader({
408
507
  escrowAddress: config.escrowAddress,
409
508
  rpcUrl: config.rpcUrl as string,
509
+ chainId,
410
510
  });
411
511
  const corroborating =
412
512
  config.corroboratingStreamReaders ??
@@ -414,6 +514,7 @@ export class CallerAuthGateway {
414
514
  createSdkStreamReader({
415
515
  escrowAddress: config.escrowAddress,
416
516
  rpcUrl,
517
+ chainId,
417
518
  }),
418
519
  );
419
520
  if (corroborating.length > MAX_CORROBORATING_STREAM_READERS) {
@@ -433,11 +534,66 @@ export class CallerAuthGateway {
433
534
  config.revocationSet ?? new InMemoryStreamRevocationSet();
434
535
  this.nonceCache = config.nonceCache ?? new InMemoryNonceReplayCache();
435
536
  this.domain = {
436
- chainId: config.chainId ?? 84532,
537
+ chainId,
437
538
  verifyingContract: config.escrowAddress,
438
539
  };
439
540
  this.now = config.now ?? (() => Math.floor(Date.now() / 1000));
440
- this.x402 = config.x402;
541
+
542
+ // Probe mode shares the chain binding with the invocation domain (same
543
+ // escrow, same chain) but a DIFFERENT EIP-712 domain name, so neither
544
+ // signature is ever valid as the other.
545
+ this.probeDomain = {
546
+ chainId,
547
+ verifyingContract: config.escrowAddress,
548
+ };
549
+ this.probeHeaderName = (
550
+ config.probe?.headerName ?? PROBE_CAPABILITY_HEADER_NAME
551
+ ).toLowerCase();
552
+ if (this.probeHeaderName === this.headerName) {
553
+ throw new Error(
554
+ "the probe capability header must differ from the invocation capability header",
555
+ );
556
+ }
557
+ if (config.probe === undefined) {
558
+ this.probeSigners = undefined;
559
+ this.probeRateLimiter = undefined;
560
+ } else {
561
+ const reader =
562
+ config.probe.signerSetReader ??
563
+ (config.rpcUrl === undefined
564
+ ? undefined
565
+ : createSdkOracleSignerSetReader({
566
+ escrowAddress: config.escrowAddress,
567
+ rpcUrl: config.rpcUrl,
568
+ chainId,
569
+ }));
570
+ if (reader === undefined) {
571
+ throw new Error(
572
+ "probe mode requires rpcUrl unless an explicit signerSetReader is supplied",
573
+ );
574
+ }
575
+ this.probeSigners = new CachedOracleSignerSet(
576
+ reader,
577
+ config.probe.signerCacheSeconds,
578
+ this.now,
579
+ );
580
+ this.probeRateLimiter =
581
+ config.probe.rateLimiter ??
582
+ new FixedWindowProbeRateLimiter(
583
+ config.probe.maxProbesPerMinute,
584
+ this.now,
585
+ );
586
+ }
587
+ }
588
+
589
+ /** Lower-cased header name that carries the buyer's invocation capability. */
590
+ get capabilityHeaderName(): string {
591
+ return this.headerName;
592
+ }
593
+
594
+ /** Lower-cased header name that carries an oracle probe capability. */
595
+ get probeCapabilityHeaderName(): string {
596
+ return this.probeHeaderName;
441
597
  }
442
598
 
443
599
  async authorize(
@@ -447,31 +603,27 @@ export class CallerAuthGateway {
447
603
  const hasCapabilityHeader =
448
604
  headerValue !== undefined && headerValue.length > 0;
449
605
 
450
- if (this.x402 !== undefined) {
451
- const paymentHeader = lookupHeader(request.headers, X402_PAYMENT_HEADER);
452
- const hasPaymentHeader =
453
- paymentHeader !== undefined && paymentHeader.trim().length > 0;
454
-
455
- // Exactly one payment mode per request. See `./x402-mode.ts`.
456
- if (hasCapabilityHeader && hasPaymentHeader) {
457
- return deny("ambiguous-payment-mode", 400);
458
- }
459
- if (!hasCapabilityHeader) {
460
- const evaluated = await evaluateX402Request(
461
- { method: request.method, path: request.path },
462
- paymentHeader,
463
- this.x402,
464
- );
465
- if (evaluated.outcome === "accepted") {
466
- return { authorized: true, x402Payment: evaluated.payment };
467
- }
468
- return {
469
- authorized: false,
470
- reason: "x402-payment-required",
471
- httpStatus: 402,
472
- x402PaymentRequired: evaluated.body,
473
- };
606
+ // ── Oracle probe path ────────────────────────────────────────────────
607
+ // Evaluated FIRST and returning unconditionally, so an authorized probe can
608
+ // never fall through into the stream branch. That ordering is the
609
+ // structural guarantee that a probe consumes no budget: no `stream` is ever
610
+ // produced on this path.
611
+ const probeHeaderValue = lookupHeader(
612
+ request.headers,
613
+ this.probeHeaderName,
614
+ );
615
+ if (probeHeaderValue !== undefined && probeHeaderValue.length > 0) {
616
+ const paymentHeader = lookupHeader(
617
+ request.headers,
618
+ PAYMENT_HEADER_REFUSED_ON_PROBES,
619
+ );
620
+ if (
621
+ hasCapabilityHeader ||
622
+ (paymentHeader !== undefined && paymentHeader.trim().length > 0)
623
+ ) {
624
+ return deny("ambiguous-probe-mode", 400);
474
625
  }
626
+ return this.authorizeProbe(probeHeaderValue, request);
475
627
  }
476
628
 
477
629
  if (!hasCapabilityHeader) {
@@ -572,6 +724,95 @@ export class CallerAuthGateway {
572
724
  return { authorized: true, stream: freshestView(views), capability };
573
725
  }
574
726
 
727
+ /**
728
+ * Authorize one oracle probe. Cheapest, most local gates first; the on-chain
729
+ * signer-set read is last so an unsigned or replayed flood cannot amplify
730
+ * into RPC load. Every failure mode is distinct and fail-closed.
731
+ */
732
+ private async authorizeProbe(
733
+ headerValue: string,
734
+ request: CallerAuthRequestInput,
735
+ ): Promise<CallerAuthDecision> {
736
+ const signerSet = this.probeSigners;
737
+ const rateLimiter = this.probeRateLimiter;
738
+ if (signerSet === undefined || rateLimiter === undefined) {
739
+ // Probe mode is off. Say so precisely: the oracle distinguishes
740
+ // "unverifiable here" from "the paid route failed".
741
+ return deny("probe-not-enabled", 403);
742
+ }
743
+
744
+ let capability: SignedProbeCapability;
745
+ try {
746
+ capability = decodeProbeCapabilityHeader(headerValue);
747
+ } catch (error) {
748
+ if (error instanceof InvalidProbeCapabilityHeaderError) {
749
+ return deny("malformed-probe-capability", 403);
750
+ }
751
+ throw error;
752
+ }
753
+
754
+ const nowSeconds = this.now();
755
+ if (nowSeconds >= capability.expiry) {
756
+ return deny("probe-capability-expired", 403);
757
+ }
758
+
759
+ let signer: Address;
760
+ try {
761
+ signer = await recoverProbeCapabilitySigner(
762
+ capability,
763
+ this.probeDomain,
764
+ capability.signature as Hex,
765
+ );
766
+ } catch {
767
+ return deny("probe-invalid-signature", 403);
768
+ }
769
+ if (signer.toLowerCase() !== capability.oracle.toLowerCase()) {
770
+ return deny("probe-invalid-signature", 403);
771
+ }
772
+
773
+ if (capability.method.toUpperCase() !== request.method.toUpperCase()) {
774
+ return deny("probe-method-mismatch", 403);
775
+ }
776
+ if (
777
+ hashProbePath(request.path).toLowerCase() !==
778
+ capability.pathHash.toLowerCase()
779
+ ) {
780
+ return deny("probe-path-mismatch", 403);
781
+ }
782
+ if (!this.serviceRefs.has(capability.serviceRef.toLowerCase())) {
783
+ return deny("probe-service-ref-mismatch", 403);
784
+ }
785
+
786
+ // Replay BEFORE the budget check: a captured capability replayed at volume
787
+ // must be rejected as a replay, not silently eat the honest probe budget.
788
+ // The SAME nonce cache as the buyer path, so a nonce can never be spent
789
+ // once as a probe and once as an invocation.
790
+ if (!this.nonceCache.consume(capability.nonce as Hex, capability.expiry)) {
791
+ return deny("probe-nonce-replayed", 403);
792
+ }
793
+
794
+ if (!rateLimiter.tryConsume()) {
795
+ return deny("probe-rate-limited", 429);
796
+ }
797
+
798
+ const signers = await signerSet.resolve();
799
+ if (signers === undefined) {
800
+ return deny("probe-signer-set-unavailable", 403);
801
+ }
802
+ if (!signers.has(signer.toLowerCase())) {
803
+ return deny("probe-signer-not-authorized", 403);
804
+ }
805
+
806
+ return {
807
+ authorized: true,
808
+ probe: {
809
+ oracle: signer,
810
+ serviceRef: capability.serviceRef as Hex,
811
+ expiry: capability.expiry,
812
+ },
813
+ };
814
+ }
815
+
575
816
  /** Returns the denial reason this single view produces, or `undefined` if it authorizes. */
576
817
  private evaluateView(
577
818
  stream: GatewayStreamView,
@@ -595,6 +836,17 @@ export class CallerAuthGateway {
595
836
  ) {
596
837
  return "service-ref-mismatch";
597
838
  }
839
+ // Operator-signed price band (metrik-contracts#41). Checked against the
840
+ // STREAM's serviceRef, which equals the capability's by the check above.
841
+ const bounds = this.rateBounds.get(stream.serviceRef.toLowerCase());
842
+ if (bounds !== undefined) {
843
+ if (stream.ratePerSecond === undefined) {
844
+ return "stream-rate-unknown";
845
+ }
846
+ if (rateOutsideBounds(stream.ratePerSecond, bounds) !== undefined) {
847
+ return "stream-rate-out-of-bounds";
848
+ }
849
+ }
598
850
  if (stream.status !== "active") {
599
851
  return "stream-not-active";
600
852
  }
@@ -640,7 +892,7 @@ function freshestView(views: readonly GatewayStreamView[]): GatewayStreamView {
640
892
 
641
893
  function deny(
642
894
  reason: CallerAuthDenialReason,
643
- httpStatus: 400 | 402 | 403,
895
+ httpStatus: 400 | 402 | 403 | 429,
644
896
  capability?: SignedInvocationCapability,
645
897
  ): CallerAuthDecision {
646
898
  return {