mppx 0.8.15 → 0.8.17

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 (464) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/Challenge.d.ts.map +1 -1
  3. package/dist/Challenge.js +40 -35
  4. package/dist/Challenge.js.map +1 -1
  5. package/dist/Constants.d.ts +17 -17
  6. package/dist/Constants.d.ts.map +1 -1
  7. package/dist/Credential.d.ts.map +1 -1
  8. package/dist/Errors.d.ts +3 -3
  9. package/dist/Errors.d.ts.map +1 -1
  10. package/dist/Errors.js.map +1 -1
  11. package/dist/Method.d.ts +35 -5
  12. package/dist/Method.d.ts.map +1 -1
  13. package/dist/Method.js +7 -22
  14. package/dist/Method.js.map +1 -1
  15. package/dist/Store.d.ts +19 -0
  16. package/dist/Store.d.ts.map +1 -1
  17. package/dist/Store.js +43 -0
  18. package/dist/Store.js.map +1 -1
  19. package/dist/attestation/Client.d.ts +17 -0
  20. package/dist/attestation/Client.d.ts.map +1 -0
  21. package/dist/attestation/Client.js +28 -0
  22. package/dist/attestation/Client.js.map +1 -0
  23. package/dist/attestation/Constants.d.ts +15 -0
  24. package/dist/attestation/Constants.d.ts.map +1 -0
  25. package/dist/attestation/Constants.js +15 -0
  26. package/dist/attestation/Constants.js.map +1 -0
  27. package/dist/attestation/Server.d.ts +4 -0
  28. package/dist/attestation/Server.d.ts.map +1 -0
  29. package/dist/attestation/Server.js +8 -0
  30. package/dist/attestation/Server.js.map +1 -0
  31. package/dist/attestation/Types.d.ts +76 -0
  32. package/dist/attestation/Types.d.ts.map +1 -0
  33. package/dist/attestation/Types.js +2 -0
  34. package/dist/attestation/Types.js.map +1 -0
  35. package/dist/attestation/index.d.ts +6 -0
  36. package/dist/attestation/index.d.ts.map +1 -0
  37. package/dist/attestation/index.js +6 -0
  38. package/dist/attestation/index.js.map +1 -0
  39. package/dist/attestation/internal/HttpMessageSignature.d.ts +73 -0
  40. package/dist/attestation/internal/HttpMessageSignature.d.ts.map +1 -0
  41. package/dist/attestation/internal/HttpMessageSignature.js +320 -0
  42. package/dist/attestation/internal/HttpMessageSignature.js.map +1 -0
  43. package/dist/attestation/internal/SigningContext.d.ts +4 -0
  44. package/dist/attestation/internal/SigningContext.d.ts.map +1 -0
  45. package/dist/attestation/internal/SigningContext.js +11 -0
  46. package/dist/attestation/internal/SigningContext.js.map +1 -0
  47. package/dist/cli/account.d.ts +14 -14
  48. package/dist/cli/account.d.ts.map +1 -1
  49. package/dist/cli/cli.d.ts +6 -6
  50. package/dist/cli/cli.d.ts.map +1 -1
  51. package/dist/cli/cli.js +1 -0
  52. package/dist/cli/cli.js.map +1 -1
  53. package/dist/cli/plugins/tempo.js.map +1 -1
  54. package/dist/cli/sessions/commands.d.ts +4 -4
  55. package/dist/cli/sessions/commands.d.ts.map +1 -1
  56. package/dist/cli/sessions/commands.js.map +1 -1
  57. package/dist/cli/sessions/store.d.ts.map +1 -1
  58. package/dist/cli/sessions/store.js.map +1 -1
  59. package/dist/cli/utils.d.ts +1 -1
  60. package/dist/cli/utils.d.ts.map +1 -1
  61. package/dist/cli/utils.js.map +1 -1
  62. package/dist/cli/validate/discovery.js.map +1 -1
  63. package/dist/cli/validate/index.d.ts +3 -3
  64. package/dist/cli/validate/index.d.ts.map +1 -1
  65. package/dist/client/Mppx.d.ts +3 -0
  66. package/dist/client/Mppx.d.ts.map +1 -1
  67. package/dist/client/Mppx.js +13 -5
  68. package/dist/client/Mppx.js.map +1 -1
  69. package/dist/client/Transport.d.ts +3 -5
  70. package/dist/client/Transport.d.ts.map +1 -1
  71. package/dist/client/Transport.js +1 -17
  72. package/dist/client/Transport.js.map +1 -1
  73. package/dist/client/internal/Fetch.d.ts.map +1 -1
  74. package/dist/client/internal/Fetch.js +2 -6
  75. package/dist/client/internal/Fetch.js.map +1 -1
  76. package/dist/client/node.js.map +1 -1
  77. package/dist/discovery/OpenApi.d.ts +3 -5
  78. package/dist/discovery/OpenApi.d.ts.map +1 -1
  79. package/dist/discovery/OpenApi.js +13 -34
  80. package/dist/discovery/OpenApi.js.map +1 -1
  81. package/dist/discovery/internal/Metadata.d.ts +20 -0
  82. package/dist/discovery/internal/Metadata.d.ts.map +1 -0
  83. package/dist/discovery/internal/Metadata.js +36 -0
  84. package/dist/discovery/internal/Metadata.js.map +1 -0
  85. package/dist/evm/Methods.d.ts +11 -11
  86. package/dist/evm/Methods.d.ts.map +1 -1
  87. package/dist/evm/Types.d.ts +17 -17
  88. package/dist/evm/Types.d.ts.map +1 -1
  89. package/dist/evm/client/Charge.d.ts +11 -11
  90. package/dist/evm/client/Methods.d.ts +11 -11
  91. package/dist/evm/server/Charge.d.ts +1 -1
  92. package/dist/evm/server/Charge.d.ts.map +1 -1
  93. package/dist/evm/server/Charge.js +2 -0
  94. package/dist/evm/server/Charge.js.map +1 -1
  95. package/dist/evm/server/Methods.d.ts +11 -11
  96. package/dist/internal/HeaderCodec.d.ts +2 -2
  97. package/dist/internal/HeaderCodec.d.ts.map +1 -1
  98. package/dist/internal/types.d.ts +6 -0
  99. package/dist/internal/types.d.ts.map +1 -1
  100. package/dist/middlewares/elysia.js.map +1 -1
  101. package/dist/middlewares/express.js.map +1 -1
  102. package/dist/middlewares/hono.js.map +1 -1
  103. package/dist/middlewares/nextjs.js.map +1 -1
  104. package/dist/proxy/Proxy.d.ts +2 -0
  105. package/dist/proxy/Proxy.d.ts.map +1 -1
  106. package/dist/proxy/Proxy.js +117 -9
  107. package/dist/proxy/Proxy.js.map +1 -1
  108. package/dist/proxy/Service.d.ts +36 -1
  109. package/dist/proxy/Service.d.ts.map +1 -1
  110. package/dist/proxy/Service.js +9 -8
  111. package/dist/proxy/Service.js.map +1 -1
  112. package/dist/proxy/services/anthropic.d.ts.map +1 -1
  113. package/dist/proxy/services/anthropic.js +1 -0
  114. package/dist/proxy/services/anthropic.js.map +1 -1
  115. package/dist/proxy/services/openai.d.ts.map +1 -1
  116. package/dist/proxy/services/openai.js +1 -0
  117. package/dist/proxy/services/openai.js.map +1 -1
  118. package/dist/proxy/services/stripe.d.ts.map +1 -1
  119. package/dist/proxy/services/stripe.js +1 -0
  120. package/dist/proxy/services/stripe.js.map +1 -1
  121. package/dist/server/Mppx.d.ts +75 -13
  122. package/dist/server/Mppx.d.ts.map +1 -1
  123. package/dist/server/Mppx.js +201 -23
  124. package/dist/server/Mppx.js.map +1 -1
  125. package/dist/server/internal/html/config.d.ts +9 -9
  126. package/dist/server/internal/html/config.d.ts.map +1 -1
  127. package/dist/server/internal/html/constants.d.ts +17 -17
  128. package/dist/server/internal/html/constants.d.ts.map +1 -1
  129. package/dist/stripe/Methods.d.ts +10 -10
  130. package/dist/stripe/Methods.d.ts.map +1 -1
  131. package/dist/stripe/client/Charge.d.ts +10 -10
  132. package/dist/stripe/client/Methods.d.ts +10 -10
  133. package/dist/stripe/internal/constants.d.ts +1 -1
  134. package/dist/stripe/internal/constants.js +1 -1
  135. package/dist/stripe/internal/types.d.ts +1 -0
  136. package/dist/stripe/internal/types.d.ts.map +1 -1
  137. package/dist/stripe/server/Charge.d.ts +11 -11
  138. package/dist/stripe/server/Charge.d.ts.map +1 -1
  139. package/dist/stripe/server/Charge.js +49 -1
  140. package/dist/stripe/server/Charge.js.map +1 -1
  141. package/dist/stripe/server/Methods.d.ts +137 -48
  142. package/dist/stripe/server/Methods.d.ts.map +1 -1
  143. package/dist/stripe/server/Methods.js +259 -4
  144. package/dist/stripe/server/Methods.js.map +1 -1
  145. package/dist/stripe/server/internal/deposit-address.d.ts +13 -0
  146. package/dist/stripe/server/internal/deposit-address.d.ts.map +1 -0
  147. package/dist/stripe/server/internal/deposit-address.js +28 -0
  148. package/dist/stripe/server/internal/deposit-address.js.map +1 -0
  149. package/dist/stripe/server/internal/html.gen.d.ts +1 -1
  150. package/dist/stripe/server/internal/html.gen.d.ts.map +1 -1
  151. package/dist/stripe/server/internal/html.gen.js +1 -1
  152. package/dist/stripe/server/internal/html.gen.js.map +1 -1
  153. package/dist/stripe/server/internal/record-payment.d.ts +15 -0
  154. package/dist/stripe/server/internal/record-payment.d.ts.map +1 -0
  155. package/dist/stripe/server/internal/record-payment.js +42 -0
  156. package/dist/stripe/server/internal/record-payment.js.map +1 -0
  157. package/dist/stripe/server/internal/request.d.ts +25 -0
  158. package/dist/stripe/server/internal/request.d.ts.map +1 -0
  159. package/dist/stripe/server/internal/request.js +29 -0
  160. package/dist/stripe/server/internal/request.js.map +1 -0
  161. package/dist/tap/Constants.d.ts +28 -0
  162. package/dist/tap/Constants.d.ts.map +1 -0
  163. package/dist/tap/Constants.js +32 -0
  164. package/dist/tap/Constants.js.map +1 -0
  165. package/dist/tap/Types.d.ts +11 -0
  166. package/dist/tap/Types.d.ts.map +1 -0
  167. package/dist/tap/Types.js +2 -0
  168. package/dist/tap/Types.js.map +1 -0
  169. package/dist/tap/client/index.d.ts +26 -0
  170. package/dist/tap/client/index.d.ts.map +1 -0
  171. package/dist/tap/client/index.js +33 -0
  172. package/dist/tap/client/index.js.map +1 -0
  173. package/dist/tap/index.d.ts +5 -0
  174. package/dist/tap/index.d.ts.map +1 -0
  175. package/dist/tap/index.js +5 -0
  176. package/dist/tap/index.js.map +1 -0
  177. package/dist/tap/server/index.d.ts +20 -0
  178. package/dist/tap/server/index.d.ts.map +1 -0
  179. package/dist/tap/server/index.js +36 -0
  180. package/dist/tap/server/index.js.map +1 -0
  181. package/dist/tempo/Attribution.d.ts +1 -1
  182. package/dist/tempo/Methods.d.ts +60 -60
  183. package/dist/tempo/Methods.d.ts.map +1 -1
  184. package/dist/tempo/Proof.d.ts +16 -16
  185. package/dist/tempo/client/Charge.d.ts +19 -19
  186. package/dist/tempo/client/Charge.d.ts.map +1 -1
  187. package/dist/tempo/client/Charge.js +1 -7
  188. package/dist/tempo/client/Charge.js.map +1 -1
  189. package/dist/tempo/client/Methods.d.ts +38 -38
  190. package/dist/tempo/client/Methods.js.map +1 -1
  191. package/dist/tempo/client/Subscription.d.ts +23 -23
  192. package/dist/tempo/client/Subscription.js.map +1 -1
  193. package/dist/tempo/internal/address.d.ts +2 -1
  194. package/dist/tempo/internal/address.d.ts.map +1 -1
  195. package/dist/tempo/internal/address.js +3 -1
  196. package/dist/tempo/internal/address.js.map +1 -1
  197. package/dist/tempo/internal/auto-swap.d.ts.map +1 -1
  198. package/dist/tempo/internal/auto-swap.js +4 -19
  199. package/dist/tempo/internal/auto-swap.js.map +1 -1
  200. package/dist/tempo/internal/defaults.d.ts +6 -6
  201. package/dist/tempo/internal/defaults.d.ts.map +1 -1
  202. package/dist/tempo/internal/fee-payer.d.ts +12 -12
  203. package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
  204. package/dist/tempo/internal/fee-payer.js.map +1 -1
  205. package/dist/tempo/internal/proof.d.ts +17 -17
  206. package/dist/tempo/internal/proof.d.ts.map +1 -1
  207. package/dist/tempo/legacy/client/Session.d.ts +20 -20
  208. package/dist/tempo/legacy/client/Session.js.map +1 -1
  209. package/dist/tempo/legacy/client/SessionManager.js.map +1 -1
  210. package/dist/tempo/legacy/index.d.ts +1 -3
  211. package/dist/tempo/legacy/index.d.ts.map +1 -1
  212. package/dist/tempo/legacy/index.js +1 -3
  213. package/dist/tempo/legacy/index.js.map +1 -1
  214. package/dist/tempo/legacy/session/escrow.abi.d.ts +374 -374
  215. package/dist/tempo/legacy/session/escrow.abi.d.ts.map +1 -1
  216. package/dist/tempo/server/Charge.d.ts +25 -11
  217. package/dist/tempo/server/Charge.d.ts.map +1 -1
  218. package/dist/tempo/server/Charge.js +44 -39
  219. package/dist/tempo/server/Charge.js.map +1 -1
  220. package/dist/tempo/server/Methods.d.ts +37 -52
  221. package/dist/tempo/server/Methods.d.ts.map +1 -1
  222. package/dist/tempo/server/Methods.js +0 -14
  223. package/dist/tempo/server/Methods.js.map +1 -1
  224. package/dist/tempo/server/Relay.d.ts +1 -1
  225. package/dist/tempo/server/Relay.d.ts.map +1 -1
  226. package/dist/tempo/server/Relay.js +2 -2
  227. package/dist/tempo/server/Relay.js.map +1 -1
  228. package/dist/tempo/server/Subscription.d.ts +25 -25
  229. package/dist/tempo/server/Subscription.d.ts.map +1 -1
  230. package/dist/tempo/server/Subscription.js +2 -0
  231. package/dist/tempo/server/Subscription.js.map +1 -1
  232. package/dist/tempo/server/index.d.ts +1 -1
  233. package/dist/tempo/server/index.d.ts.map +1 -1
  234. package/dist/tempo/server/index.js +1 -1
  235. package/dist/tempo/server/index.js.map +1 -1
  236. package/dist/tempo/server/internal/html.gen.d.ts +1 -1
  237. package/dist/tempo/server/internal/html.gen.d.ts.map +1 -1
  238. package/dist/tempo/server/internal/html.gen.js +1 -1
  239. package/dist/tempo/server/internal/html.gen.js.map +1 -1
  240. package/dist/tempo/server/internal/transport.d.ts +2 -0
  241. package/dist/tempo/server/internal/transport.d.ts.map +1 -1
  242. package/dist/tempo/server/internal/transport.js +9 -2
  243. package/dist/tempo/server/internal/transport.js.map +1 -1
  244. package/dist/tempo/session/client/ChannelOps.js.map +1 -1
  245. package/dist/tempo/session/client/CredentialState.d.ts +1 -1
  246. package/dist/tempo/session/client/CredentialState.js.map +1 -1
  247. package/dist/tempo/session/client/ReceiptCoordinator.js.map +1 -1
  248. package/dist/tempo/session/client/Runtime.js.map +1 -1
  249. package/dist/tempo/session/client/Session.d.ts +19 -19
  250. package/dist/tempo/session/client/Session.js.map +1 -1
  251. package/dist/tempo/session/client/SessionManager.js.map +1 -1
  252. package/dist/tempo/session/client/Transports.d.ts.map +1 -1
  253. package/dist/tempo/session/precompile/Chain.d.ts +27 -0
  254. package/dist/tempo/session/precompile/Chain.d.ts.map +1 -1
  255. package/dist/tempo/session/precompile/Chain.js +68 -7
  256. package/dist/tempo/session/precompile/Chain.js.map +1 -1
  257. package/dist/tempo/session/precompile/Protocol.js.map +1 -1
  258. package/dist/tempo/session/precompile/Voucher.d.ts +4 -4
  259. package/dist/tempo/session/precompile/Voucher.d.ts.map +1 -1
  260. package/dist/tempo/session/precompile/escrow.abi.d.ts +306 -306
  261. package/dist/tempo/session/precompile/escrow.abi.d.ts.map +1 -1
  262. package/dist/tempo/session/server/ChannelStore.d.ts +9 -0
  263. package/dist/tempo/session/server/ChannelStore.d.ts.map +1 -1
  264. package/dist/tempo/session/server/ChannelStore.js +16 -8
  265. package/dist/tempo/session/server/ChannelStore.js.map +1 -1
  266. package/dist/tempo/session/server/CredentialVerification.d.ts +30 -13
  267. package/dist/tempo/session/server/CredentialVerification.d.ts.map +1 -1
  268. package/dist/tempo/session/server/CredentialVerification.js +207 -13
  269. package/dist/tempo/session/server/CredentialVerification.js.map +1 -1
  270. package/dist/tempo/session/server/MeteredStream.d.ts +3 -0
  271. package/dist/tempo/session/server/MeteredStream.d.ts.map +1 -1
  272. package/dist/tempo/session/server/MeteredStream.js +3 -1
  273. package/dist/tempo/session/server/MeteredStream.js.map +1 -1
  274. package/dist/tempo/session/server/Session.d.ts +32 -21
  275. package/dist/tempo/session/server/Session.d.ts.map +1 -1
  276. package/dist/tempo/session/server/Session.js +116 -53
  277. package/dist/tempo/session/server/Session.js.map +1 -1
  278. package/dist/tempo/session/server/Sse.d.ts +3 -1
  279. package/dist/tempo/session/server/Sse.d.ts.map +1 -1
  280. package/dist/tempo/session/server/Sse.js +2 -1
  281. package/dist/tempo/session/server/Sse.js.map +1 -1
  282. package/dist/tempo/session/server/Transports.d.ts +1 -1
  283. package/dist/tempo/session/server/Transports.d.ts.map +1 -1
  284. package/dist/tempo/session/server/Transports.js +1 -0
  285. package/dist/tempo/session/server/Transports.js.map +1 -1
  286. package/dist/tempo/session/server/Ws.d.ts +6 -1
  287. package/dist/tempo/session/server/Ws.d.ts.map +1 -1
  288. package/dist/tempo/session/server/Ws.js +1 -0
  289. package/dist/tempo/session/server/Ws.js.map +1 -1
  290. package/dist/tempo/subscription/KeyAuthorization.d.ts +39 -39
  291. package/dist/tempo/subscription/KeyAuthorization.d.ts.map +1 -1
  292. package/dist/viem/Account.d.ts.map +1 -1
  293. package/dist/viem/Account.js.map +1 -1
  294. package/dist/web-bot-auth/Constants.d.ts +20 -0
  295. package/dist/web-bot-auth/Constants.d.ts.map +1 -0
  296. package/dist/web-bot-auth/Constants.js +24 -0
  297. package/dist/web-bot-auth/Constants.js.map +1 -0
  298. package/dist/web-bot-auth/Types.d.ts +10 -0
  299. package/dist/web-bot-auth/Types.d.ts.map +1 -0
  300. package/dist/web-bot-auth/Types.js +2 -0
  301. package/dist/web-bot-auth/Types.js.map +1 -0
  302. package/dist/web-bot-auth/client/index.d.ts +29 -0
  303. package/dist/web-bot-auth/client/index.d.ts.map +1 -0
  304. package/dist/web-bot-auth/client/index.js +64 -0
  305. package/dist/web-bot-auth/client/index.js.map +1 -0
  306. package/dist/web-bot-auth/index.d.ts +7 -0
  307. package/dist/web-bot-auth/index.d.ts.map +1 -0
  308. package/dist/web-bot-auth/index.js +7 -0
  309. package/dist/web-bot-auth/index.js.map +1 -0
  310. package/dist/web-bot-auth/internal/JwkThumbprint.d.ts +5 -0
  311. package/dist/web-bot-auth/internal/JwkThumbprint.d.ts.map +1 -0
  312. package/dist/web-bot-auth/internal/JwkThumbprint.js +20 -0
  313. package/dist/web-bot-auth/internal/JwkThumbprint.js.map +1 -0
  314. package/dist/web-bot-auth/internal/SignatureAgent.d.ts +3 -0
  315. package/dist/web-bot-auth/internal/SignatureAgent.d.ts.map +1 -0
  316. package/dist/web-bot-auth/internal/SignatureAgent.js +18 -0
  317. package/dist/web-bot-auth/internal/SignatureAgent.js.map +1 -0
  318. package/dist/web-bot-auth/server/index.d.ts +35 -0
  319. package/dist/web-bot-auth/server/index.d.ts.map +1 -0
  320. package/dist/web-bot-auth/server/index.js +88 -0
  321. package/dist/web-bot-auth/server/index.js.map +1 -0
  322. package/dist/x402/Assets.d.ts.map +1 -1
  323. package/dist/x402/Types.d.ts +6 -6
  324. package/dist/x402/Types.d.ts.map +1 -1
  325. package/dist/x402/server/EvmCharge.d.ts.map +1 -1
  326. package/dist/x402/server/EvmCharge.js +32 -20
  327. package/dist/x402/server/EvmCharge.js.map +1 -1
  328. package/package.json +19 -3
  329. package/src/Challenge.fuzz.test.ts +80 -47
  330. package/src/Challenge.test.ts +65 -0
  331. package/src/Challenge.ts +39 -35
  332. package/src/Method.ts +82 -68
  333. package/src/Store.test-d.ts +16 -0
  334. package/src/Store.test.ts +50 -0
  335. package/src/Store.ts +68 -0
  336. package/src/attestation/Attestation.integration.test.ts +208 -0
  337. package/src/attestation/Client.test.ts +83 -0
  338. package/src/attestation/Client.ts +34 -0
  339. package/src/attestation/Constants.ts +15 -0
  340. package/src/attestation/Server.test.ts +60 -0
  341. package/src/attestation/Server.ts +12 -0
  342. package/src/attestation/Types.test-d.ts +54 -0
  343. package/src/attestation/Types.ts +77 -0
  344. package/src/attestation/index.ts +5 -0
  345. package/src/attestation/internal/HttpMessageSignature.test.ts +101 -0
  346. package/src/attestation/internal/HttpMessageSignature.ts +429 -0
  347. package/src/attestation/internal/SigningContext.ts +13 -0
  348. package/src/bin.js +2 -0
  349. package/src/cli/cli.ts +1 -0
  350. package/src/client/Mppx.test-d.ts +17 -0
  351. package/src/client/Mppx.test.ts +14 -14
  352. package/src/client/Mppx.ts +25 -4
  353. package/src/client/Transport.test.ts +12 -45
  354. package/src/client/Transport.ts +3 -24
  355. package/src/client/internal/Fetch.ts +2 -6
  356. package/src/discovery/OpenApi.test.ts +170 -0
  357. package/src/discovery/OpenApi.ts +16 -48
  358. package/src/discovery/internal/Metadata.ts +51 -0
  359. package/src/evm/server/Charge.ts +6 -1
  360. package/src/internal/AcceptPayment.test.ts +12 -8
  361. package/src/internal/types.ts +9 -0
  362. package/src/mcp/client/McpClient.integration.test.ts +19 -32
  363. package/src/middlewares/elysia.test.ts +2 -12
  364. package/src/middlewares/express.test.ts +2 -12
  365. package/src/middlewares/hono.test.ts +6 -9
  366. package/src/middlewares/nextjs.test.ts +2 -12
  367. package/src/proxy/Proxy.test.ts +26 -19
  368. package/src/proxy/Proxy.ts +147 -9
  369. package/src/proxy/Proxy.upstreamError.test.ts +364 -0
  370. package/src/proxy/Service.test.ts +73 -3
  371. package/src/proxy/Service.ts +50 -23
  372. package/src/proxy/services/anthropic.ts +1 -0
  373. package/src/proxy/services/hooks.test-d.ts +14 -0
  374. package/src/proxy/services/hooks.test.ts +44 -0
  375. package/src/proxy/services/openai.ts +1 -0
  376. package/src/proxy/services/stripe.ts +1 -0
  377. package/src/server/Methods.test-d.ts +88 -0
  378. package/src/server/Methods.test.ts +69 -0
  379. package/src/server/Mppx.test-d.ts +141 -7
  380. package/src/server/Mppx.test.ts +1017 -119
  381. package/src/server/Mppx.ts +350 -54
  382. package/src/stripe/internal/constants.ts +1 -1
  383. package/src/stripe/internal/types.ts +1 -0
  384. package/src/stripe/server/Charge.test-d.ts +16 -1
  385. package/src/stripe/server/Charge.test.ts +79 -0
  386. package/src/stripe/server/Charge.ts +54 -1
  387. package/src/stripe/server/Methods.test-d.ts +157 -0
  388. package/src/stripe/server/Methods.test.ts +403 -0
  389. package/src/stripe/server/Methods.ts +423 -6
  390. package/src/stripe/server/internal/deposit-address.ts +57 -0
  391. package/src/stripe/server/internal/html/node_modules/.bin/mppx +3 -3
  392. package/src/stripe/server/internal/html/package.json +1 -1
  393. package/src/stripe/server/internal/html.gen.ts +1 -1
  394. package/src/stripe/server/internal/record-payment.ts +66 -0
  395. package/src/stripe/server/internal/request.ts +49 -0
  396. package/src/tap/Constants.ts +32 -0
  397. package/src/tap/Tap.test.ts +125 -0
  398. package/src/tap/Types.ts +11 -0
  399. package/src/tap/client/index.ts +54 -0
  400. package/src/tap/index.ts +4 -0
  401. package/src/tap/server/index.ts +48 -0
  402. package/src/tempo/PublicExports.test-d.ts +3 -3
  403. package/src/tempo/client/Charge.ts +1 -19
  404. package/src/tempo/internal/address.test.ts +42 -0
  405. package/src/tempo/internal/address.ts +3 -3
  406. package/src/tempo/internal/auto-swap.test.ts +4 -4
  407. package/src/tempo/internal/auto-swap.ts +7 -50
  408. package/src/tempo/legacy/README.md +5 -5
  409. package/src/tempo/legacy/index.ts +1 -3
  410. package/src/tempo/server/AtomicStore.test-d.ts +13 -0
  411. package/src/tempo/server/Charge.test.ts +19 -84
  412. package/src/tempo/server/Charge.ts +83 -55
  413. package/src/tempo/server/Methods.ts +0 -20
  414. package/src/tempo/server/Relay.test.ts +5 -5
  415. package/src/tempo/server/Relay.ts +2 -2
  416. package/src/tempo/server/Subscription.ts +4 -1
  417. package/src/tempo/server/index.ts +1 -1
  418. package/src/tempo/server/internal/html/node_modules/.bin/mppx +3 -3
  419. package/src/tempo/server/internal/html/package.json +1 -1
  420. package/src/tempo/server/internal/html.gen.ts +1 -1
  421. package/src/tempo/server/internal/transport.test.ts +22 -3
  422. package/src/tempo/server/internal/transport.ts +15 -3
  423. package/src/tempo/session/README.md +112 -0
  424. package/src/tempo/session/precompile/Chain.ts +131 -11
  425. package/src/tempo/session/server/ChannelStore.ts +33 -12
  426. package/src/tempo/session/server/CredentialVerification.test.ts +4 -4
  427. package/src/tempo/session/server/CredentialVerification.ts +340 -28
  428. package/src/tempo/session/server/MeteredStream.ts +5 -1
  429. package/src/tempo/session/server/Session.test.ts +428 -43
  430. package/src/tempo/session/server/Session.ts +159 -60
  431. package/src/tempo/session/server/Sse.test.ts +77 -0
  432. package/src/tempo/session/server/Sse.ts +8 -1
  433. package/src/tempo/session/server/Transports.ts +2 -1
  434. package/src/tempo/session/server/Ws.test.ts +171 -0
  435. package/src/tempo/session/server/Ws.ts +7 -1
  436. package/src/web-bot-auth/Constants.ts +24 -0
  437. package/src/web-bot-auth/Types.ts +9 -0
  438. package/src/web-bot-auth/WebBotAuth.test.ts +182 -0
  439. package/src/web-bot-auth/client/index.ts +84 -0
  440. package/src/web-bot-auth/index.ts +6 -0
  441. package/src/web-bot-auth/internal/JwkThumbprint.ts +21 -0
  442. package/src/web-bot-auth/internal/SignatureAgent.ts +18 -0
  443. package/src/web-bot-auth/server/index.ts +113 -0
  444. package/src/x402/Exact.e2e.test.ts +121 -81
  445. package/src/x402/Exact.localnet.test.ts +1 -1
  446. package/src/x402/server/EvmCharge.ts +35 -19
  447. package/dist/tempo/legacy/server/Session.d.ts +0 -208
  448. package/dist/tempo/legacy/server/Session.d.ts.map +0 -1
  449. package/dist/tempo/legacy/server/Session.js +0 -698
  450. package/dist/tempo/legacy/server/Session.js.map +0 -1
  451. package/dist/tempo/legacy/server/index.d.ts +0 -5
  452. package/dist/tempo/legacy/server/index.d.ts.map +0 -1
  453. package/dist/tempo/legacy/server/index.js +0 -5
  454. package/dist/tempo/legacy/server/index.js.map +0 -1
  455. package/dist/tempo/legacy/session/ChannelStore.d.ts +0 -22
  456. package/dist/tempo/legacy/session/ChannelStore.d.ts.map +0 -1
  457. package/dist/tempo/legacy/session/ChannelStore.js +0 -6
  458. package/dist/tempo/legacy/session/ChannelStore.js.map +0 -1
  459. package/src/tempo/legacy/server/Defaults.test-d.ts +0 -9
  460. package/src/tempo/legacy/server/Session.test.ts +0 -6370
  461. package/src/tempo/legacy/server/Session.ts +0 -1024
  462. package/src/tempo/legacy/server/index.ts +0 -4
  463. package/src/tempo/legacy/session/ChannelStore.test.ts +0 -58
  464. package/src/tempo/legacy/session/ChannelStore.ts +0 -39
@@ -31,7 +31,7 @@ import {
31
31
  serializeSnapshot as serializeSessionSnapshot,
32
32
  } from '../Snapshot.js'
33
33
  import * as ChannelStore from './ChannelStore.js'
34
- import { verifyCredentialPayload } from './CredentialVerification.js'
34
+ import { broadcastCredentialPayload, validateCredentialPayload } from './CredentialVerification.js'
35
35
  import { requireSessionCredentialPayload } from './CredentialVerification.js'
36
36
  import {
37
37
  type ResolveSessionChannelId,
@@ -42,13 +42,18 @@ import {
42
42
  type SessionPaymentRequestInput,
43
43
  } from './RequestState.js'
44
44
  import { respondToSessionCredential } from './RequestState.js'
45
- import { applyVerifiedHttpAccounting, chargeSessionChannel } from './Settlement.js'
46
- import { maybeSettleScheduled } from './Settlement.js'
45
+ import {
46
+ applyVerifiedHttpAccounting,
47
+ chargeSessionChannel,
48
+ type SettleChargedSessionChannel,
49
+ } from './Settlement.js'
50
+ import { isSettlementDue, maybeSettleScheduled } from './Settlement.js'
47
51
  import {
48
52
  resolveSettlementSchedule,
49
53
  type OnSessionSettlement,
50
54
  type SettlementSchedule,
51
55
  } from './Settlement.js'
56
+ import * as Ws from './Ws.js'
52
57
 
53
58
  /** Server-side automatic settlement schedule. */
54
59
  export type { SettlementSchedule } from './Settlement.js'
@@ -330,6 +335,26 @@ export function session<const parameters extends session.Parameters>(
330
335
  getClient: parameters.getClient,
331
336
  rpcUrl: defaults.rpcUrl,
332
337
  })
338
+ const settleScheduled: SettleChargedSessionChannel = async (channel) => {
339
+ if (!isSettlementDue(channel, settlementSchedule)) return undefined
340
+ return maybeSettleScheduled({
341
+ account,
342
+ channel,
343
+ client: await getClient({ chainId: channel.chainId }),
344
+ ...(feePayer ? { feePayer } : {}),
345
+ feePayerPolicy: parameters.feePayerPolicy,
346
+ feeToken: parameters.feeToken,
347
+ onSessionSettlement,
348
+ schedule: settlementSchedule,
349
+ store,
350
+ })
351
+ }
352
+ const serveWebSocket: session.Extensions['serveWebSocket'] = (options) =>
353
+ Ws.serve({
354
+ ...options,
355
+ onChargeCommitted: settleScheduled,
356
+ store,
357
+ })
333
358
  const bootstrapCharge = ChargeServer.charge({
334
359
  account,
335
360
  chainId: parameters.chainId,
@@ -341,16 +366,123 @@ export function session<const parameters extends session.Parameters>(
341
366
  store: rawStore,
342
367
  })
343
368
 
344
- type Transport = parameters['sse'] extends false | undefined ? undefined : Transport.Sse
369
+ type SessionTransport = parameters['sse'] extends false | undefined ? undefined : Transport.Sse
345
370
  const transport = parameters.sse
346
371
  ? Transport.sse({
372
+ settleCharged: settleScheduled,
347
373
  store,
348
374
  ...(typeof parameters.sse === 'object' ? parameters.sse : undefined),
349
375
  })
350
376
  : undefined
351
377
 
378
+ const validateCredential: Method.ValidateFn<typeof Methods.session> = async ({
379
+ credential,
380
+ request,
381
+ }) => {
382
+ const payload = requireSessionCredentialPayload(credential.payload)
383
+ const context = await resolveCredentialVerificationContext({
384
+ decimals,
385
+ feePayer: configuredFeePayer,
386
+ getClient,
387
+ minVoucherDelta: parameters.minVoucherDelta,
388
+ request,
389
+ })
390
+
391
+ const details = await validateCredentialPayload({
392
+ account,
393
+ challenge: credential.challenge,
394
+ channelStateTtl,
395
+ chainId: context.chainId,
396
+ client: context.client,
397
+ credentialSource: credential.source,
398
+ escrow: context.escrow,
399
+ expectedOperator: context.methodDetails.operator,
400
+ feePayer: context.feePayer,
401
+ feePayerPolicy: parameters.feePayerPolicy,
402
+ lastOnChainVerified,
403
+ minVoucherDelta: context.minVoucherDelta,
404
+ payload,
405
+ store,
406
+ })
407
+
408
+ return {
409
+ challenge: credential.challenge,
410
+ credential: { ...credential, payload },
411
+ details,
412
+ intent: 'session' as const,
413
+ method: 'tempo' as const,
414
+ request: context.request,
415
+ source: credential.source,
416
+ }
417
+ }
418
+
419
+ const broadcastCredential: Method.BroadcastFn<typeof Methods.session> = async ({
420
+ credential,
421
+ envelope,
422
+ request,
423
+ }) => {
424
+ const { challenge } = credential
425
+ const payload = requireSessionCredentialPayload(credential.payload)
426
+ const context = await resolveCredentialVerificationContext({
427
+ decimals,
428
+ feePayer: configuredFeePayer,
429
+ getClient,
430
+ minVoucherDelta: parameters.minVoucherDelta,
431
+ request,
432
+ })
433
+
434
+ const sessionReceipt = await broadcastCredentialPayload({
435
+ account,
436
+ challenge,
437
+ channelStateTtl,
438
+ chainId: context.chainId,
439
+ client: context.client,
440
+ credentialSource: credential.source,
441
+ escrow: context.escrow,
442
+ expectedOperator: context.methodDetails.operator,
443
+ feePayer: context.feePayer,
444
+ feePayerPolicy: parameters.feePayerPolicy,
445
+ feeToken: parameters.feeToken,
446
+ lastOnChainVerified,
447
+ minVoucherDelta: context.minVoucherDelta,
448
+ onSessionSettlement,
449
+ payload,
450
+ store,
451
+ })
452
+
453
+ return applyVerifiedHttpAccounting({
454
+ capturedRequest: envelope?.capturedRequest,
455
+ payloadAction: payload.action,
456
+ receipt: sessionReceipt,
457
+ getRequestAmount: () => BigInt(context.request.amount ?? challenge.request.amount),
458
+ sseEnabled: Boolean(parameters.sse),
459
+ markPrepaidReceipt: Transport.markPrepaidSessionTick,
460
+ charge: (channelId, requestAmount) =>
461
+ chargeSessionChannel({ store, channelId, amount: requestAmount }),
462
+ settleCharged: (channel) =>
463
+ maybeSettleScheduled({
464
+ account,
465
+ client: context.client,
466
+ ...(typeof context.feePayer === 'object' ? { feePayer: context.feePayer } : {}),
467
+ feePayerPolicy: parameters.feePayerPolicy,
468
+ feeToken: parameters.feeToken,
469
+ onSessionSettlement,
470
+ schedule: settlementSchedule,
471
+ store,
472
+ channel,
473
+ }),
474
+ })
475
+ }
476
+
352
477
  type Defaults = session.DeriveDefaults<parameters>
353
- return Method.toServer<typeof Methods.session, Defaults, Transport>(Methods.session, {
478
+ const method = Method.toServer<
479
+ typeof Methods.session,
480
+ Defaults,
481
+ SessionTransport,
482
+ session.Extensions
483
+ >(Methods.session, {
484
+ canOffer: parameters.canOffer,
485
+ onPaymentSuccess: parameters.onPaymentSuccess,
354
486
  defaults: deriveServerDefaults<parameters>({
355
487
  amount,
356
488
  currency,
@@ -361,6 +493,8 @@ export function session<const parameters extends session.Parameters>(
361
493
  unitType,
362
494
  }),
363
495
 
496
+ extensions: { serveWebSocket, settleScheduled },
497
+
364
498
  transport: deriveTransport<parameters>(transport),
365
499
 
366
500
  preflight: parameters.bootstrap
@@ -406,59 +540,8 @@ export function session<const parameters extends session.Parameters>(
406
540
  }
407
541
  },
408
542
 
409
- async verify({ credential, envelope, request }) {
410
- const { challenge } = credential
411
- const payload = requireSessionCredentialPayload(credential.payload)
412
- const context = await resolveCredentialVerificationContext({
413
- decimals,
414
- feePayer: configuredFeePayer,
415
- getClient,
416
- minVoucherDelta: parameters.minVoucherDelta,
417
- request,
418
- })
419
-
420
- const sessionReceipt = await verifyCredentialPayload({
421
- account,
422
- challenge,
423
- channelStateTtl,
424
- chainId: context.chainId,
425
- client: context.client,
426
- credentialSource: credential.source,
427
- escrow: context.escrow,
428
- expectedOperator: context.methodDetails.operator,
429
- feePayer: context.feePayer,
430
- feePayerPolicy: parameters.feePayerPolicy,
431
- feeToken: parameters.feeToken,
432
- lastOnChainVerified,
433
- minVoucherDelta: context.minVoucherDelta,
434
- onSessionSettlement,
435
- payload,
436
- store,
437
- })
438
-
439
- return applyVerifiedHttpAccounting({
440
- capturedRequest: envelope?.capturedRequest,
441
- payloadAction: payload.action,
442
- receipt: sessionReceipt,
443
- getRequestAmount: () => BigInt(context.request.amount ?? challenge.request.amount),
444
- sseEnabled: Boolean(parameters.sse),
445
- markPrepaidReceipt: Transport.markPrepaidSessionTick,
446
- charge: (channelId, requestAmount) =>
447
- chargeSessionChannel({ store, channelId, amount: requestAmount }),
448
- settleCharged: (channel) =>
449
- maybeSettleScheduled({
450
- account,
451
- client: context.client,
452
- ...(typeof context.feePayer === 'object' ? { feePayer: context.feePayer } : {}),
453
- feePayerPolicy: parameters.feePayerPolicy,
454
- feeToken: parameters.feeToken,
455
- onSessionSettlement,
456
- schedule: settlementSchedule,
457
- store,
458
- channel,
459
- }),
460
- })
461
- },
543
+ validate: validateCredential,
544
+ broadcast: broadcastCredential,
462
545
 
463
546
  // This hook acts as a gate: when it returns a Response, `withReceipt()`
464
547
  // in Mppx.ts short-circuits and returns that response directly without
@@ -478,12 +561,27 @@ export function session<const parameters extends session.Parameters>(
478
561
  })
479
562
  },
480
563
  })
564
+ return method
481
565
  }
482
566
 
483
567
  export namespace session {
484
568
  export const serializeSnapshot = serializeSessionSnapshot
485
569
  export const deserializeSnapshot = deserializeSessionSnapshot
486
570
 
571
+ /** Extensions attached to the Tempo session method handler. */
572
+ export type Extensions = {
573
+ /** Applies the configured automatic settlement policy to a committed channel charge. */
574
+ settleScheduled: SettleChargedSessionChannel
575
+ /** Serves a WebSocket route from this handler using its configured store and settlement policy. */
576
+ serveWebSocket: (options: ServeWebSocketOptions) => Promise<void>
577
+ }
578
+
579
+ /** WebSocket server options supplied after the session binds shared dependencies. */
580
+ export type ServeWebSocketOptions = Omit<
581
+ Ws.serve.Options,
582
+ 'onChargeCommitted' | 'settleScheduled' | 'store'
583
+ >
584
+
487
585
  /** Request defaults inferred from the Tempo session method schema. */
488
586
  export type Defaults = LooseOmit<
489
587
  Method.RequestDefaults<typeof Methods.session>,
@@ -526,7 +624,7 @@ export namespace session {
526
624
  store?: Store.AtomicStore | undefined
527
625
  /** Enable SSE streaming. Pass `true` for defaults or an options object to configure SSE. */
528
626
  sse?: boolean | Transport.sse.Options | undefined
529
- /** Tempo chain ID used for TIP-1034 channel escrow challenges. Defaults to the resolved client chain ID. Pass the Tempo testnet chain ID here instead of using legacy session's `testnet` boolean. */
627
+ /** Tempo chain ID used for TIP-1034 channel escrow challenges. Defaults to the resolved client chain ID. */
530
628
  chainId?: number | undefined
531
629
  /** TIP20EscrowChannel precompile address override. */
532
630
  escrowContract?: Address | undefined
@@ -539,7 +637,8 @@ export namespace session {
539
637
  feeToken?: Address | undefined
540
638
  } & Account.resolve.Parameters &
541
639
  Client.getResolver.Parameters &
542
- Defaults
640
+ Defaults &
641
+ Method.ComposableHooks<typeof Methods.session>
543
642
 
544
643
  /** Defaults derived from `session()` parameters for handler type inference. */
545
644
  export type DeriveDefaults<parameters extends Parameters> = types.DeriveDefaults<
@@ -260,6 +260,7 @@ describe('serve', () => {
260
260
 
261
261
  test('uses a prepaid unit for the first generated value', async () => {
262
262
  const storage = memoryStore()
263
+ const committed: Array<{ spent: bigint; units: number }> = []
263
264
  await seedChannel(storage, 3000000n)
264
265
  await storage.updateChannel(channelId, (current) =>
265
266
  current ? { ...current, spent: 1000000n, units: 1 } : current,
@@ -271,6 +272,9 @@ describe('serve', () => {
271
272
  challengeId,
272
273
  tickCost: 1000000n,
273
274
  generate: generate(['hello', 'world']),
275
+ onChargeCommitted(channel) {
276
+ committed.push({ spent: channel.spent, units: channel.units })
277
+ },
274
278
  prepaidUnits: 1,
275
279
  })
276
280
 
@@ -281,6 +285,79 @@ describe('serve', () => {
281
285
  const channel = await storage.getChannel(channelId)
282
286
  expect(channel!.spent).toBe(2000000n)
283
287
  expect(channel!.units).toBe(2)
288
+ expect(committed).toEqual([{ spent: 2000000n, units: 2 }])
289
+ })
290
+
291
+ test('runs the post-commit hook before emitting each charged value', async () => {
292
+ const storage = memoryStore()
293
+ const committed: Array<{ spent: bigint; units: number }> = []
294
+ await seedChannel(storage, 2000000n)
295
+
296
+ const output = await readStream(
297
+ serve({
298
+ store: storage,
299
+ channelId,
300
+ challengeId,
301
+ tickCost: 1000000n,
302
+ generate: generate(['first', 'second']),
303
+ onChargeCommitted(channel) {
304
+ committed.push({ spent: channel.spent, units: channel.units })
305
+ },
306
+ }),
307
+ )
308
+
309
+ expect(output).toContain('event: message\ndata: first\n\n')
310
+ expect(output).toContain('event: message\ndata: second\n\n')
311
+ expect(committed).toEqual([
312
+ { spent: 1000000n, units: 1 },
313
+ { spent: 2000000n, units: 2 },
314
+ ])
315
+ })
316
+
317
+ test('does not emit a charged value when the post-commit hook fails', async () => {
318
+ const storage = memoryStore()
319
+ await seedChannel(storage, 1000000n)
320
+
321
+ const reader = serve({
322
+ store: storage,
323
+ channelId,
324
+ challengeId,
325
+ tickCost: 1000000n,
326
+ generate: generate(['blocked']),
327
+ onChargeCommitted() {
328
+ throw new Error('settlement failed')
329
+ },
330
+ }).getReader()
331
+
332
+ await expect(reader.read()).rejects.toThrow('settlement failed')
333
+ const channel = await storage.getChannel(channelId)
334
+ expect(channel).toMatchObject({ spent: 1000000n, units: 1 })
335
+ })
336
+
337
+ test('does not run the post-commit hook for an unconsumed reservation', async () => {
338
+ const storage = memoryStore()
339
+ let commits = 0
340
+ await seedChannel(storage, 1000000n)
341
+
342
+ await readStream(
343
+ serve({
344
+ store: storage,
345
+ channelId,
346
+ challengeId,
347
+ tickCost: 1000000n,
348
+ generate: async function* (stream) {
349
+ await stream.charge()
350
+ yield* []
351
+ },
352
+ onChargeCommitted() {
353
+ commits++
354
+ },
355
+ }),
356
+ )
357
+
358
+ expect(commits).toBe(0)
359
+ const channel = await storage.getChannel(channelId)
360
+ expect(channel).toMatchObject({ spent: 0n, units: 0 })
284
361
  })
285
362
 
286
363
  test('emits multiline message values as a single SSE message event', async () => {
@@ -12,7 +12,11 @@ import {
12
12
  requireSessionCredentialContext,
13
13
  } from '../precompile/Protocol.js'
14
14
  import * as ChannelStore from './ChannelStore.js'
15
- import { meterIterable, type SessionController } from './MeteredStream.js'
15
+ import {
16
+ meterIterable,
17
+ type MeteredStreamOptions,
18
+ type SessionController,
19
+ } from './MeteredStream.js'
16
20
 
17
21
  /**
18
22
  * SSE (Server-Sent Events) utilities for metered streaming payments.
@@ -81,6 +85,7 @@ export function serve(options: serve.Options): ReadableStream<Uint8Array> {
81
85
  channelId,
82
86
  tickCost,
83
87
  generate,
88
+ onChargeCommitted: options.onChargeCommitted,
84
89
  pollIntervalMs,
85
90
  prepaidUnits: options.prepaidUnits,
86
91
  signal,
@@ -121,6 +126,8 @@ export declare namespace serve {
121
126
  challengeId: string
122
127
  tickCost: bigint
123
128
  generate: AsyncIterable<string> | ((stream: SessionController) => AsyncIterable<string>)
129
+ /** Callback invoked after each nonzero stream charge is committed. */
130
+ onChargeCommitted?: MeteredStreamOptions['onChargeCommitted']
124
131
  pollIntervalMs?: number | undefined
125
132
  prepaidUnits?: number | undefined
126
133
  signal?: AbortSignal | undefined
@@ -86,7 +86,7 @@ export async function reserveChargeOrWait(options: ReserveChargeParameters): Pro
86
86
  /** Atomically commits previously reserved stream charges to channel spend and unit counters. */
87
87
  export async function commitReservedCharges(
88
88
  options: CommitReservedChargesParameters,
89
- ): Promise<void> {
89
+ ): Promise<ChannelStore.State | undefined> {
90
90
  const { amount, channelId, store, units } = options
91
91
  if (amount === 0n || units === 0) return
92
92
 
@@ -107,6 +107,7 @@ export async function commitReservedCharges(
107
107
  if (!channel) throw new Error('channel not found')
108
108
  throwIfChannelClosed(channel)
109
109
  if (!committed) throw new Error('reserved voucher coverage is no longer available')
110
+ return channel
110
111
  }
111
112
 
112
113
  /** Throws when a channel can no longer be used for streaming charges. */
@@ -124,6 +124,27 @@ function seedChannel(
124
124
  }))
125
125
  }
126
126
 
127
+ function acceptingRoute(acceptedCumulative: bigint): Ws.serve.Options['route'] {
128
+ return async () => ({
129
+ status: 200,
130
+ withReceipt(response = new Response(null, { status: 204 })) {
131
+ response.headers.set(
132
+ 'Payment-Receipt',
133
+ serializeSessionReceipt(
134
+ createSessionReceipt({
135
+ challengeId: challenge.id,
136
+ channelId,
137
+ acceptedCumulative,
138
+ spent: 0n,
139
+ units: 0,
140
+ }),
141
+ ),
142
+ )
143
+ return response
144
+ },
145
+ })
146
+ }
147
+
127
148
  describe('parseMessage', () => {
128
149
  test('rejects non-object data in payment-receipt', () => {
129
150
  expect(Ws.parseMessage('{"mpp":"payment-receipt","data":true}')).toBeNull()
@@ -348,6 +369,7 @@ describe('isows', () => {
348
369
  test('drops reserved charges when the stream ends without delivering a chunk', async () => {
349
370
  const socket = new MockSocket()
350
371
  const store = memoryChannelStore()
372
+ let commits = 0
351
373
  await seedChannel(store, 1n)
352
374
 
353
375
  await Ws.serve({
@@ -376,6 +398,9 @@ describe('isows', () => {
376
398
  await stream.charge()
377
399
  yield* []
378
400
  },
401
+ onChargeCommitted() {
402
+ commits++
403
+ },
379
404
  })
380
405
 
381
406
  socket.receive(
@@ -406,6 +431,7 @@ describe('isows', () => {
406
431
  const channel = await store.getChannel(channelId)
407
432
  expect(channel?.spent).toBe(0n)
408
433
  expect(channel?.units).toBe(0)
434
+ expect(commits).toBe(0)
409
435
  })
410
436
 
411
437
  test('aborts a blocked application generator before sending close-ready', async () => {
@@ -521,6 +547,151 @@ describe('isows', () => {
521
547
  expect(socket.sent.some((message) => message.includes('priced-response'))).toBe(true)
522
548
  })
523
549
 
550
+ test.each(['onChargeCommitted', 'settleScheduled'] as const)(
551
+ 'runs %s after each committed charge and before emitting its message',
552
+ async (hookName) => {
553
+ const socket = new MockSocket()
554
+ const store = memoryChannelStore()
555
+ const committed: Array<{ emitted: number; spent: bigint; units: number }> = []
556
+ await seedChannel(store, 2n)
557
+
558
+ const hook = async (channel: ChannelStore.State) => {
559
+ committed.push({
560
+ emitted: socket.sent.filter((message) => Ws.parseMessage(message)?.mpp === 'message')
561
+ .length,
562
+ spent: channel.spent,
563
+ units: channel.units,
564
+ })
565
+ return undefined
566
+ }
567
+
568
+ await Ws.serve({
569
+ socket,
570
+ store,
571
+ url: 'ws://example.test/stream',
572
+ route: acceptingRoute(2n),
573
+ generate: (async function* () {
574
+ yield 'first'
575
+ yield 'second'
576
+ })(),
577
+ ...(hookName === 'onChargeCommitted'
578
+ ? { onChargeCommitted: hook }
579
+ : { settleScheduled: hook }),
580
+ })
581
+
582
+ socket.receive(
583
+ Ws.formatAuthorizationMessage(
584
+ makeCredential({
585
+ action: 'open',
586
+ channelId,
587
+ cumulativeAmount: '2',
588
+ signature: `0x${'77'.repeat(65)}`,
589
+ transaction: '0x01',
590
+ type: 'transaction',
591
+ }),
592
+ ),
593
+ )
594
+
595
+ await sleep(10)
596
+
597
+ expect(committed).toEqual([
598
+ { emitted: 0, spent: 1n, units: 1 },
599
+ { emitted: 1, spent: 2n, units: 2 },
600
+ ])
601
+ expect(
602
+ socket.sent
603
+ .map((message) => Ws.parseMessage(message))
604
+ .filter((message) => message?.mpp === 'message')
605
+ .map((message) => (message?.mpp === 'message' ? message.data : undefined)),
606
+ ).toEqual(['first', 'second'])
607
+ },
608
+ )
609
+
610
+ test('prefers onChargeCommitted over the deprecated settlement callback', async () => {
611
+ const socket = new MockSocket()
612
+ const store = memoryChannelStore()
613
+ const callbacks: string[] = []
614
+ await seedChannel(store, 1n)
615
+
616
+ await Ws.serve({
617
+ socket,
618
+ store,
619
+ url: 'ws://example.test/stream',
620
+ route: acceptingRoute(1n),
621
+ generate: (async function* () {
622
+ yield 'message'
623
+ })(),
624
+ onChargeCommitted() {
625
+ callbacks.push('current')
626
+ },
627
+ async settleScheduled() {
628
+ callbacks.push('deprecated')
629
+ return undefined
630
+ },
631
+ })
632
+
633
+ socket.receive(
634
+ Ws.formatAuthorizationMessage(
635
+ makeCredential({
636
+ action: 'open',
637
+ channelId,
638
+ cumulativeAmount: '1',
639
+ signature: `0x${'77'.repeat(65)}`,
640
+ transaction: '0x01',
641
+ type: 'transaction',
642
+ }),
643
+ ),
644
+ )
645
+
646
+ await sleep(10)
647
+
648
+ expect(callbacks).toEqual(['current'])
649
+ })
650
+
651
+ test('closes without emitting a charged message when the post-commit hook fails', async () => {
652
+ const socket = new MockSocket()
653
+ const store = memoryChannelStore()
654
+ await seedChannel(store, 1n)
655
+
656
+ await Ws.serve({
657
+ socket,
658
+ store,
659
+ url: 'ws://example.test/stream',
660
+ route: acceptingRoute(1n),
661
+ generate: (async function* () {
662
+ yield 'blocked'
663
+ })(),
664
+ onChargeCommitted() {
665
+ throw new Error('settlement failed')
666
+ },
667
+ })
668
+
669
+ socket.receive(
670
+ Ws.formatAuthorizationMessage(
671
+ makeCredential({
672
+ action: 'open',
673
+ channelId,
674
+ cumulativeAmount: '1',
675
+ signature: `0x${'77'.repeat(65)}`,
676
+ transaction: '0x01',
677
+ type: 'transaction',
678
+ }),
679
+ ),
680
+ )
681
+
682
+ await sleep(10)
683
+
684
+ expect(socket.closed).toBe(true)
685
+ expect(socket.sent.some((message) => message.includes('settlement failed'))).toBe(true)
686
+ expect(
687
+ socket.sent.some((message) => {
688
+ const parsed = Ws.parseMessage(message)
689
+ return parsed?.mpp === 'message' && parsed.data === 'blocked'
690
+ }),
691
+ ).toBe(false)
692
+ expect(await store.getChannel(channelId)).toMatchObject({ spent: 1n, units: 1 })
693
+ })
694
+
524
695
  test('does not meter or emit application messages after close is requested on-chain', async () => {
525
696
  const socket = new MockSocket()
526
697
  const store = memoryChannelStore()
@@ -15,7 +15,8 @@ import {
15
15
  type SessionReceipt,
16
16
  } from '../precompile/Protocol.js'
17
17
  import * as ChannelStore from './ChannelStore.js'
18
- import type { SessionController } from './MeteredStream.js'
18
+ import type { MeteredStreamOptions, SessionController } from './MeteredStream.js'
19
+ import type { SettleChargedSessionChannel } from './Settlement.js'
19
20
  export type { SessionController } from './MeteredStream.js'
20
21
  export type { Socket } from './Transports.js'
21
22
  import { meterIterable } from './MeteredStream.js'
@@ -152,6 +153,7 @@ export async function serve(options: serve.Options): Promise<void> {
152
153
  channelId: context.channelId,
153
154
  tickCost: context.tickCost,
154
155
  generate,
156
+ onChargeCommitted: options.onChargeCommitted ?? options.settleScheduled,
155
157
  pollIntervalMs,
156
158
  signal: abortController.signal,
157
159
  emitNeedVoucher: (message) => send(socket, message),
@@ -332,6 +334,10 @@ export declare namespace serve {
332
334
  /** Payment route handler. Receives synthetic `POST` requests with only
333
335
  * the `Authorization` header — no cookies, bodies, or upgrade headers. */
334
336
  route: SessionRoute
337
+ /** Optional low-level hook invoked after each committed stream charge. */
338
+ onChargeCommitted?: MeteredStreamOptions['onChargeCommitted']
339
+ /** @deprecated Use `onChargeCommitted`. */
340
+ settleScheduled?: SettleChargedSessionChannel | undefined
335
341
  socket: Socket
336
342
  store: ChannelStore.ChannelStore | import('../../../Store.js').Store
337
343
  url: string | URL
@@ -0,0 +1,24 @@
1
+ import { Constants as HttpMessageSignature } from '../attestation/internal/HttpMessageSignature.js'
2
+
3
+ /** Web Bot Auth values for the supported HTTPS-directory signature profile. */
4
+ export const Constants = {
5
+ /** Stable identifier for Web Bot Auth signers and replay storage. */
6
+ protocol: 'web-bot-auth',
7
+ /** Web Bot Auth discovery type supported by this adapter. */
8
+ discoveryType: 'directory',
9
+ /** RFC 9421 signature label used when no label is configured. */
10
+ label: 'webbot',
11
+ /** Tag identifying a Web Bot Auth request signature. */
12
+ tag: 'web-bot-auth',
13
+ /** Structured HTTP header linking a bot signature to its HTTPS directory origin. */
14
+ signatureAgentHeader: 'Signature-Agent',
15
+ /** Default lifetime, in seconds, for a bot request signature. */
16
+ defaultSignatureLifetime: 60,
17
+ /** Default verifier limit, following the draft's recommended 24-hour maximum. */
18
+ defaultMaximumSignatureLifetime: 24 * 60 * 60,
19
+ /** HTTP components required by this directory profile. */
20
+ requiredComponents: [
21
+ HttpMessageSignature.components.authority,
22
+ HttpMessageSignature.components.signatureAgent,
23
+ ],
24
+ } as const