mppx 0.8.17 → 0.8.18

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 (914) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +15 -0
  3. package/dist/Challenge.js +21 -4
  4. package/dist/bin.js +3 -3
  5. package/dist/cli/THIRD-PARTY-LICENSES.txt +328 -0
  6. package/dist/cli/cli.js +253 -1505
  7. package/dist/cli/plugins/index.js +19 -5
  8. package/dist/cli/plugins/tempo.js +7 -3
  9. package/dist/cli/sessions/Manager.js +7 -4
  10. package/dist/cli/sessions/request.d.ts +2 -0
  11. package/dist/cli/sessions/request.js +18 -0
  12. package/dist/cli/sessions/store.js +28 -14
  13. package/dist/discovery/Discovery.js +2 -1
  14. package/dist/evm/client/Charge.js +8 -0
  15. package/dist/server/core.d.ts +9 -0
  16. package/dist/server/core.js +9 -0
  17. package/dist/stripe/server/Charge.js +2 -4
  18. package/dist/stripe/server/Methods.d.ts +2 -2
  19. package/dist/stripe/server/Methods.js +17 -11
  20. package/dist/stripe/server/internal/html.gen.d.ts +1 -1
  21. package/dist/stripe/server/internal/html.gen.js +1 -1
  22. package/dist/stripe/server/spt.d.ts +8 -0
  23. package/dist/stripe/server/spt.js +8 -0
  24. package/dist/tempo/Methods.d.ts +13 -0
  25. package/dist/tempo/Methods.js +14 -3
  26. package/dist/tempo/client/Charge.d.ts +3 -0
  27. package/dist/tempo/client/Charge.js +31 -9
  28. package/dist/tempo/client/Methods.d.ts +13 -0
  29. package/dist/tempo/internal/defaults.d.ts +11 -0
  30. package/dist/tempo/internal/defaults.js +11 -0
  31. package/dist/tempo/internal/machine-token-charge.d.ts +51 -0
  32. package/dist/tempo/internal/machine-token-charge.js +113 -0
  33. package/dist/tempo/internal/machine-token-session.d.ts +88 -0
  34. package/dist/tempo/internal/machine-token-session.js +173 -0
  35. package/dist/tempo/internal/signature-envelope.d.ts +14 -0
  36. package/dist/tempo/internal/signature-envelope.js +28 -0
  37. package/dist/tempo/legacy/client/ChannelOps.d.ts +2 -2
  38. package/dist/tempo/legacy/client/ChannelOps.js +11 -5
  39. package/dist/tempo/legacy/client/Session.d.ts +13 -1
  40. package/dist/tempo/legacy/client/Session.js +3 -3
  41. package/dist/tempo/legacy/client/SessionManager.d.ts +3 -1
  42. package/dist/tempo/legacy/client/SessionManager.js +2 -0
  43. package/dist/tempo/server/Charge.d.ts +3 -0
  44. package/dist/tempo/server/Charge.js +58 -17
  45. package/dist/tempo/server/Methods.d.ts +21 -4
  46. package/dist/tempo/server/Methods.js +8 -4
  47. package/dist/tempo/server/internal/html.gen.d.ts +1 -1
  48. package/dist/tempo/server/internal/html.gen.js +1 -1
  49. package/dist/tempo/session/client/ChannelOps.d.ts +18 -3
  50. package/dist/tempo/session/client/ChannelOps.js +35 -6
  51. package/dist/tempo/session/client/ChannelStore.d.ts +0 -5
  52. package/dist/tempo/session/client/ChannelStore.js +2 -2
  53. package/dist/tempo/session/client/CredentialState.d.ts +17 -2
  54. package/dist/tempo/session/client/CredentialState.js +77 -76
  55. package/dist/tempo/session/client/Runtime.d.ts +4 -2
  56. package/dist/tempo/session/client/Runtime.js +21 -5
  57. package/dist/tempo/session/client/Session.d.ts +15 -3
  58. package/dist/tempo/session/client/Session.js +186 -63
  59. package/dist/tempo/session/client/SessionManager.d.ts +3 -1
  60. package/dist/tempo/session/client/SessionManager.js +35 -11
  61. package/dist/tempo/session/client/Transports.d.ts +2 -0
  62. package/dist/tempo/session/client/Transports.js +12 -2
  63. package/dist/tempo/session/precompile/Chain.d.ts +10 -2
  64. package/dist/tempo/session/precompile/Chain.js +50 -10
  65. package/dist/tempo/session/precompile/Protocol.d.ts +15 -0
  66. package/dist/tempo/session/precompile/Protocol.js +7 -0
  67. package/dist/tempo/session/precompile/Voucher.d.ts +3 -1
  68. package/dist/tempo/session/precompile/Voucher.js +6 -12
  69. package/dist/tempo/session/server/ChannelStore.d.ts +6 -0
  70. package/dist/tempo/session/server/ChannelStore.js +11 -4
  71. package/dist/tempo/session/server/CredentialVerification.d.ts +11 -9
  72. package/dist/tempo/session/server/CredentialVerification.js +185 -109
  73. package/dist/tempo/session/server/MeteredStream.d.ts +1 -1
  74. package/dist/tempo/session/server/MeteredStream.js +5 -4
  75. package/dist/tempo/session/server/RequestState.d.ts +19 -0
  76. package/dist/tempo/session/server/RequestState.js +61 -15
  77. package/dist/tempo/session/server/Session.d.ts +14 -2
  78. package/dist/tempo/session/server/Session.js +37 -6
  79. package/dist/tempo/session/server/Settlement.d.ts +11 -4
  80. package/dist/tempo/session/server/Settlement.js +53 -21
  81. package/dist/x402/client/Exact.d.ts +8 -0
  82. package/dist/x402/client/Exact.js +40 -10
  83. package/dist/x402/server/EvmCharge.d.ts +22 -0
  84. package/dist/x402/server/EvmCharge.js +23 -1
  85. package/package.json +15 -37
  86. package/dist/BodyDigest.d.ts.map +0 -1
  87. package/dist/BodyDigest.js.map +0 -1
  88. package/dist/Challenge.d.ts.map +0 -1
  89. package/dist/Challenge.js.map +0 -1
  90. package/dist/Constants.d.ts.map +0 -1
  91. package/dist/Constants.js.map +0 -1
  92. package/dist/Credential.d.ts.map +0 -1
  93. package/dist/Credential.js.map +0 -1
  94. package/dist/Errors.d.ts.map +0 -1
  95. package/dist/Errors.js.map +0 -1
  96. package/dist/Expires.d.ts.map +0 -1
  97. package/dist/Expires.js.map +0 -1
  98. package/dist/Html.d.ts.map +0 -1
  99. package/dist/Html.js.map +0 -1
  100. package/dist/Mcp.d.ts.map +0 -1
  101. package/dist/Mcp.js.map +0 -1
  102. package/dist/Method.d.ts.map +0 -1
  103. package/dist/Method.js.map +0 -1
  104. package/dist/PaymentRequest.d.ts.map +0 -1
  105. package/dist/PaymentRequest.js.map +0 -1
  106. package/dist/Receipt.d.ts.map +0 -1
  107. package/dist/Receipt.js.map +0 -1
  108. package/dist/Store.d.ts.map +0 -1
  109. package/dist/Store.js.map +0 -1
  110. package/dist/attestation/Client.d.ts.map +0 -1
  111. package/dist/attestation/Client.js.map +0 -1
  112. package/dist/attestation/Constants.d.ts.map +0 -1
  113. package/dist/attestation/Constants.js.map +0 -1
  114. package/dist/attestation/Server.d.ts.map +0 -1
  115. package/dist/attestation/Server.js.map +0 -1
  116. package/dist/attestation/Types.d.ts.map +0 -1
  117. package/dist/attestation/Types.js.map +0 -1
  118. package/dist/attestation/index.d.ts.map +0 -1
  119. package/dist/attestation/index.js.map +0 -1
  120. package/dist/attestation/internal/HttpMessageSignature.d.ts.map +0 -1
  121. package/dist/attestation/internal/HttpMessageSignature.js.map +0 -1
  122. package/dist/attestation/internal/SigningContext.d.ts.map +0 -1
  123. package/dist/attestation/internal/SigningContext.js.map +0 -1
  124. package/dist/bin.d.ts.map +0 -1
  125. package/dist/bin.js.map +0 -1
  126. package/dist/cli/account.d.ts.map +0 -1
  127. package/dist/cli/account.js.map +0 -1
  128. package/dist/cli/cli.d.ts.map +0 -1
  129. package/dist/cli/cli.js.map +0 -1
  130. package/dist/cli/config.d.ts.map +0 -1
  131. package/dist/cli/config.js.map +0 -1
  132. package/dist/cli/internal.d.ts.map +0 -1
  133. package/dist/cli/internal.js.map +0 -1
  134. package/dist/cli/plugins/evm.d.ts.map +0 -1
  135. package/dist/cli/plugins/evm.js.map +0 -1
  136. package/dist/cli/plugins/index.d.ts.map +0 -1
  137. package/dist/cli/plugins/index.js.map +0 -1
  138. package/dist/cli/plugins/plugin.d.ts.map +0 -1
  139. package/dist/cli/plugins/plugin.js.map +0 -1
  140. package/dist/cli/plugins/stripe.d.ts.map +0 -1
  141. package/dist/cli/plugins/stripe.js.map +0 -1
  142. package/dist/cli/plugins/tempo.d.ts.map +0 -1
  143. package/dist/cli/plugins/tempo.js.map +0 -1
  144. package/dist/cli/sessions/Manager.d.ts.map +0 -1
  145. package/dist/cli/sessions/Manager.js.map +0 -1
  146. package/dist/cli/sessions/commands.d.ts.map +0 -1
  147. package/dist/cli/sessions/commands.js.map +0 -1
  148. package/dist/cli/sessions/request.d.ts.map +0 -1
  149. package/dist/cli/sessions/request.js.map +0 -1
  150. package/dist/cli/sessions/store.d.ts.map +0 -1
  151. package/dist/cli/sessions/store.js.map +0 -1
  152. package/dist/cli/utils.d.ts.map +0 -1
  153. package/dist/cli/utils.js.map +0 -1
  154. package/dist/cli/validate/challenge.d.ts.map +0 -1
  155. package/dist/cli/validate/challenge.js.map +0 -1
  156. package/dist/cli/validate/discovery.d.ts.map +0 -1
  157. package/dist/cli/validate/discovery.js.map +0 -1
  158. package/dist/cli/validate/helpers.d.ts.map +0 -1
  159. package/dist/cli/validate/helpers.js.map +0 -1
  160. package/dist/cli/validate/index.d.ts.map +0 -1
  161. package/dist/cli/validate/index.js.map +0 -1
  162. package/dist/cli/validate/messages.d.ts.map +0 -1
  163. package/dist/cli/validate/messages.js.map +0 -1
  164. package/dist/cli/validate/payment.d.ts.map +0 -1
  165. package/dist/cli/validate/payment.js.map +0 -1
  166. package/dist/client/Methods.d.ts.map +0 -1
  167. package/dist/client/Methods.js.map +0 -1
  168. package/dist/client/Mppx.d.ts.map +0 -1
  169. package/dist/client/Mppx.js.map +0 -1
  170. package/dist/client/Transport.d.ts.map +0 -1
  171. package/dist/client/Transport.js.map +0 -1
  172. package/dist/client/index.d.ts.map +0 -1
  173. package/dist/client/index.js.map +0 -1
  174. package/dist/client/internal/Fetch.d.ts.map +0 -1
  175. package/dist/client/internal/Fetch.js.map +0 -1
  176. package/dist/client/internal/MethodChallenge.d.ts.map +0 -1
  177. package/dist/client/internal/MethodChallenge.js.map +0 -1
  178. package/dist/client/internal/MethodResponse.d.ts.map +0 -1
  179. package/dist/client/internal/MethodResponse.js.map +0 -1
  180. package/dist/client/internal/protocols/Mcp.d.ts.map +0 -1
  181. package/dist/client/internal/protocols/Mcp.js.map +0 -1
  182. package/dist/client/internal/protocols/Mpp.d.ts.map +0 -1
  183. package/dist/client/internal/protocols/Mpp.js.map +0 -1
  184. package/dist/client/internal/protocols/Protocol.d.ts.map +0 -1
  185. package/dist/client/internal/protocols/Protocol.js.map +0 -1
  186. package/dist/client/internal/protocols/Shared.d.ts.map +0 -1
  187. package/dist/client/internal/protocols/Shared.js.map +0 -1
  188. package/dist/client/internal/protocols/X402.d.ts.map +0 -1
  189. package/dist/client/internal/protocols/X402.js.map +0 -1
  190. package/dist/client/node.d.ts.map +0 -1
  191. package/dist/client/node.js.map +0 -1
  192. package/dist/discovery/Discovery.d.ts.map +0 -1
  193. package/dist/discovery/Discovery.js.map +0 -1
  194. package/dist/discovery/OpenApi.d.ts.map +0 -1
  195. package/dist/discovery/OpenApi.js.map +0 -1
  196. package/dist/discovery/Validate.d.ts.map +0 -1
  197. package/dist/discovery/Validate.js.map +0 -1
  198. package/dist/discovery/index.d.ts.map +0 -1
  199. package/dist/discovery/index.js.map +0 -1
  200. package/dist/discovery/internal/Metadata.d.ts.map +0 -1
  201. package/dist/discovery/internal/Metadata.js.map +0 -1
  202. package/dist/evm/Assets.d.ts.map +0 -1
  203. package/dist/evm/Assets.js.map +0 -1
  204. package/dist/evm/Chains.d.ts.map +0 -1
  205. package/dist/evm/Chains.js.map +0 -1
  206. package/dist/evm/Methods.d.ts.map +0 -1
  207. package/dist/evm/Methods.js.map +0 -1
  208. package/dist/evm/Types.d.ts.map +0 -1
  209. package/dist/evm/Types.js.map +0 -1
  210. package/dist/evm/client/Charge.d.ts.map +0 -1
  211. package/dist/evm/client/Charge.js.map +0 -1
  212. package/dist/evm/client/Methods.d.ts.map +0 -1
  213. package/dist/evm/client/Methods.js.map +0 -1
  214. package/dist/evm/client/index.d.ts.map +0 -1
  215. package/dist/evm/client/index.js.map +0 -1
  216. package/dist/evm/index.d.ts.map +0 -1
  217. package/dist/evm/index.js.map +0 -1
  218. package/dist/evm/server/Charge.d.ts.map +0 -1
  219. package/dist/evm/server/Charge.js.map +0 -1
  220. package/dist/evm/server/Methods.d.ts.map +0 -1
  221. package/dist/evm/server/Methods.js.map +0 -1
  222. package/dist/evm/server/index.d.ts.map +0 -1
  223. package/dist/evm/server/index.js.map +0 -1
  224. package/dist/index.d.ts.map +0 -1
  225. package/dist/index.js.map +0 -1
  226. package/dist/internal/AcceptPayment.d.ts.map +0 -1
  227. package/dist/internal/AcceptPayment.js.map +0 -1
  228. package/dist/internal/HeaderCodec.d.ts.map +0 -1
  229. package/dist/internal/HeaderCodec.js.map +0 -1
  230. package/dist/internal/constantTimeEqual.d.ts.map +0 -1
  231. package/dist/internal/constantTimeEqual.js.map +0 -1
  232. package/dist/internal/env.d.ts.map +0 -1
  233. package/dist/internal/env.js.map +0 -1
  234. package/dist/internal/types.d.ts.map +0 -1
  235. package/dist/internal/types.js.map +0 -1
  236. package/dist/mcp/client/McpClient.d.ts.map +0 -1
  237. package/dist/mcp/client/McpClient.js.map +0 -1
  238. package/dist/mcp/client/index.d.ts.map +0 -1
  239. package/dist/mcp/client/index.js.map +0 -1
  240. package/dist/mcp/server/Transport.d.ts.map +0 -1
  241. package/dist/mcp/server/Transport.js.map +0 -1
  242. package/dist/mcp/server/index.d.ts.map +0 -1
  243. package/dist/mcp/server/index.js.map +0 -1
  244. package/dist/middlewares/elysia.d.ts.map +0 -1
  245. package/dist/middlewares/elysia.js.map +0 -1
  246. package/dist/middlewares/express.d.ts.map +0 -1
  247. package/dist/middlewares/express.js.map +0 -1
  248. package/dist/middlewares/hono.d.ts.map +0 -1
  249. package/dist/middlewares/hono.js.map +0 -1
  250. package/dist/middlewares/internal/mppx.d.ts.map +0 -1
  251. package/dist/middlewares/internal/mppx.js.map +0 -1
  252. package/dist/middlewares/nextjs.d.ts.map +0 -1
  253. package/dist/middlewares/nextjs.js.map +0 -1
  254. package/dist/proxy/Proxy.d.ts.map +0 -1
  255. package/dist/proxy/Proxy.js.map +0 -1
  256. package/dist/proxy/Service.d.ts.map +0 -1
  257. package/dist/proxy/Service.js.map +0 -1
  258. package/dist/proxy/index.d.ts.map +0 -1
  259. package/dist/proxy/index.js.map +0 -1
  260. package/dist/proxy/internal/Headers.d.ts.map +0 -1
  261. package/dist/proxy/internal/Headers.js.map +0 -1
  262. package/dist/proxy/internal/Route.d.ts.map +0 -1
  263. package/dist/proxy/internal/Route.js.map +0 -1
  264. package/dist/proxy/services/anthropic.d.ts.map +0 -1
  265. package/dist/proxy/services/anthropic.js.map +0 -1
  266. package/dist/proxy/services/openai.d.ts.map +0 -1
  267. package/dist/proxy/services/openai.js.map +0 -1
  268. package/dist/proxy/services/stripe.d.ts.map +0 -1
  269. package/dist/proxy/services/stripe.js.map +0 -1
  270. package/dist/server/Methods.d.ts.map +0 -1
  271. package/dist/server/Methods.js.map +0 -1
  272. package/dist/server/Mppx.d.ts.map +0 -1
  273. package/dist/server/Mppx.js.map +0 -1
  274. package/dist/server/NodeListener.d.ts.map +0 -1
  275. package/dist/server/NodeListener.js.map +0 -1
  276. package/dist/server/Request.d.ts.map +0 -1
  277. package/dist/server/Request.js.map +0 -1
  278. package/dist/server/Response.d.ts.map +0 -1
  279. package/dist/server/Response.js.map +0 -1
  280. package/dist/server/Transport.d.ts.map +0 -1
  281. package/dist/server/Transport.js.map +0 -1
  282. package/dist/server/index.d.ts.map +0 -1
  283. package/dist/server/index.js.map +0 -1
  284. package/dist/server/internal/html/compose.main.gen.d.ts.map +0 -1
  285. package/dist/server/internal/html/compose.main.gen.js.map +0 -1
  286. package/dist/server/internal/html/config.d.ts.map +0 -1
  287. package/dist/server/internal/html/config.js.map +0 -1
  288. package/dist/server/internal/html/constants.d.ts.map +0 -1
  289. package/dist/server/internal/html/constants.js.map +0 -1
  290. package/dist/server/internal/html/serviceWorker.client.d.ts.map +0 -1
  291. package/dist/server/internal/html/serviceWorker.client.js.map +0 -1
  292. package/dist/server/internal/html/serviceWorker.gen.d.ts.map +0 -1
  293. package/dist/server/internal/html/serviceWorker.gen.js.map +0 -1
  294. package/dist/server/internal/scope.d.ts.map +0 -1
  295. package/dist/server/internal/scope.js.map +0 -1
  296. package/dist/stripe/Methods.d.ts.map +0 -1
  297. package/dist/stripe/Methods.js.map +0 -1
  298. package/dist/stripe/client/Charge.d.ts.map +0 -1
  299. package/dist/stripe/client/Charge.js.map +0 -1
  300. package/dist/stripe/client/Methods.d.ts.map +0 -1
  301. package/dist/stripe/client/Methods.js.map +0 -1
  302. package/dist/stripe/client/index.d.ts.map +0 -1
  303. package/dist/stripe/client/index.js.map +0 -1
  304. package/dist/stripe/index.d.ts.map +0 -1
  305. package/dist/stripe/index.js.map +0 -1
  306. package/dist/stripe/internal/constants.d.ts.map +0 -1
  307. package/dist/stripe/internal/constants.js.map +0 -1
  308. package/dist/stripe/internal/types.d.ts.map +0 -1
  309. package/dist/stripe/internal/types.js.map +0 -1
  310. package/dist/stripe/server/Charge.d.ts.map +0 -1
  311. package/dist/stripe/server/Charge.js.map +0 -1
  312. package/dist/stripe/server/Methods.d.ts.map +0 -1
  313. package/dist/stripe/server/Methods.js.map +0 -1
  314. package/dist/stripe/server/index.d.ts.map +0 -1
  315. package/dist/stripe/server/index.js.map +0 -1
  316. package/dist/stripe/server/internal/deposit-address.d.ts.map +0 -1
  317. package/dist/stripe/server/internal/deposit-address.js.map +0 -1
  318. package/dist/stripe/server/internal/html/types.d.ts.map +0 -1
  319. package/dist/stripe/server/internal/html/types.js.map +0 -1
  320. package/dist/stripe/server/internal/html.gen.d.ts.map +0 -1
  321. package/dist/stripe/server/internal/html.gen.js.map +0 -1
  322. package/dist/stripe/server/internal/record-payment.d.ts.map +0 -1
  323. package/dist/stripe/server/internal/record-payment.js.map +0 -1
  324. package/dist/stripe/server/internal/request.d.ts.map +0 -1
  325. package/dist/stripe/server/internal/request.js.map +0 -1
  326. package/dist/tap/Constants.d.ts.map +0 -1
  327. package/dist/tap/Constants.js.map +0 -1
  328. package/dist/tap/Types.d.ts.map +0 -1
  329. package/dist/tap/Types.js.map +0 -1
  330. package/dist/tap/client/index.d.ts.map +0 -1
  331. package/dist/tap/client/index.js.map +0 -1
  332. package/dist/tap/index.d.ts.map +0 -1
  333. package/dist/tap/index.js.map +0 -1
  334. package/dist/tap/server/index.d.ts.map +0 -1
  335. package/dist/tap/server/index.js.map +0 -1
  336. package/dist/tempo/Attribution.d.ts.map +0 -1
  337. package/dist/tempo/Attribution.js.map +0 -1
  338. package/dist/tempo/Methods.d.ts.map +0 -1
  339. package/dist/tempo/Methods.js.map +0 -1
  340. package/dist/tempo/Proof.d.ts.map +0 -1
  341. package/dist/tempo/Proof.js.map +0 -1
  342. package/dist/tempo/client/Charge.d.ts.map +0 -1
  343. package/dist/tempo/client/Charge.js.map +0 -1
  344. package/dist/tempo/client/Methods.d.ts.map +0 -1
  345. package/dist/tempo/client/Methods.js.map +0 -1
  346. package/dist/tempo/client/ResolveAccount.d.ts.map +0 -1
  347. package/dist/tempo/client/ResolveAccount.js.map +0 -1
  348. package/dist/tempo/client/Subscription.d.ts.map +0 -1
  349. package/dist/tempo/client/Subscription.js.map +0 -1
  350. package/dist/tempo/client/index.d.ts.map +0 -1
  351. package/dist/tempo/client/index.js.map +0 -1
  352. package/dist/tempo/index.d.ts.map +0 -1
  353. package/dist/tempo/index.js.map +0 -1
  354. package/dist/tempo/internal/account.d.ts.map +0 -1
  355. package/dist/tempo/internal/account.js.map +0 -1
  356. package/dist/tempo/internal/address.d.ts.map +0 -1
  357. package/dist/tempo/internal/address.js.map +0 -1
  358. package/dist/tempo/internal/auto-swap.d.ts.map +0 -1
  359. package/dist/tempo/internal/auto-swap.js.map +0 -1
  360. package/dist/tempo/internal/charge.d.ts.map +0 -1
  361. package/dist/tempo/internal/charge.js.map +0 -1
  362. package/dist/tempo/internal/defaults.d.ts.map +0 -1
  363. package/dist/tempo/internal/defaults.js.map +0 -1
  364. package/dist/tempo/internal/fee-payer.d.ts.map +0 -1
  365. package/dist/tempo/internal/fee-payer.js.map +0 -1
  366. package/dist/tempo/internal/fee-token.d.ts.map +0 -1
  367. package/dist/tempo/internal/fee-token.js.map +0 -1
  368. package/dist/tempo/internal/proof.d.ts.map +0 -1
  369. package/dist/tempo/internal/proof.js.map +0 -1
  370. package/dist/tempo/internal/selectors.d.ts.map +0 -1
  371. package/dist/tempo/internal/selectors.js.map +0 -1
  372. package/dist/tempo/internal/types.d.ts.map +0 -1
  373. package/dist/tempo/internal/types.js.map +0 -1
  374. package/dist/tempo/legacy/client/ChannelOps.d.ts.map +0 -1
  375. package/dist/tempo/legacy/client/ChannelOps.js.map +0 -1
  376. package/dist/tempo/legacy/client/Session.d.ts.map +0 -1
  377. package/dist/tempo/legacy/client/Session.js.map +0 -1
  378. package/dist/tempo/legacy/client/SessionManager.d.ts.map +0 -1
  379. package/dist/tempo/legacy/client/SessionManager.js.map +0 -1
  380. package/dist/tempo/legacy/client/index.d.ts.map +0 -1
  381. package/dist/tempo/legacy/client/index.js.map +0 -1
  382. package/dist/tempo/legacy/index.d.ts.map +0 -1
  383. package/dist/tempo/legacy/index.js.map +0 -1
  384. package/dist/tempo/legacy/session/Chain.d.ts.map +0 -1
  385. package/dist/tempo/legacy/session/Chain.js.map +0 -1
  386. package/dist/tempo/legacy/session/Channel.d.ts.map +0 -1
  387. package/dist/tempo/legacy/session/Channel.js.map +0 -1
  388. package/dist/tempo/legacy/session/Types.d.ts.map +0 -1
  389. package/dist/tempo/legacy/session/Types.js.map +0 -1
  390. package/dist/tempo/legacy/session/Voucher.d.ts.map +0 -1
  391. package/dist/tempo/legacy/session/Voucher.js.map +0 -1
  392. package/dist/tempo/legacy/session/escrow.abi.d.ts.map +0 -1
  393. package/dist/tempo/legacy/session/escrow.abi.js.map +0 -1
  394. package/dist/tempo/legacy/session/index.d.ts.map +0 -1
  395. package/dist/tempo/legacy/session/index.js.map +0 -1
  396. package/dist/tempo/server/Charge.d.ts.map +0 -1
  397. package/dist/tempo/server/Charge.js.map +0 -1
  398. package/dist/tempo/server/Methods.d.ts.map +0 -1
  399. package/dist/tempo/server/Methods.js.map +0 -1
  400. package/dist/tempo/server/Relay.d.ts.map +0 -1
  401. package/dist/tempo/server/Relay.js.map +0 -1
  402. package/dist/tempo/server/SponsorBudget.d.ts.map +0 -1
  403. package/dist/tempo/server/SponsorBudget.js.map +0 -1
  404. package/dist/tempo/server/Subscription.d.ts.map +0 -1
  405. package/dist/tempo/server/Subscription.js.map +0 -1
  406. package/dist/tempo/server/index.d.ts.map +0 -1
  407. package/dist/tempo/server/index.js.map +0 -1
  408. package/dist/tempo/server/internal/html.gen.d.ts.map +0 -1
  409. package/dist/tempo/server/internal/html.gen.js.map +0 -1
  410. package/dist/tempo/server/internal/request-body.d.ts.map +0 -1
  411. package/dist/tempo/server/internal/request-body.js.map +0 -1
  412. package/dist/tempo/server/internal/transport.d.ts.map +0 -1
  413. package/dist/tempo/server/internal/transport.js.map +0 -1
  414. package/dist/tempo/session/Snapshot.d.ts.map +0 -1
  415. package/dist/tempo/session/Snapshot.js.map +0 -1
  416. package/dist/tempo/session/client/ChannelOps.d.ts.map +0 -1
  417. package/dist/tempo/session/client/ChannelOps.js.map +0 -1
  418. package/dist/tempo/session/client/ChannelStore.d.ts.map +0 -1
  419. package/dist/tempo/session/client/ChannelStore.js.map +0 -1
  420. package/dist/tempo/session/client/CredentialState.d.ts.map +0 -1
  421. package/dist/tempo/session/client/CredentialState.js.map +0 -1
  422. package/dist/tempo/session/client/ReceiptCoordinator.d.ts.map +0 -1
  423. package/dist/tempo/session/client/ReceiptCoordinator.js.map +0 -1
  424. package/dist/tempo/session/client/Runtime.d.ts.map +0 -1
  425. package/dist/tempo/session/client/Runtime.js.map +0 -1
  426. package/dist/tempo/session/client/Session.d.ts.map +0 -1
  427. package/dist/tempo/session/client/Session.js.map +0 -1
  428. package/dist/tempo/session/client/SessionManager.d.ts.map +0 -1
  429. package/dist/tempo/session/client/SessionManager.js.map +0 -1
  430. package/dist/tempo/session/client/Transports.d.ts.map +0 -1
  431. package/dist/tempo/session/client/Transports.js.map +0 -1
  432. package/dist/tempo/session/client/index.d.ts.map +0 -1
  433. package/dist/tempo/session/client/index.js.map +0 -1
  434. package/dist/tempo/session/client/internal/SessionManager.d.ts.map +0 -1
  435. package/dist/tempo/session/client/internal/SessionManager.js.map +0 -1
  436. package/dist/tempo/session/index.d.ts.map +0 -1
  437. package/dist/tempo/session/index.js.map +0 -1
  438. package/dist/tempo/session/precompile/Chain.d.ts.map +0 -1
  439. package/dist/tempo/session/precompile/Chain.js.map +0 -1
  440. package/dist/tempo/session/precompile/Channel.d.ts.map +0 -1
  441. package/dist/tempo/session/precompile/Channel.js.map +0 -1
  442. package/dist/tempo/session/precompile/Protocol.d.ts.map +0 -1
  443. package/dist/tempo/session/precompile/Protocol.js.map +0 -1
  444. package/dist/tempo/session/precompile/Voucher.d.ts.map +0 -1
  445. package/dist/tempo/session/precompile/Voucher.js.map +0 -1
  446. package/dist/tempo/session/precompile/escrow.abi.d.ts.map +0 -1
  447. package/dist/tempo/session/precompile/escrow.abi.js.map +0 -1
  448. package/dist/tempo/session/precompile/index.d.ts.map +0 -1
  449. package/dist/tempo/session/precompile/index.js.map +0 -1
  450. package/dist/tempo/session/server/ChannelOps.d.ts.map +0 -1
  451. package/dist/tempo/session/server/ChannelOps.js.map +0 -1
  452. package/dist/tempo/session/server/ChannelStore.d.ts.map +0 -1
  453. package/dist/tempo/session/server/ChannelStore.js.map +0 -1
  454. package/dist/tempo/session/server/CredentialVerification.d.ts.map +0 -1
  455. package/dist/tempo/session/server/CredentialVerification.js.map +0 -1
  456. package/dist/tempo/session/server/MeteredStream.d.ts.map +0 -1
  457. package/dist/tempo/session/server/MeteredStream.js.map +0 -1
  458. package/dist/tempo/session/server/RequestState.d.ts.map +0 -1
  459. package/dist/tempo/session/server/RequestState.js.map +0 -1
  460. package/dist/tempo/session/server/Session.d.ts.map +0 -1
  461. package/dist/tempo/session/server/Session.js.map +0 -1
  462. package/dist/tempo/session/server/Settlement.d.ts.map +0 -1
  463. package/dist/tempo/session/server/Settlement.js.map +0 -1
  464. package/dist/tempo/session/server/Sse.d.ts.map +0 -1
  465. package/dist/tempo/session/server/Sse.js.map +0 -1
  466. package/dist/tempo/session/server/Transports.d.ts.map +0 -1
  467. package/dist/tempo/session/server/Transports.js.map +0 -1
  468. package/dist/tempo/session/server/Ws.d.ts.map +0 -1
  469. package/dist/tempo/session/server/Ws.js.map +0 -1
  470. package/dist/tempo/session/server/index.d.ts.map +0 -1
  471. package/dist/tempo/session/server/index.js.map +0 -1
  472. package/dist/tempo/subscription/KeyAuthorization.d.ts.map +0 -1
  473. package/dist/tempo/subscription/KeyAuthorization.js.map +0 -1
  474. package/dist/tempo/subscription/Receipt.d.ts.map +0 -1
  475. package/dist/tempo/subscription/Receipt.js.map +0 -1
  476. package/dist/tempo/subscription/Store.d.ts.map +0 -1
  477. package/dist/tempo/subscription/Store.js.map +0 -1
  478. package/dist/tempo/subscription/Types.d.ts.map +0 -1
  479. package/dist/tempo/subscription/Types.js.map +0 -1
  480. package/dist/tempo/subscription/index.d.ts.map +0 -1
  481. package/dist/tempo/subscription/index.js.map +0 -1
  482. package/dist/validation/core.d.ts.map +0 -1
  483. package/dist/validation/core.js.map +0 -1
  484. package/dist/validation/index.d.ts.map +0 -1
  485. package/dist/validation/index.js.map +0 -1
  486. package/dist/viem/Account.d.ts.map +0 -1
  487. package/dist/viem/Account.js.map +0 -1
  488. package/dist/viem/Client.d.ts.map +0 -1
  489. package/dist/viem/Client.js.map +0 -1
  490. package/dist/web-bot-auth/Constants.d.ts.map +0 -1
  491. package/dist/web-bot-auth/Constants.js.map +0 -1
  492. package/dist/web-bot-auth/Types.d.ts.map +0 -1
  493. package/dist/web-bot-auth/Types.js.map +0 -1
  494. package/dist/web-bot-auth/client/index.d.ts.map +0 -1
  495. package/dist/web-bot-auth/client/index.js.map +0 -1
  496. package/dist/web-bot-auth/index.d.ts.map +0 -1
  497. package/dist/web-bot-auth/index.js.map +0 -1
  498. package/dist/web-bot-auth/internal/JwkThumbprint.d.ts.map +0 -1
  499. package/dist/web-bot-auth/internal/JwkThumbprint.js.map +0 -1
  500. package/dist/web-bot-auth/internal/SignatureAgent.d.ts.map +0 -1
  501. package/dist/web-bot-auth/internal/SignatureAgent.js.map +0 -1
  502. package/dist/web-bot-auth/server/index.d.ts.map +0 -1
  503. package/dist/web-bot-auth/server/index.js.map +0 -1
  504. package/dist/x402/Assets.d.ts.map +0 -1
  505. package/dist/x402/Assets.js.map +0 -1
  506. package/dist/x402/Header.d.ts.map +0 -1
  507. package/dist/x402/Header.js.map +0 -1
  508. package/dist/x402/Types.d.ts.map +0 -1
  509. package/dist/x402/Types.js.map +0 -1
  510. package/dist/x402/client/Exact.d.ts.map +0 -1
  511. package/dist/x402/client/Exact.js.map +0 -1
  512. package/dist/x402/index.d.ts.map +0 -1
  513. package/dist/x402/index.js.map +0 -1
  514. package/dist/x402/internal/ChallengeBrand.d.ts.map +0 -1
  515. package/dist/x402/internal/ChallengeBrand.js.map +0 -1
  516. package/dist/x402/internal/RouteBinding.d.ts.map +0 -1
  517. package/dist/x402/internal/RouteBinding.js.map +0 -1
  518. package/dist/x402/server/EvmCharge.d.ts.map +0 -1
  519. package/dist/x402/server/EvmCharge.js.map +0 -1
  520. package/dist/x402/server/Facilitator.d.ts.map +0 -1
  521. package/dist/x402/server/Facilitator.js.map +0 -1
  522. package/dist/zod.d.ts.map +0 -1
  523. package/dist/zod.js.map +0 -1
  524. package/src/BodyDigest.test.ts +0 -43
  525. package/src/BodyDigest.ts +0 -55
  526. package/src/Challenge.fuzz.test.ts +0 -154
  527. package/src/Challenge.test-d.ts +0 -82
  528. package/src/Challenge.test.ts +0 -1060
  529. package/src/Challenge.ts +0 -687
  530. package/src/Constants.ts +0 -58
  531. package/src/Credential.fuzz.test.ts +0 -62
  532. package/src/Credential.test.ts +0 -378
  533. package/src/Credential.ts +0 -217
  534. package/src/Errors.test.ts +0 -520
  535. package/src/Errors.ts +0 -448
  536. package/src/Expires.test.ts +0 -112
  537. package/src/Expires.ts +0 -59
  538. package/src/Html.ts +0 -67
  539. package/src/Mcp.ts +0 -85
  540. package/src/Method.test.ts +0 -177
  541. package/src/Method.ts +0 -631
  542. package/src/PaymentRequest.test.ts +0 -147
  543. package/src/PaymentRequest.ts +0 -108
  544. package/src/Receipt.test.ts +0 -151
  545. package/src/Receipt.ts +0 -146
  546. package/src/Store.test-d.ts +0 -211
  547. package/src/Store.test.ts +0 -407
  548. package/src/Store.ts +0 -397
  549. package/src/attestation/Attestation.integration.test.ts +0 -208
  550. package/src/attestation/Client.test.ts +0 -83
  551. package/src/attestation/Client.ts +0 -34
  552. package/src/attestation/Constants.ts +0 -15
  553. package/src/attestation/Server.test.ts +0 -60
  554. package/src/attestation/Server.ts +0 -12
  555. package/src/attestation/Types.test-d.ts +0 -54
  556. package/src/attestation/Types.ts +0 -77
  557. package/src/attestation/index.ts +0 -5
  558. package/src/attestation/internal/HttpMessageSignature.test.ts +0 -101
  559. package/src/attestation/internal/HttpMessageSignature.ts +0 -429
  560. package/src/attestation/internal/SigningContext.ts +0 -13
  561. package/src/bin.js +0 -2
  562. package/src/bin.ts +0 -4
  563. package/src/cli/account.ts +0 -269
  564. package/src/cli/cli.test.ts +0 -2221
  565. package/src/cli/cli.ts +0 -1650
  566. package/src/cli/config.test.ts +0 -89
  567. package/src/cli/config.ts +0 -50
  568. package/src/cli/internal.ts +0 -114
  569. package/src/cli/mcp.test.ts +0 -262
  570. package/src/cli/plugins/evm.ts +0 -55
  571. package/src/cli/plugins/index.ts +0 -4
  572. package/src/cli/plugins/plugin.ts +0 -84
  573. package/src/cli/plugins/stripe.ts +0 -174
  574. package/src/cli/plugins/tempo.ts +0 -1102
  575. package/src/cli/sessions/Manager.test.ts +0 -249
  576. package/src/cli/sessions/Manager.ts +0 -93
  577. package/src/cli/sessions/commands.ts +0 -444
  578. package/src/cli/sessions/request.test.ts +0 -51
  579. package/src/cli/sessions/request.ts +0 -353
  580. package/src/cli/sessions/store.test.ts +0 -581
  581. package/src/cli/sessions/store.ts +0 -940
  582. package/src/cli/utils.test.ts +0 -156
  583. package/src/cli/utils.ts +0 -394
  584. package/src/cli/validate/challenge.ts +0 -565
  585. package/src/cli/validate/discovery.test.ts +0 -435
  586. package/src/cli/validate/discovery.ts +0 -221
  587. package/src/cli/validate/helpers.ts +0 -166
  588. package/src/cli/validate/index.ts +0 -229
  589. package/src/cli/validate/messages.ts +0 -7
  590. package/src/cli/validate/payment.ts +0 -774
  591. package/src/cli/validate.test.ts +0 -843
  592. package/src/client/Methods.ts +0 -8
  593. package/src/client/Mppx.test-d.ts +0 -287
  594. package/src/client/Mppx.test.ts +0 -1065
  595. package/src/client/Mppx.ts +0 -487
  596. package/src/client/Transport.test.ts +0 -586
  597. package/src/client/Transport.ts +0 -170
  598. package/src/client/index.ts +0 -29
  599. package/src/client/internal/Fetch.browser.test.ts +0 -197
  600. package/src/client/internal/Fetch.test-d.ts +0 -109
  601. package/src/client/internal/Fetch.test.ts +0 -2336
  602. package/src/client/internal/Fetch.ts +0 -1075
  603. package/src/client/internal/MethodChallenge.ts +0 -35
  604. package/src/client/internal/MethodResponse.ts +0 -67
  605. package/src/client/internal/protocols/Mcp.test.ts +0 -220
  606. package/src/client/internal/protocols/Mcp.ts +0 -186
  607. package/src/client/internal/protocols/Mpp.ts +0 -21
  608. package/src/client/internal/protocols/Protocol.ts +0 -10
  609. package/src/client/internal/protocols/Shared.ts +0 -25
  610. package/src/client/internal/protocols/X402.ts +0 -46
  611. package/src/client/node.test.ts +0 -115
  612. package/src/client/node.ts +0 -247
  613. package/src/discovery/Discovery.test.ts +0 -214
  614. package/src/discovery/Discovery.ts +0 -105
  615. package/src/discovery/OpenApi.test.ts +0 -623
  616. package/src/discovery/OpenApi.ts +0 -192
  617. package/src/discovery/Validate.test.ts +0 -305
  618. package/src/discovery/Validate.ts +0 -77
  619. package/src/discovery/index.ts +0 -3
  620. package/src/discovery/internal/Metadata.ts +0 -51
  621. package/src/env.d.ts +0 -12
  622. package/src/evm/Assets.ts +0 -1
  623. package/src/evm/Chains.ts +0 -11
  624. package/src/evm/Methods.ts +0 -44
  625. package/src/evm/PublicInterface.test-d.ts +0 -134
  626. package/src/evm/Types.ts +0 -140
  627. package/src/evm/client/Charge.test.ts +0 -347
  628. package/src/evm/client/Charge.ts +0 -187
  629. package/src/evm/client/Methods.ts +0 -19
  630. package/src/evm/client/index.ts +0 -6
  631. package/src/evm/index.ts +0 -16
  632. package/src/evm/server/Charge.test.ts +0 -339
  633. package/src/evm/server/Charge.ts +0 -295
  634. package/src/evm/server/Methods.ts +0 -22
  635. package/src/evm/server/index.ts +0 -6
  636. package/src/index.ts +0 -14
  637. package/src/internal/AcceptPayment.test.ts +0 -347
  638. package/src/internal/AcceptPayment.ts +0 -366
  639. package/src/internal/HeaderCodec.ts +0 -36
  640. package/src/internal/changeset.test.ts +0 -106
  641. package/src/internal/constantTimeEqual.test.ts +0 -47
  642. package/src/internal/constantTimeEqual.ts +0 -10
  643. package/src/internal/env.test.ts +0 -42
  644. package/src/internal/env.ts +0 -49
  645. package/src/internal/types.test-d.ts +0 -21
  646. package/src/internal/types.ts +0 -479
  647. package/src/mcp/client/McpClient.integration.test.ts +0 -639
  648. package/src/mcp/client/McpClient.test-d.ts +0 -144
  649. package/src/mcp/client/McpClient.test.ts +0 -463
  650. package/src/mcp/client/McpClient.ts +0 -307
  651. package/src/mcp/client/McpClient.unit.test.ts +0 -135
  652. package/src/mcp/client/index.ts +0 -2
  653. package/src/mcp/server/Transport.test.ts +0 -191
  654. package/src/mcp/server/Transport.ts +0 -111
  655. package/src/mcp/server/index.ts +0 -1
  656. package/src/middlewares/elysia.test.ts +0 -285
  657. package/src/middlewares/elysia.ts +0 -116
  658. package/src/middlewares/express.test.ts +0 -361
  659. package/src/middlewares/express.ts +0 -140
  660. package/src/middlewares/hono.test.ts +0 -473
  661. package/src/middlewares/hono.ts +0 -153
  662. package/src/middlewares/internal/mppx.test.ts +0 -177
  663. package/src/middlewares/internal/mppx.ts +0 -67
  664. package/src/middlewares/nextjs.test.ts +0 -359
  665. package/src/middlewares/nextjs.ts +0 -107
  666. package/src/proxy/Proxy.test.ts +0 -1038
  667. package/src/proxy/Proxy.ts +0 -483
  668. package/src/proxy/Proxy.upstreamError.test.ts +0 -364
  669. package/src/proxy/Service.test.ts +0 -252
  670. package/src/proxy/Service.ts +0 -280
  671. package/src/proxy/index.ts +0 -6
  672. package/src/proxy/internal/Headers.test.ts +0 -139
  673. package/src/proxy/internal/Headers.ts +0 -66
  674. package/src/proxy/internal/Route.test.ts +0 -217
  675. package/src/proxy/internal/Route.ts +0 -64
  676. package/src/proxy/services/anthropic.test.ts +0 -132
  677. package/src/proxy/services/anthropic.ts +0 -53
  678. package/src/proxy/services/hooks.test-d.ts +0 -14
  679. package/src/proxy/services/hooks.test.ts +0 -44
  680. package/src/proxy/services/openai.test.ts +0 -157
  681. package/src/proxy/services/openai.ts +0 -60
  682. package/src/proxy/services/stripe.test.ts +0 -175
  683. package/src/proxy/services/stripe.ts +0 -59
  684. package/src/server/Methods.test-d.ts +0 -88
  685. package/src/server/Methods.test.ts +0 -69
  686. package/src/server/Methods.ts +0 -3
  687. package/src/server/Mppx.authorize.test.ts +0 -210
  688. package/src/server/Mppx.test-d.ts +0 -494
  689. package/src/server/Mppx.test.ts +0 -6711
  690. package/src/server/Mppx.ts +0 -2919
  691. package/src/server/NodeListener.test.ts +0 -293
  692. package/src/server/NodeListener.ts +0 -45
  693. package/src/server/Request.test.ts +0 -255
  694. package/src/server/Request.ts +0 -155
  695. package/src/server/Response.test.ts +0 -32
  696. package/src/server/Response.ts +0 -45
  697. package/src/server/Transport.test.ts +0 -598
  698. package/src/server/Transport.ts +0 -320
  699. package/src/server/index.ts +0 -9
  700. package/src/server/internal/html/compose.main.gen.ts +0 -2
  701. package/src/server/internal/html/compose.main.ts +0 -88
  702. package/src/server/internal/html/config.ts +0 -672
  703. package/src/server/internal/html/constants.ts +0 -28
  704. package/src/server/internal/html/serviceWorker.client.ts +0 -28
  705. package/src/server/internal/html/serviceWorker.gen.ts +0 -2
  706. package/src/server/internal/html/serviceWorker.ts +0 -27
  707. package/src/server/internal/html/tsconfig.compose.json +0 -8
  708. package/src/server/internal/html/tsconfig.worker.client.json +0 -8
  709. package/src/server/internal/html/tsconfig.worker.json +0 -8
  710. package/src/server/internal/scope.ts +0 -43
  711. package/src/stripe/Charge.integration.test.ts +0 -329
  712. package/src/stripe/Methods.test.ts +0 -62
  713. package/src/stripe/Methods.ts +0 -44
  714. package/src/stripe/client/Charge.test.ts +0 -205
  715. package/src/stripe/client/Charge.ts +0 -132
  716. package/src/stripe/client/Methods.ts +0 -37
  717. package/src/stripe/client/index.ts +0 -2
  718. package/src/stripe/index.ts +0 -1
  719. package/src/stripe/internal/constants.ts +0 -7
  720. package/src/stripe/internal/types.ts +0 -47
  721. package/src/stripe/server/Charge.test-d.ts +0 -81
  722. package/src/stripe/server/Charge.test.ts +0 -700
  723. package/src/stripe/server/Charge.ts +0 -487
  724. package/src/stripe/server/Methods.test-d.ts +0 -157
  725. package/src/stripe/server/Methods.test.ts +0 -403
  726. package/src/stripe/server/Methods.ts +0 -441
  727. package/src/stripe/server/index.ts +0 -2
  728. package/src/stripe/server/internal/deposit-address.ts +0 -57
  729. package/src/stripe/server/internal/html/main.ts +0 -165
  730. package/src/stripe/server/internal/html/node_modules/.bin/mppx +0 -22
  731. package/src/stripe/server/internal/html/node_modules/.bin/mppx.src +0 -22
  732. package/src/stripe/server/internal/html/package.json +0 -9
  733. package/src/stripe/server/internal/html/stripe-js-pure.d.ts +0 -7
  734. package/src/stripe/server/internal/html/tsconfig.json +0 -8
  735. package/src/stripe/server/internal/html/types.ts +0 -5
  736. package/src/stripe/server/internal/html.gen.ts +0 -2
  737. package/src/stripe/server/internal/record-payment.ts +0 -66
  738. package/src/stripe/server/internal/request.ts +0 -49
  739. package/src/tap/Constants.ts +0 -32
  740. package/src/tap/Tap.test.ts +0 -125
  741. package/src/tap/Types.ts +0 -11
  742. package/src/tap/client/index.ts +0 -54
  743. package/src/tap/index.ts +0 -4
  744. package/src/tap/server/index.ts +0 -48
  745. package/src/tempo/AccessKeyAuthorization.test.ts +0 -141
  746. package/src/tempo/Attribution.test.ts +0 -294
  747. package/src/tempo/Attribution.ts +0 -185
  748. package/src/tempo/Methods.test.ts +0 -425
  749. package/src/tempo/Methods.ts +0 -367
  750. package/src/tempo/Proof.conformance.test.ts +0 -146
  751. package/src/tempo/Proof.test-d.ts +0 -32
  752. package/src/tempo/Proof.test.ts +0 -40
  753. package/src/tempo/Proof.ts +0 -69
  754. package/src/tempo/PublicExports.test-d.ts +0 -130
  755. package/src/tempo/Subscription.integration.test.ts +0 -591
  756. package/src/tempo/client/Charge.test.ts +0 -501
  757. package/src/tempo/client/Charge.ts +0 -271
  758. package/src/tempo/client/Methods.ts +0 -45
  759. package/src/tempo/client/ResolveAccount.ts +0 -46
  760. package/src/tempo/client/Subscription.test.ts +0 -180
  761. package/src/tempo/client/Subscription.ts +0 -156
  762. package/src/tempo/client/index.ts +0 -17
  763. package/src/tempo/index.ts +0 -5
  764. package/src/tempo/internal/account.ts +0 -56
  765. package/src/tempo/internal/address.test.ts +0 -42
  766. package/src/tempo/internal/address.ts +0 -6
  767. package/src/tempo/internal/auto-swap.test.ts +0 -198
  768. package/src/tempo/internal/auto-swap.ts +0 -145
  769. package/src/tempo/internal/charge.test.ts +0 -66
  770. package/src/tempo/internal/charge.ts +0 -43
  771. package/src/tempo/internal/defaults.test.ts +0 -95
  772. package/src/tempo/internal/defaults.ts +0 -53
  773. package/src/tempo/internal/fee-payer.test.ts +0 -1177
  774. package/src/tempo/internal/fee-payer.ts +0 -808
  775. package/src/tempo/internal/fee-token.test.ts +0 -165
  776. package/src/tempo/internal/fee-token.ts +0 -72
  777. package/src/tempo/internal/proof.test.ts +0 -97
  778. package/src/tempo/internal/proof.ts +0 -87
  779. package/src/tempo/internal/selectors.ts +0 -10
  780. package/src/tempo/internal/types.ts +0 -19
  781. package/src/tempo/legacy/AccessKeyAuthorization.test.ts +0 -162
  782. package/src/tempo/legacy/README.md +0 -9
  783. package/src/tempo/legacy/client/ChannelOps.test.ts +0 -379
  784. package/src/tempo/legacy/client/ChannelOps.ts +0 -271
  785. package/src/tempo/legacy/client/Session.test.ts +0 -800
  786. package/src/tempo/legacy/client/Session.ts +0 -397
  787. package/src/tempo/legacy/client/SessionManager.test.ts +0 -468
  788. package/src/tempo/legacy/client/SessionManager.ts +0 -909
  789. package/src/tempo/legacy/client/index.ts +0 -6
  790. package/src/tempo/legacy/index.ts +0 -4
  791. package/src/tempo/legacy/session/Chain.test.ts +0 -1349
  792. package/src/tempo/legacy/session/Chain.ts +0 -830
  793. package/src/tempo/legacy/session/Channel.test.ts +0 -109
  794. package/src/tempo/legacy/session/Channel.ts +0 -51
  795. package/src/tempo/legacy/session/Types.ts +0 -91
  796. package/src/tempo/legacy/session/Voucher.test.ts +0 -410
  797. package/src/tempo/legacy/session/Voucher.ts +0 -183
  798. package/src/tempo/legacy/session/escrow.abi.ts +0 -760
  799. package/src/tempo/legacy/session/index.ts +0 -8
  800. package/src/tempo/server/AtomicStore.test-d.ts +0 -63
  801. package/src/tempo/server/Charge.test.ts +0 -6056
  802. package/src/tempo/server/Charge.ts +0 -1379
  803. package/src/tempo/server/Methods.ts +0 -86
  804. package/src/tempo/server/Relay.test.ts +0 -677
  805. package/src/tempo/server/Relay.ts +0 -297
  806. package/src/tempo/server/SponsorBudget.test.ts +0 -154
  807. package/src/tempo/server/SponsorBudget.ts +0 -219
  808. package/src/tempo/server/Sse.test.ts +0 -321
  809. package/src/tempo/server/Subscription.test.ts +0 -1944
  810. package/src/tempo/server/Subscription.ts +0 -1336
  811. package/src/tempo/server/index.ts +0 -12
  812. package/src/tempo/server/internal/html/main.ts +0 -115
  813. package/src/tempo/server/internal/html/node_modules/.bin/mppx +0 -22
  814. package/src/tempo/server/internal/html/node_modules/.bin/mppx.src +0 -22
  815. package/src/tempo/server/internal/html/package.json +0 -10
  816. package/src/tempo/server/internal/html/tsconfig.json +0 -8
  817. package/src/tempo/server/internal/html.gen.ts +0 -2
  818. package/src/tempo/server/internal/request-body.test.ts +0 -210
  819. package/src/tempo/server/internal/request-body.ts +0 -61
  820. package/src/tempo/server/internal/transport.test.ts +0 -922
  821. package/src/tempo/server/internal/transport.ts +0 -322
  822. package/src/tempo/session/README.md +0 -320
  823. package/src/tempo/session/Snapshot.test.ts +0 -41
  824. package/src/tempo/session/Snapshot.ts +0 -95
  825. package/src/tempo/session/client/ChannelOps.test.ts +0 -218
  826. package/src/tempo/session/client/ChannelOps.ts +0 -348
  827. package/src/tempo/session/client/ChannelStore.ts +0 -111
  828. package/src/tempo/session/client/CredentialState.test.ts +0 -789
  829. package/src/tempo/session/client/CredentialState.ts +0 -942
  830. package/src/tempo/session/client/ReceiptCoordinator.ts +0 -95
  831. package/src/tempo/session/client/Runtime.test.ts +0 -1104
  832. package/src/tempo/session/client/Runtime.ts +0 -1008
  833. package/src/tempo/session/client/Session.test.ts +0 -1355
  834. package/src/tempo/session/client/Session.ts +0 -420
  835. package/src/tempo/session/client/SessionManager.test.ts +0 -1899
  836. package/src/tempo/session/client/SessionManager.ts +0 -996
  837. package/src/tempo/session/client/Transports.test.ts +0 -1141
  838. package/src/tempo/session/client/Transports.ts +0 -1534
  839. package/src/tempo/session/client/index.ts +0 -40
  840. package/src/tempo/session/client/internal/SessionManager.ts +0 -36
  841. package/src/tempo/session/index.ts +0 -7
  842. package/src/tempo/session/precompile/Chain.integration.test.ts +0 -339
  843. package/src/tempo/session/precompile/Chain.test.ts +0 -1641
  844. package/src/tempo/session/precompile/Chain.ts +0 -1269
  845. package/src/tempo/session/precompile/Channel.test.ts +0 -147
  846. package/src/tempo/session/precompile/Channel.ts +0 -108
  847. package/src/tempo/session/precompile/Protocol.test.ts +0 -358
  848. package/src/tempo/session/precompile/Protocol.ts +0 -520
  849. package/src/tempo/session/precompile/Voucher.test.ts +0 -354
  850. package/src/tempo/session/precompile/Voucher.ts +0 -162
  851. package/src/tempo/session/precompile/escrow.abi.ts +0 -226
  852. package/src/tempo/session/precompile/index.ts +0 -33
  853. package/src/tempo/session/server/ChannelOps.test.ts +0 -129
  854. package/src/tempo/session/server/ChannelOps.ts +0 -157
  855. package/src/tempo/session/server/ChannelStore.test.ts +0 -1093
  856. package/src/tempo/session/server/ChannelStore.ts +0 -856
  857. package/src/tempo/session/server/CredentialVerification.test.ts +0 -299
  858. package/src/tempo/session/server/CredentialVerification.ts +0 -1087
  859. package/src/tempo/session/server/MeteredStream.ts +0 -99
  860. package/src/tempo/session/server/RequestState.test.ts +0 -574
  861. package/src/tempo/session/server/RequestState.ts +0 -507
  862. package/src/tempo/session/server/Session.integration.test.ts +0 -449
  863. package/src/tempo/session/server/Session.test.ts +0 -4247
  864. package/src/tempo/session/server/Session.ts +0 -669
  865. package/src/tempo/session/server/Settlement.test.ts +0 -345
  866. package/src/tempo/session/server/Settlement.ts +0 -527
  867. package/src/tempo/session/server/Sse.fuzz.test.ts +0 -138
  868. package/src/tempo/session/server/Sse.test.ts +0 -634
  869. package/src/tempo/session/server/Sse.ts +0 -261
  870. package/src/tempo/session/server/Transports.test.ts +0 -346
  871. package/src/tempo/session/server/Transports.ts +0 -256
  872. package/src/tempo/session/server/Ws.test.ts +0 -765
  873. package/src/tempo/session/server/Ws.ts +0 -391
  874. package/src/tempo/session/server/index.ts +0 -12
  875. package/src/tempo/subscription/KeyAuthorization.test.ts +0 -282
  876. package/src/tempo/subscription/KeyAuthorization.ts +0 -396
  877. package/src/tempo/subscription/Receipt.ts +0 -28
  878. package/src/tempo/subscription/Store.test.ts +0 -609
  879. package/src/tempo/subscription/Store.ts +0 -449
  880. package/src/tempo/subscription/Types.ts +0 -68
  881. package/src/tempo/subscription/index.ts +0 -23
  882. package/src/tsconfig.json +0 -10
  883. package/src/validation/core.ts +0 -386
  884. package/src/validation/index.ts +0 -11
  885. package/src/viem/Account.test.ts +0 -72
  886. package/src/viem/Account.ts +0 -30
  887. package/src/viem/Client.test.ts +0 -366
  888. package/src/viem/Client.ts +0 -93
  889. package/src/web-bot-auth/Constants.ts +0 -24
  890. package/src/web-bot-auth/Types.ts +0 -9
  891. package/src/web-bot-auth/WebBotAuth.test.ts +0 -182
  892. package/src/web-bot-auth/client/index.ts +0 -84
  893. package/src/web-bot-auth/index.ts +0 -6
  894. package/src/web-bot-auth/internal/JwkThumbprint.ts +0 -21
  895. package/src/web-bot-auth/internal/SignatureAgent.ts +0 -18
  896. package/src/web-bot-auth/server/index.ts +0 -113
  897. package/src/x402/Assets.test.ts +0 -253
  898. package/src/x402/Assets.ts +0 -221
  899. package/src/x402/Exact.e2e.test.ts +0 -488
  900. package/src/x402/Exact.localnet.test.ts +0 -475
  901. package/src/x402/Header.test.ts +0 -73
  902. package/src/x402/Header.ts +0 -79
  903. package/src/x402/PublicInterface.test-d.ts +0 -39
  904. package/src/x402/Types.ts +0 -248
  905. package/src/x402/client/Exact.test.ts +0 -309
  906. package/src/x402/client/Exact.ts +0 -186
  907. package/src/x402/index.ts +0 -6
  908. package/src/x402/internal/ChallengeBrand.ts +0 -14
  909. package/src/x402/internal/RouteBinding.ts +0 -18
  910. package/src/x402/server/EvmCharge.ts +0 -410
  911. package/src/x402/server/Facilitator.test.ts +0 -111
  912. package/src/x402/server/Facilitator.ts +0 -56
  913. package/src/zod.test.ts +0 -169
  914. package/src/zod.ts +0 -71
@@ -1,1899 +0,0 @@
1
- import { createClient, custom, encodeFunctionResult, type Address, type Hex } from 'viem'
2
- import { privateKeyToAccount } from 'viem/accounts'
3
- import { describe, expect, test, vi } from 'vp/test'
4
-
5
- import * as Challenge from '../../../Challenge.js'
6
- import * as Constants from '../../../Constants.js'
7
- import * as Credential from '../../../Credential.js'
8
- import type { ChannelEntry } from '../client/ChannelOps.js'
9
- import { createJsonChannelStore, entryKey, type ChannelStore } from '../client/ChannelStore.js'
10
- import * as Channel from '../precompile/Channel.js'
11
- import { escrowAbi } from '../precompile/escrow.abi.js'
12
- import { tip20ChannelEscrow } from '../precompile/Protocol.js'
13
- import { createSessionReceipt, serializeSessionReceipt } from '../precompile/Protocol.js'
14
- import type { NeedVoucherEvent, SessionReceipt } from '../precompile/Protocol.js'
15
- import { formatNeedVoucherEvent, parseEvent } from '../precompile/Protocol.js'
16
- import type { SessionCredentialPayload } from '../precompile/Protocol.js'
17
- import * as Voucher from '../precompile/Voucher.js'
18
- import { computeFallbackCloseAmount, sessionManager } from './SessionManager.js'
19
-
20
- const channelId = '0x0000000000000000000000000000000000000000000000000000000000000001' as Hex
21
- const challengeId = 'test-challenge-1'
22
- const realm = 'test.example.com'
23
- const account = privateKeyToAccount(
24
- '0xac0974bec39a17e36ba6a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
25
- )
26
-
27
- const client = createClient({
28
- account,
29
- chain: { id: 4217 } as never,
30
- transport: custom({
31
- async request(args) {
32
- if (args.method === 'eth_chainId') return '0x1079'
33
- if (args.method === 'eth_getTransactionCount') return '0x0'
34
- if (args.method === 'eth_estimateGas') return '0x5208'
35
- if (args.method === 'eth_maxPriorityFeePerGas') return '0x1'
36
- if (args.method === 'eth_getBlockByNumber') return { baseFeePerGas: '0x1' }
37
- if (args.method === 'eth_call')
38
- return encodeFunctionResult({
39
- abi: escrowAbi,
40
- functionName: 'getChannelState',
41
- result: { settled: 0n, deposit: 10_000_000n, closeRequestedAt: 0 },
42
- })
43
- throw new Error(`unexpected rpc request: ${args.method}`)
44
- },
45
- }),
46
- })
47
-
48
- function channelStateClient(state: { closeRequestedAt: number; deposit: bigint; settled: bigint }) {
49
- return createClient({
50
- account,
51
- chain: { id: 4217 } as never,
52
- transport: custom({
53
- async request(args) {
54
- if (args.method === 'eth_call')
55
- return encodeFunctionResult({
56
- abi: escrowAbi,
57
- functionName: 'getChannelState',
58
- result: state,
59
- })
60
- throw new Error(`unexpected rpc request: ${args.method}`)
61
- },
62
- }),
63
- })
64
- }
65
-
66
- const storedDescriptor = {
67
- authorizedSigner: account.address,
68
- expiringNonceHash: `0x${'11'.repeat(32)}` as Hex,
69
- operator: '0x0000000000000000000000000000000000000000' as Address,
70
- payee: '0x742d35cc6634c0532925a3b844bc9e7595f8fe00' as Address,
71
- payer: account.address,
72
- salt: `0x${'22'.repeat(32)}` as Hex,
73
- token: '0x20c0000000000000000000000000000000000001' as Address,
74
- }
75
-
76
- const storedChannelId = Channel.computeId({
77
- ...storedDescriptor,
78
- chainId: 4217,
79
- escrow: tip20ChannelEscrow,
80
- })
81
-
82
- function channelEntry(overrides: Partial<ChannelEntry> = {}): ChannelEntry {
83
- return {
84
- channelId: storedChannelId,
85
- cumulativeAmount: 1_000_000n,
86
- deposit: 10_000_000n,
87
- descriptor: storedDescriptor,
88
- escrow: tip20ChannelEscrow,
89
- chainId: 4217,
90
- opened: true,
91
- ...overrides,
92
- }
93
- }
94
-
95
- /**
96
- * In-memory {@link ChannelStore} with spied `set`/`delete`, optionally seeded.
97
- * Seeded entries live in the entry index, so the plugin resumes them from
98
- * `store.get(resolved.key)` after a 402 (there is no first-request hint).
99
- */
100
- function makeChannelStore(seed: readonly ChannelEntry[] = []) {
101
- const map = new Map<string, ChannelEntry>(seed.map((entry) => [entryKey(entry), entry]))
102
- const set = vi.fn((entry: ChannelEntry) => {
103
- map.set(entryKey(entry), entry)
104
- })
105
- const remove = vi.fn((key: string) => {
106
- map.delete(key)
107
- })
108
- const store: ChannelStore = {
109
- get: (key) => map.get(key),
110
- set,
111
- delete: remove,
112
- }
113
- return { store, set, delete: remove, map }
114
- }
115
-
116
- function makeDurableChannelStore() {
117
- const backend = new Map<string, string>()
118
- const store = createJsonChannelStore({
119
- get: (key) => backend.get(key),
120
- set: (key, value) => {
121
- backend.set(key, value)
122
- },
123
- delete: (key) => {
124
- backend.delete(key)
125
- },
126
- })
127
- return { backend, store }
128
- }
129
-
130
- function makeChallenge(overrides: Record<string, unknown> = {}): Challenge.Challenge {
131
- return Challenge.from({
132
- id: challengeId,
133
- realm,
134
- method: 'tempo',
135
- intent: 'session',
136
- request: {
137
- amount: '1000000',
138
- currency: '0x20c0000000000000000000000000000000000001',
139
- recipient: '0x742d35cc6634c0532925a3b844bc9e7595f8fe00',
140
- decimals: 6,
141
- methodDetails: {
142
- escrowContract: tip20ChannelEscrow,
143
- chainId: 4217,
144
- sessionProtocol: Constants.SessionProtocols.v2,
145
- },
146
- ...overrides,
147
- },
148
- })
149
- }
150
-
151
- function makeChargeChallenge(overrides: Record<string, unknown> = {}): Challenge.Challenge {
152
- return Challenge.from({
153
- id: 'charge-bootstrap',
154
- realm,
155
- method: 'tempo',
156
- intent: 'charge',
157
- request: {
158
- amount: '0',
159
- currency: '0x20c0000000000000000000000000000000000001',
160
- recipient: '0x742d35cc6634c0532925a3b844bc9e7595f8fe00',
161
- methodDetails: { chainId: 4217 },
162
- ...overrides,
163
- },
164
- })
165
- }
166
-
167
- function make402Response(challenge?: Challenge.Challenge): Response {
168
- const c = challenge ?? makeChallenge()
169
- return new Response(null, {
170
- status: 402,
171
- headers: { 'WWW-Authenticate': Challenge.serialize(c) },
172
- })
173
- }
174
-
175
- function makeOkResponse(body?: string): Response {
176
- return new Response(body ?? 'ok', { status: 200 })
177
- }
178
-
179
- function makeSseResponse(events: string[]): Response {
180
- const body = events.join('')
181
- return new Response(body, {
182
- status: 200,
183
- headers: { 'Content-Type': 'text/event-stream' },
184
- })
185
- }
186
-
187
- describe('Session', () => {
188
- describe('computeFallbackCloseAmount', () => {
189
- test('uses matching close-ready receipt spend first', () => {
190
- const receipt = createSessionReceipt({
191
- acceptedCumulative: 100n,
192
- challengeId,
193
- channelId,
194
- spent: 80n,
195
- })
196
-
197
- expect(
198
- computeFallbackCloseAmount({
199
- challengeId,
200
- channelId,
201
- closeReadyReceipt: receipt,
202
- cumulativeAmount: 100n,
203
- deliveredChunks: 10n,
204
- socketChallengeId: challengeId,
205
- socketChannelId: channelId,
206
- spent: 50n,
207
- tickCost: 10n,
208
- }),
209
- ).toBe(80n)
210
- })
211
-
212
- test('uses matching socket delivery estimate clamped to cumulative authorization', () => {
213
- expect(
214
- computeFallbackCloseAmount({
215
- challengeId,
216
- channelId,
217
- cumulativeAmount: 90n,
218
- deliveredChunks: 10n,
219
- socketChallengeId: challengeId,
220
- socketChannelId: channelId,
221
- spent: 40n,
222
- tickCost: 10n,
223
- }),
224
- ).toBe(90n)
225
- })
226
-
227
- test('uses receipt-tracked spend when no socket estimate applies', () => {
228
- expect(
229
- computeFallbackCloseAmount({
230
- challengeId,
231
- channelId,
232
- cumulativeAmount: 100n,
233
- deliveredChunks: 10n,
234
- socketChallengeId: 'other-challenge',
235
- socketChannelId: channelId,
236
- spent: 40n,
237
- tickCost: 10n,
238
- }),
239
- ).toBe(40n)
240
- })
241
- })
242
-
243
- describe('parseEvent round-trip via SSE', () => {
244
- test('parses message events from SSE stream', () => {
245
- const raw = 'event: message\ndata: hello world\n\n'
246
- const event = parseEvent(raw)
247
- expect(event).toEqual({ type: 'message', data: 'hello world' })
248
- })
249
-
250
- test('parses payment-need-voucher events', () => {
251
- const params: NeedVoucherEvent = {
252
- channelId,
253
- requiredCumulative: '6000000',
254
- acceptedCumulative: '5000000',
255
- deposit: '10000000',
256
- }
257
- const raw = formatNeedVoucherEvent(params)
258
- const event = parseEvent(raw)
259
- expect(event).toEqual({ type: 'payment-need-voucher', data: params })
260
- })
261
- })
262
-
263
- describe('session creation', () => {
264
- test('creates session with initial state', () => {
265
- const s = sessionManager({
266
- account: '0x0000000000000000000000000000000000000001',
267
- maxDeposit: '10',
268
- })
269
-
270
- expect(s.channelId).toBeUndefined()
271
- expect(s.cumulative).toBe(0n)
272
- expect(s.opened).toBe(false)
273
- })
274
- })
275
-
276
- describe('.fetch()', () => {
277
- test('passes through non-402 responses', async () => {
278
- const mockFetch = vi.fn().mockResolvedValue(makeOkResponse('hello'))
279
-
280
- const s = sessionManager({
281
- account: '0x0000000000000000000000000000000000000001',
282
- fetch: mockFetch as typeof globalThis.fetch,
283
- })
284
-
285
- const res = await s.fetch('https://api.example.com/data')
286
- expect(res.status).toBe(200)
287
- expect(await res.text()).toBe('hello')
288
- expect(mockFetch).toHaveBeenCalledOnce()
289
- })
290
-
291
- test('rejects a concurrent request while one is in flight', async () => {
292
- let release!: () => void
293
- const gate = new Promise<void>((resolve) => {
294
- release = resolve
295
- })
296
- const mockFetch = vi.fn().mockImplementation(async () => {
297
- await gate
298
- return makeOkResponse('hello')
299
- })
300
-
301
- const s = sessionManager({
302
- account: '0x0000000000000000000000000000000000000001',
303
- fetch: mockFetch as typeof globalThis.fetch,
304
- })
305
-
306
- const first = s.fetch('https://api.example.com/data')
307
- await expect(s.fetch('https://api.example.com/data')).rejects.toThrow(
308
- 'concurrent requests on one manager are not supported',
309
- )
310
-
311
- release()
312
- expect((await first).status).toBe(200)
313
-
314
- // The guard clears after the in-flight request settles.
315
- expect((await s.fetch('https://api.example.com/data')).status).toBe(200)
316
- })
317
-
318
- test('binds the default global fetch for browser runtimes', async () => {
319
- const originalFetch = globalThis.fetch
320
- const mockFetch = vi.fn(function (this: unknown) {
321
- expect(this).toBe(globalThis)
322
- return Promise.resolve(makeOkResponse('hello'))
323
- })
324
- globalThis.fetch = mockFetch as typeof globalThis.fetch
325
- try {
326
- const s = sessionManager({
327
- account: '0x0000000000000000000000000000000000000001',
328
- })
329
-
330
- const res = await s.fetch('https://api.example.com/data')
331
-
332
- expect(res.status).toBe(200)
333
- expect(mockFetch).toHaveBeenCalledOnce()
334
- } finally {
335
- globalThis.fetch = originalFetch
336
- }
337
- })
338
-
339
- test('resumes a seeded channel after a 402 without a first-request hint', async () => {
340
- const posted: SessionCredentialPayload[] = []
341
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
342
- const authorization = new Headers(init?.headers).get(Constants.Headers.authorization)
343
- const payload = authorization
344
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
345
- : undefined
346
- if (payload) posted.push(payload)
347
- if (!payload) return Promise.resolve(make402Response())
348
- return Promise.resolve(makeOkResponse())
349
- })
350
- const s = sessionManager({
351
- account,
352
- client,
353
- fetch: mockFetch as typeof globalThis.fetch,
354
- channelStore: makeChannelStore([channelEntry()]).store,
355
- })
356
-
357
- await s.fetch('https://api.example.com/data')
358
-
359
- // No persisted hint: the first request carries no Payment-Session header,
360
- // and the channel is resumed from the entry index with a voucher.
361
- expect(new Headers(mockFetch.mock.calls[0]?.[1]?.headers).get('Payment-Session')).toBeNull()
362
- expect(posted[0]).toMatchObject({ action: 'voucher', channelId: storedChannelId })
363
- })
364
-
365
- test('seeds a same-route HEAD snapshot and resolves the account when resuming it', async () => {
366
- const { store, set } = makeChannelStore()
367
- const posted: SessionCredentialPayload[] = []
368
- const highestVoucher = {
369
- channelId: storedChannelId,
370
- cumulativeAmount: '1000000',
371
- signature: await Voucher.signVoucher(
372
- client,
373
- account,
374
- { channelId: storedChannelId, cumulativeAmount: 1_000_000n },
375
- tip20ChannelEscrow,
376
- 4217,
377
- ),
378
- }
379
- const resolveAccount = vi.fn(
380
- (info: Parameters<NonNullable<sessionManager.Parameters['resolveAccount']>>[0]) =>
381
- info.account,
382
- )
383
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
384
- const headers = new Headers(init?.headers)
385
- if (init?.method === 'HEAD' && !headers.get(Constants.Headers.authorization)) {
386
- expect(headers.get(Constants.Headers.acceptPayment)).toBe('tempo/charge')
387
- return Promise.resolve(make402Response(makeChargeChallenge()))
388
- }
389
- if (init?.method === 'HEAD') {
390
- const credential = Credential.deserialize(headers.get(Constants.Headers.authorization)!)
391
- expect(credential.payload).toMatchObject({ type: 'proof' })
392
- return Promise.resolve(
393
- new Response(null, {
394
- status: 204,
395
- headers: {
396
- [Constants.Headers.paymentSessionSnapshot]: sessionManager.serializeSnapshot({
397
- acceptedCumulative: '1000000',
398
- chainId: 4217,
399
- channelId: storedChannelId,
400
- deposit: '10000000',
401
- descriptor: storedDescriptor,
402
- escrow: tip20ChannelEscrow,
403
- highestVoucher,
404
- requiredCumulative: '1000000',
405
- settled: '0',
406
- spent: '0',
407
- units: 0,
408
- }),
409
- },
410
- }),
411
- )
412
- }
413
- // The seeded snapshot is not sent as a first-request hint; the content
414
- // request gets a 402 and resumes from the entry index with a voucher.
415
- const authorization = headers.get(Constants.Headers.authorization)
416
- const payload = authorization
417
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
418
- : undefined
419
- if (payload) posted.push(payload)
420
- if (!payload) {
421
- expect(s.channelId).toBe(storedChannelId)
422
- expect(s.cumulative).toBe(1_000_000n)
423
- return Promise.resolve(make402Response())
424
- }
425
- return Promise.resolve(makeOkResponse())
426
- })
427
- const s = sessionManager({
428
- account,
429
- bootstrap: true,
430
- client,
431
- fetch: mockFetch as typeof globalThis.fetch,
432
- channelStore: store,
433
- resolveAccount,
434
- })
435
-
436
- const response = await s.fetch('https://api.example.com/data')
437
-
438
- expect(response.status).toBe(200)
439
- expect(set).toHaveBeenCalledWith(expect.objectContaining({ channelId: storedChannelId }))
440
- expect(posted[0]).toMatchObject({ action: 'voucher', channelId: storedChannelId })
441
- expect(resolveAccount).toHaveBeenCalledTimes(2)
442
- expect(resolveAccount).toHaveBeenNthCalledWith(1, {
443
- account,
444
- chainId: 4217,
445
- operation: { authority: account.address, kind: 'authorizePaymentChannel' },
446
- })
447
- const contentCall = mockFetch.mock.calls.find((call) => call[1]?.method !== 'HEAD')
448
- expect(new Headers(contentCall?.[1]?.headers).get('Payment-Session')).toBeNull()
449
- })
450
-
451
- test('does not cache a server snapshot for a channel that is closed on-chain', async () => {
452
- const { store, set } = makeChannelStore()
453
- const highestVoucher = {
454
- channelId: storedChannelId,
455
- cumulativeAmount: '1000000',
456
- signature: await Voucher.signVoucher(
457
- client,
458
- account,
459
- { channelId: storedChannelId, cumulativeAmount: 1_000_000n },
460
- tip20ChannelEscrow,
461
- 4217,
462
- ),
463
- }
464
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
465
- const headers = new Headers(init?.headers)
466
- if (init?.method === 'HEAD' && !headers.get(Constants.Headers.authorization))
467
- return Promise.resolve(make402Response(makeChargeChallenge()))
468
- if (init?.method === 'HEAD')
469
- return Promise.resolve(
470
- new Response(null, {
471
- status: 204,
472
- headers: {
473
- [Constants.Headers.paymentSessionSnapshot]: sessionManager.serializeSnapshot({
474
- acceptedCumulative: '1000000',
475
- chainId: 4217,
476
- channelId: storedChannelId,
477
- deposit: '10000000',
478
- descriptor: storedDescriptor,
479
- escrow: tip20ChannelEscrow,
480
- highestVoucher,
481
- requiredCumulative: '1000000',
482
- settled: '0',
483
- spent: '0',
484
- units: 0,
485
- }),
486
- },
487
- }),
488
- )
489
- return Promise.resolve(makeOkResponse())
490
- })
491
- const s = sessionManager({
492
- account,
493
- bootstrap: true,
494
- client: channelStateClient({ closeRequestedAt: 0, deposit: 0n, settled: 0n }),
495
- fetch: mockFetch as typeof globalThis.fetch,
496
- channelStore: store,
497
- })
498
-
499
- expect((await s.fetch('https://api.example.com/data')).status).toBe(200)
500
- expect(set).not.toHaveBeenCalled()
501
- })
502
-
503
- test('does not cache a server snapshot with an invalid highest voucher signature', async () => {
504
- const { store, set } = makeChannelStore()
505
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
506
- const headers = new Headers(init?.headers)
507
- if (init?.method === 'HEAD' && !headers.get(Constants.Headers.authorization))
508
- return Promise.resolve(make402Response(makeChargeChallenge()))
509
- if (init?.method === 'HEAD')
510
- return Promise.resolve(
511
- new Response(null, {
512
- status: 204,
513
- headers: {
514
- [Constants.Headers.paymentSessionSnapshot]: sessionManager.serializeSnapshot({
515
- acceptedCumulative: '1000000',
516
- chainId: 4217,
517
- channelId: storedChannelId,
518
- deposit: '10000000',
519
- descriptor: storedDescriptor,
520
- escrow: tip20ChannelEscrow,
521
- highestVoucher: {
522
- channelId: storedChannelId,
523
- cumulativeAmount: '1000000',
524
- signature: `0x${'00'.repeat(64)}`,
525
- },
526
- requiredCumulative: '1000000',
527
- settled: '0',
528
- spent: '0',
529
- units: 0,
530
- }),
531
- },
532
- }),
533
- )
534
- return Promise.resolve(makeOkResponse())
535
- })
536
- const s = sessionManager({
537
- account,
538
- bootstrap: true,
539
- client,
540
- fetch: mockFetch as typeof globalThis.fetch,
541
- channelStore: store,
542
- })
543
-
544
- expect((await s.fetch('https://api.example.com/data')).status).toBe(200)
545
- expect(set).not.toHaveBeenCalled()
546
- })
547
-
548
- test('does not answer non-zero bootstrap charge challenges', async () => {
549
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
550
- const headers = new Headers(init?.headers)
551
- if (init?.method === 'HEAD' && !headers.get(Constants.Headers.authorization)) {
552
- return Promise.resolve(make402Response(makeChargeChallenge({ amount: '1' })))
553
- }
554
- if (init?.method === 'HEAD') throw new Error('unexpected bootstrap authorization')
555
- expect(headers.get(Constants.Headers.paymentSession)).toBeNull()
556
- return Promise.resolve(makeOkResponse())
557
- })
558
- const s = sessionManager({
559
- account,
560
- bootstrap: true,
561
- client,
562
- fetch: mockFetch as typeof globalThis.fetch,
563
- })
564
-
565
- const response = await s.fetch('https://api.example.com/data')
566
-
567
- expect(response.status).toBe(200)
568
- expect(mockFetch).toHaveBeenCalledTimes(2)
569
- })
570
-
571
- test('falls back to normal fetch when bootstrap is unsupported', async () => {
572
- const mockFetch = vi
573
- .fn()
574
- .mockResolvedValueOnce(new Response(null, { status: 404 }))
575
- .mockResolvedValueOnce(makeOkResponse())
576
- const s = sessionManager({
577
- account,
578
- bootstrap: true,
579
- client,
580
- fetch: mockFetch as typeof globalThis.fetch,
581
- })
582
-
583
- const response = await s.fetch('https://api.example.com/data')
584
-
585
- expect(response.status).toBe(200)
586
- expect(s.channelId).toBeUndefined()
587
- expect(mockFetch).toHaveBeenCalledTimes(2)
588
- expect(mockFetch.mock.calls[0]?.[1]).toMatchObject({ method: 'HEAD' })
589
- expect(new Headers(mockFetch.mock.calls[1]?.[1]?.headers).get('Payment-Session')).toBeNull()
590
- })
591
-
592
- test('drops a stale stored channel the server rejects and retries with a fresh one', async () => {
593
- const { store, delete: remove } = makeChannelStore([channelEntry()])
594
- const postedPayloads: SessionCredentialPayload[] = []
595
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
596
- const headers = new Headers(init?.headers)
597
- const authorization = headers.get(Constants.Headers.authorization)
598
- const payload = authorization
599
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
600
- : undefined
601
- if (payload) postedPayloads.push(payload)
602
-
603
- if (!payload) return Promise.resolve(make402Response())
604
- // Reject any reuse of the stale stored channel; accept a freshly opened one.
605
- if (payload.channelId === storedChannelId)
606
- return Promise.resolve(new Response('gone', { status: 500 }))
607
- return Promise.resolve(makeOkResponse())
608
- })
609
- const s = sessionManager({
610
- account,
611
- client,
612
- fetch: mockFetch as typeof globalThis.fetch,
613
- maxDeposit: '10',
614
- channelStore: store,
615
- })
616
-
617
- const response = await s.fetch('https://api.example.com/data')
618
-
619
- expect(response.status).toBe(200)
620
- expect(remove).toHaveBeenCalledOnce()
621
- expect(postedPayloads.map((payload) => payload.action)).toEqual(['voucher', 'open'])
622
- expect(s.opened).toBe(true)
623
- expect(s.channelId).not.toBe(storedChannelId)
624
- })
625
-
626
- test('keeps a persisted channel after its committed top-up when the paid retry fails', async () => {
627
- const seeded = channelEntry({ cumulativeAmount: 10_000_000n, deposit: 10_000_000n })
628
- const { store, delete: remove, map } = makeChannelStore([seeded])
629
- const postedPayloads: SessionCredentialPayload[] = []
630
- let probes = 0
631
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
632
- const authorization = new Headers(init?.headers).get(Constants.Headers.authorization)
633
- const payload = authorization
634
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
635
- : undefined
636
- if (!payload) {
637
- probes++
638
- if (probes > 1) throw new Error('unexpected fresh-channel retry')
639
- return Promise.resolve(make402Response())
640
- }
641
-
642
- postedPayloads.push(payload)
643
- if (payload.action === 'topUp') return Promise.resolve(new Response(null, { status: 204 }))
644
- if (payload.action === 'voucher')
645
- return Promise.resolve(new Response('upstream failed', { status: 500 }))
646
- throw new Error(`unexpected ${payload.action} credential`)
647
- })
648
- const s = sessionManager({
649
- account,
650
- client,
651
- fetch: mockFetch as typeof globalThis.fetch,
652
- maxDeposit: '20',
653
- channelStore: store,
654
- })
655
-
656
- const response = await s.fetch('https://api.example.com/data')
657
-
658
- expect(response.status).toBe(500)
659
- expect(postedPayloads.map((payload) => payload.action)).toEqual(['topUp', 'voucher'])
660
- expect(remove).not.toHaveBeenCalled()
661
- expect(map.get(entryKey(seeded))).toMatchObject({
662
- channelId: storedChannelId,
663
- cumulativeAmount: 10_000_000n,
664
- deposit: 11_000_000n,
665
- })
666
- expect(s.channelId).toBe(storedChannelId)
667
- expect(s.state).toMatchObject({
668
- status: 'active',
669
- channelId: storedChannelId,
670
- deposit: '11000000',
671
- })
672
- })
673
-
674
- test('rolls back optimistic opens across replacement challenges', async () => {
675
- const { store, delete: remove } = makeChannelStore()
676
- const postedPayloads: SessionCredentialPayload[] = []
677
- const challenge = (feePayer: boolean) =>
678
- makeChallenge({
679
- methodDetails: {
680
- escrowContract: tip20ChannelEscrow,
681
- chainId: 4217,
682
- sessionProtocol: Constants.SessionProtocols.v2,
683
- feePayer,
684
- },
685
- })
686
- const original = challenge(true)
687
- const replacement = challenge(false)
688
- let openCount = 0
689
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
690
- const authorization = new Headers(init?.headers).get(Constants.Headers.authorization)
691
- const payload = authorization
692
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
693
- : undefined
694
- if (payload) postedPayloads.push(payload)
695
-
696
- if (!payload) return Promise.resolve(make402Response(original))
697
- if (payload.action === 'open') {
698
- openCount++
699
- if (openCount === 1) return Promise.resolve(make402Response(replacement))
700
- if (openCount === 2) return Promise.resolve(make402Response(original))
701
- return Promise.resolve(makeOkResponse())
702
- }
703
- return Promise.resolve(new Response('unexpected voucher', { status: 500 }))
704
- })
705
- const s = sessionManager({
706
- account,
707
- client,
708
- fetch: mockFetch as typeof globalThis.fetch,
709
- maxDeposit: '10',
710
- channelStore: store,
711
- })
712
-
713
- const response = await s.fetch('https://api.example.com/data')
714
-
715
- expect(response.status).toBe(200)
716
- expect(postedPayloads.map((payload) => payload.action)).toEqual(['open', 'open', 'open'])
717
- expect(new Set(postedPayloads.map((payload) => payload.channelId)).size).toBe(3)
718
- expect(remove).toHaveBeenCalledTimes(2)
719
- expect(s.channelId).toBe(postedPayloads[2]?.channelId)
720
- })
721
-
722
- test('reuses prepared voucher state when an identical challenge succeeds', async () => {
723
- const vouchers: Extract<SessionCredentialPayload, { action: 'voucher' }>[] = []
724
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
725
- const authorization = new Headers(init?.headers).get(Constants.Headers.authorization)
726
- if (!authorization) return Promise.resolve(make402Response())
727
- const payload = Credential.deserialize<SessionCredentialPayload>(authorization).payload
728
- if (payload.action !== 'voucher') throw new Error('expected voucher')
729
- vouchers.push(payload)
730
- return Promise.resolve(vouchers.length === 1 ? make402Response() : makeOkResponse())
731
- })
732
- const s = sessionManager({
733
- account,
734
- client,
735
- fetch: mockFetch as typeof globalThis.fetch,
736
- channelStore: makeChannelStore([channelEntry()]).store,
737
- })
738
-
739
- expect((await s.fetch('https://api.example.com/data')).status).toBe(200)
740
- expect(vouchers.map((voucher) => voucher.cumulativeAmount)).toEqual(['2000000', '2000000'])
741
- expect(s.cumulative).toBe(2_000_000n)
742
- expect(s.state.status).toBe('active')
743
- })
744
-
745
- test('does not bootstrap when disabled', async () => {
746
- const mockFetch = vi.fn().mockResolvedValue(makeOkResponse())
747
- const s = sessionManager({
748
- account,
749
- client,
750
- fetch: mockFetch as typeof globalThis.fetch,
751
- })
752
-
753
- await s.fetch('https://api.example.com/data')
754
-
755
- expect(mockFetch).toHaveBeenCalledOnce()
756
- expect(new Headers(mockFetch.mock.calls[0]?.[1]?.headers).get('Payment-Session')).toBeNull()
757
- })
758
-
759
- test('uses stored channel details when the server does not return a snapshot', async () => {
760
- const postedPayloads: SessionCredentialPayload[] = []
761
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
762
- const authorization = new Headers(init?.headers).get('Authorization')
763
- const payload = authorization
764
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
765
- : undefined
766
- if (payload) postedPayloads.push(payload)
767
-
768
- if (!payload) return Promise.resolve(make402Response())
769
- return Promise.resolve(makeOkResponse())
770
- })
771
- const s = sessionManager({
772
- account,
773
- client,
774
- fetch: mockFetch as typeof globalThis.fetch,
775
- channelStore: makeChannelStore([channelEntry()]).store,
776
- })
777
-
778
- await s.fetch('https://api.example.com/data')
779
-
780
- expect(postedPayloads[0]).toMatchObject({
781
- action: 'voucher',
782
- channelId: storedChannelId,
783
- })
784
- })
785
-
786
- test('resumes a persisted channel across a restart via the entry index', async () => {
787
- // A shared durable KV backing two manager instances simulates a restart:
788
- // the second manager shares only what survived to disk.
789
- const backend = new Map<string, string>()
790
- const durableStore = () =>
791
- createJsonChannelStore({
792
- get: (key) => backend.get(key),
793
- set: (key, value) => {
794
- backend.set(key, value)
795
- },
796
- delete: (key) => {
797
- backend.delete(key)
798
- },
799
- })
800
-
801
- const openFetch = vi.fn((_input: RequestInfo | URL, init?: RequestInit) => {
802
- const authorization = new Headers(init?.headers).get(Constants.Headers.authorization)
803
- if (!authorization) return Promise.resolve(make402Response())
804
- return Promise.resolve(makeOkResponse())
805
- })
806
- const first = sessionManager({
807
- account,
808
- client,
809
- fetch: openFetch as typeof globalThis.fetch,
810
- maxDeposit: '10',
811
- channelStore: durableStore(),
812
- })
813
- await first.fetch('https://api.example.com/data')
814
- const channelId = first.channelId
815
- expect(channelId).toBeDefined()
816
-
817
- // The durable channel entry must have reached the KV.
818
- expect([...backend.keys()].some((key) => key.startsWith('chan:'))).toBe(true)
819
- // No persistent hints are written; only the durable channel entry survives.
820
- expect([...backend.keys()].some((key) => key.startsWith('hint:'))).toBe(false)
821
-
822
- const posted: SessionCredentialPayload[] = []
823
- const resumeFetch = vi.fn((_input: RequestInfo | URL, init?: RequestInit) => {
824
- const authorization = new Headers(init?.headers).get(Constants.Headers.authorization)
825
- const payload = authorization
826
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
827
- : undefined
828
- if (payload) posted.push(payload)
829
- if (!payload) return Promise.resolve(make402Response())
830
- return Promise.resolve(makeOkResponse())
831
- })
832
- const restarted = sessionManager({
833
- account,
834
- client,
835
- fetch: resumeFetch as typeof globalThis.fetch,
836
- maxDeposit: '10',
837
- channelStore: durableStore(),
838
- })
839
- await restarted.fetch('https://api.example.com/data')
840
-
841
- // The first request carries no hint header; after the 402 the restarted
842
- // manager tops up and resumes the full persisted channel rather than
843
- // opening a new one.
844
- expect(new Headers(resumeFetch.mock.calls[0]?.[1]?.headers).get('Payment-Session')).toBeNull()
845
- expect(posted.map((payload) => payload.action)).toEqual(['topUp', 'voucher'])
846
- expect(posted[1]).toMatchObject({ channelId })
847
- })
848
-
849
- test('persists opened channels and deletes closed channels when supported', async () => {
850
- const { store, set, delete: remove } = makeChannelStore()
851
- let callCount = 0
852
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
853
- const authorization = new Headers(init?.headers).get('Authorization')
854
- const payload = authorization
855
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
856
- : undefined
857
- callCount++
858
-
859
- if (callCount === 1) return Promise.resolve(make402Response())
860
- if (payload?.action === 'open') {
861
- return Promise.resolve(
862
- new Response('ok', {
863
- headers: {
864
- 'Payment-Receipt': serializeSessionReceipt(
865
- createSessionReceipt({
866
- acceptedCumulative: BigInt(payload.cumulativeAmount),
867
- challengeId,
868
- channelId: payload.channelId,
869
- spent: 0n,
870
- }),
871
- ),
872
- },
873
- }),
874
- )
875
- }
876
- if (payload?.action === 'close') {
877
- return Promise.resolve(
878
- new Response('ok', {
879
- headers: {
880
- 'Payment-Receipt': serializeSessionReceipt(
881
- createSessionReceipt({
882
- acceptedCumulative: BigInt(payload.cumulativeAmount),
883
- challengeId,
884
- channelId: payload.channelId,
885
- spent: BigInt(payload.cumulativeAmount),
886
- txHash: `0x${'aa'.repeat(32)}`,
887
- }),
888
- ),
889
- },
890
- }),
891
- )
892
- }
893
- return Promise.resolve(makeOkResponse())
894
- })
895
- const s = sessionManager({
896
- account,
897
- client,
898
- fetch: mockFetch as typeof globalThis.fetch,
899
- maxDeposit: '10',
900
- channelStore: store,
901
- })
902
-
903
- await s.fetch('https://api.example.com/data')
904
- expect(set).toHaveBeenCalledWith(
905
- expect.objectContaining({
906
- channelId: s.channelId,
907
- opened: true,
908
- }),
909
- )
910
-
911
- await s.close()
912
- expect(remove).toHaveBeenCalledOnce()
913
- })
914
-
915
- test('rolls back state when opening a channel throws', async () => {
916
- const failingClient = createClient({
917
- account,
918
- chain: { id: 4217 } as never,
919
- transport: custom({
920
- async request(args) {
921
- if (args.method === 'eth_chainId') return '0x1079'
922
- if (args.method === 'eth_getTransactionCount') return '0x0'
923
- if (args.method === 'eth_estimateGas') throw new Error('insufficient balance')
924
- if (args.method === 'eth_maxPriorityFeePerGas') return '0x1'
925
- if (args.method === 'eth_getBlockByNumber') return { baseFeePerGas: '0x1' }
926
- throw new Error(`unexpected rpc request: ${args.method}`)
927
- },
928
- }),
929
- })
930
- const mockFetch = vi.fn().mockResolvedValue(make402Response())
931
- const s = sessionManager({
932
- account,
933
- client: failingClient,
934
- fetch: mockFetch as typeof globalThis.fetch,
935
- maxDeposit: '10',
936
- })
937
-
938
- await expect(s.fetch('https://api.example.com/data')).rejects.toThrow(/insufficient balance/)
939
-
940
- expect(s.state).toEqual({ status: 'idle' })
941
- expect(s.opened).toBe(false)
942
- expect(s.cumulative).toBe(0n)
943
- })
944
-
945
- test('automatically top-ups and retries when an HTTP session exceeds deposit', async () => {
946
- const postedPayloads: SessionCredentialPayload[] = []
947
- let callCount = 0
948
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
949
- callCount++
950
- const authorization = new Headers(init?.headers).get('Authorization')
951
- const payload = authorization
952
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
953
- : undefined
954
- if (payload) postedPayloads.push(payload)
955
-
956
- if (callCount === 1)
957
- return Promise.resolve(make402Response(makeChallenge({ suggestedDeposit: '1000000' })))
958
-
959
- if (payload?.action === 'open') {
960
- return Promise.resolve(
961
- make402Response(
962
- makeChallenge({
963
- methodDetails: {
964
- escrowContract: tip20ChannelEscrow,
965
- chainId: 4217,
966
- sessionProtocol: Constants.SessionProtocols.v2,
967
- sessionSnapshot: {
968
- acceptedCumulative: '2000000',
969
- chainId: 4217,
970
- channelId: payload.channelId,
971
- deposit: '1000000',
972
- descriptor: payload.descriptor,
973
- escrow: tip20ChannelEscrow,
974
- requiredCumulative: '2000000',
975
- settled: '0',
976
- spent: '1000000',
977
- units: 1,
978
- },
979
- },
980
- }),
981
- ),
982
- )
983
- }
984
-
985
- if (payload?.action === 'topUp') return Promise.resolve(makeOkResponse())
986
-
987
- if (payload?.action === 'voucher') {
988
- return Promise.resolve(
989
- new Response('paid', {
990
- status: 200,
991
- headers: {
992
- 'Payment-Receipt': serializeSessionReceipt(
993
- createSessionReceipt({
994
- acceptedCumulative: 2_000_000n,
995
- challengeId,
996
- channelId: payload.channelId,
997
- spent: 2_000_000n,
998
- units: 2,
999
- }),
1000
- ),
1001
- },
1002
- }),
1003
- )
1004
- }
1005
-
1006
- return Promise.resolve(makeOkResponse())
1007
- })
1008
-
1009
- const s = sessionManager({
1010
- account,
1011
- client,
1012
- fetch: mockFetch as typeof globalThis.fetch,
1013
- maxDeposit: '10',
1014
- })
1015
-
1016
- const response = await s.fetch('https://api.example.com/data')
1017
-
1018
- expect(response.status).toBe(200)
1019
- expect(await response.text()).toBe('paid')
1020
- expect(postedPayloads.map((payload) => payload.action)).toEqual(['open', 'topUp', 'voucher'])
1021
- expect(s.state).toMatchObject({
1022
- status: 'active',
1023
- acceptedCumulative: '2000000',
1024
- deposit: '2000000',
1025
- spent: '2000000',
1026
- units: 2,
1027
- })
1028
- })
1029
-
1030
- test('preserves a snapshot-acknowledged open when its voucher fails', async () => {
1031
- const { backend, store } = makeDurableChannelStore()
1032
- const payloads: SessionCredentialPayload[] = []
1033
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1034
- const authorization = new Headers(init?.headers).get(Constants.Headers.authorization)
1035
- if (!authorization)
1036
- return Promise.resolve(make402Response(makeChallenge({ suggestedDeposit: '10000000' })))
1037
- const payload = Credential.deserialize<SessionCredentialPayload>(authorization).payload
1038
- payloads.push(payload)
1039
- if (payload.action !== 'open')
1040
- return Promise.resolve(new Response('failed', { status: 500 }))
1041
- return Promise.resolve(
1042
- make402Response(
1043
- makeChallenge({
1044
- methodDetails: {
1045
- escrowContract: tip20ChannelEscrow,
1046
- chainId: 4217,
1047
- sessionProtocol: Constants.SessionProtocols.v2,
1048
- sessionSnapshot: {
1049
- acceptedCumulative: '1000000',
1050
- chainId: 4217,
1051
- channelId: payload.channelId,
1052
- deposit: '10000000',
1053
- descriptor: payload.descriptor,
1054
- escrow: tip20ChannelEscrow,
1055
- requiredCumulative: '2000000',
1056
- settled: '0',
1057
- spent: '1000000',
1058
- units: 1,
1059
- },
1060
- },
1061
- }),
1062
- ),
1063
- )
1064
- })
1065
- const s = sessionManager({
1066
- account,
1067
- client,
1068
- fetch: mockFetch as typeof globalThis.fetch,
1069
- maxDeposit: '10',
1070
- channelStore: store,
1071
- })
1072
-
1073
- expect((await s.fetch('https://api.example.com/data')).status).toBe(500)
1074
- expect(payloads.map((payload) => payload.action)).toEqual(['open', 'voucher'])
1075
- expect(s.channelId).toBe(payloads[0]?.channelId)
1076
- expect(s.cumulative).toBe(1_000_000n)
1077
- expect(JSON.parse([...backend.values()][0]!)).toMatchObject({
1078
- channelId: payloads[0]?.channelId,
1079
- cumulativeAmount: '1000000',
1080
- opened: true,
1081
- })
1082
- })
1083
-
1084
- test('preemptively top-ups before signing an HTTP voucher that exceeds deposit', async () => {
1085
- const postedPayloads: SessionCredentialPayload[] = []
1086
- let challengeCount = 0
1087
- const receipt = (payload: Extract<SessionCredentialPayload, { channelId: Hex }>) =>
1088
- new Response('paid', {
1089
- status: 200,
1090
- headers: {
1091
- 'Payment-Receipt': serializeSessionReceipt(
1092
- createSessionReceipt({
1093
- acceptedCumulative: BigInt(
1094
- 'cumulativeAmount' in payload ? payload.cumulativeAmount : '1000000',
1095
- ),
1096
- challengeId,
1097
- channelId: payload.channelId,
1098
- spent: BigInt('cumulativeAmount' in payload ? payload.cumulativeAmount : '1000000'),
1099
- units:
1100
- 'cumulativeAmount' in payload && payload.cumulativeAmount === '2000000' ? 2 : 1,
1101
- }),
1102
- ),
1103
- },
1104
- })
1105
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1106
- const authorization = new Headers(init?.headers).get('Authorization')
1107
- const payload = authorization
1108
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
1109
- : undefined
1110
- if (payload) postedPayloads.push(payload)
1111
-
1112
- if (!payload) {
1113
- challengeCount++
1114
- return Promise.resolve(
1115
- make402Response(
1116
- makeChallenge(challengeCount === 1 ? { suggestedDeposit: '1000000' } : {}),
1117
- ),
1118
- )
1119
- }
1120
- if (payload.action === 'topUp') return Promise.resolve(makeOkResponse())
1121
- if (payload.action === 'open' || payload.action === 'voucher')
1122
- return Promise.resolve(receipt(payload))
1123
- return Promise.resolve(makeOkResponse())
1124
- })
1125
-
1126
- const s = sessionManager({
1127
- account,
1128
- client,
1129
- fetch: mockFetch as typeof globalThis.fetch,
1130
- maxDeposit: '10',
1131
- topUpAmount: '5',
1132
- })
1133
-
1134
- await s.fetch('https://api.example.com/data')
1135
- const response = await s.fetch('https://api.example.com/data')
1136
-
1137
- expect(response.status).toBe(200)
1138
- expect(postedPayloads.map((payload) => payload.action)).toEqual(['open', 'topUp', 'voucher'])
1139
- const topUp = postedPayloads[1]
1140
- if (topUp?.action !== 'topUp') throw new Error('expected top-up payload')
1141
- expect(topUp.additionalDeposit).toBe('5000000')
1142
- expect(s.state).toMatchObject({
1143
- status: 'active',
1144
- acceptedCumulative: '2000000',
1145
- deposit: '6000000',
1146
- spent: '2000000',
1147
- units: 2,
1148
- })
1149
- })
1150
-
1151
- test('preserves a successful automatic top-up when the paid retry fails', async () => {
1152
- const { map, store } = makeChannelStore()
1153
- const payloads: SessionCredentialPayload[] = []
1154
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1155
- const authorization = new Headers(init?.headers).get(Constants.Headers.authorization)
1156
- if (!authorization)
1157
- return Promise.resolve(make402Response(makeChallenge({ suggestedDeposit: '1000000' })))
1158
- const payload = Credential.deserialize<SessionCredentialPayload>(authorization).payload
1159
- payloads.push(payload)
1160
- if (payload.action === 'open')
1161
- return Promise.resolve(
1162
- new Response('ok', {
1163
- headers: {
1164
- [Constants.Headers.paymentReceipt]: serializeSessionReceipt(
1165
- createSessionReceipt({
1166
- acceptedCumulative: 1_000_000n,
1167
- challengeId,
1168
- channelId: payload.channelId,
1169
- spent: 1_000_000n,
1170
- units: 3,
1171
- }),
1172
- ),
1173
- },
1174
- }),
1175
- )
1176
- if (payload.action === 'topUp') return Promise.resolve(new Response(null, { status: 204 }))
1177
- return Promise.resolve(make402Response(makeChallenge({ suggestedDeposit: '1000000' })))
1178
- })
1179
- const s = sessionManager({
1180
- account,
1181
- client,
1182
- fetch: mockFetch as typeof globalThis.fetch,
1183
- maxDeposit: '3',
1184
- channelStore: store,
1185
- })
1186
-
1187
- await s.fetch('https://api.example.com/data')
1188
- expect((await s.fetch('https://api.example.com/data')).status).toBe(402)
1189
-
1190
- expect(payloads.map((payload) => payload.action)).toEqual([
1191
- 'open',
1192
- 'topUp',
1193
- 'voucher',
1194
- 'voucher',
1195
- 'voucher',
1196
- ])
1197
- expect(s.cumulative).toBe(1_000_000n)
1198
- expect(s.state).toMatchObject({ status: 'active', deposit: '2000000', units: 3 })
1199
- expect([...map.values()][0]).toMatchObject({
1200
- cumulativeAmount: 1_000_000n,
1201
- deposit: 2_000_000n,
1202
- })
1203
- })
1204
-
1205
- test('preserves a topped-up resumed channel in durable storage after payment fails', async () => {
1206
- const { store } = makeDurableChannelStore()
1207
- const seeded = channelEntry({ cumulativeAmount: 1_000_000n, deposit: 1_000_000n })
1208
- await store.set(seeded)
1209
- const payloads: SessionCredentialPayload[] = []
1210
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1211
- const authorization = new Headers(init?.headers).get(Constants.Headers.authorization)
1212
- if (!authorization)
1213
- return Promise.resolve(make402Response(makeChallenge({ suggestedDeposit: '1000000' })))
1214
- const payload = Credential.deserialize<SessionCredentialPayload>(authorization).payload
1215
- payloads.push(payload)
1216
- return Promise.resolve(
1217
- payload.action === 'topUp'
1218
- ? new Response(null, { status: 204 })
1219
- : new Response('failed', { status: 500 }),
1220
- )
1221
- })
1222
- const s = sessionManager({
1223
- account,
1224
- client,
1225
- fetch: mockFetch as typeof globalThis.fetch,
1226
- maxDeposit: '3',
1227
- channelStore: store,
1228
- })
1229
-
1230
- expect((await s.fetch('https://api.example.com/data')).status).toBe(500)
1231
-
1232
- expect(payloads.map((payload) => payload.action)).toEqual(['topUp', 'voucher'])
1233
- expect(s.cumulative).toBe(1_000_000n)
1234
- expect(s.state).toMatchObject({ status: 'active', deposit: '2000000' })
1235
- await expect(store.get(entryKey(seeded))).resolves.toMatchObject({
1236
- cumulativeAmount: 1_000_000n,
1237
- deposit: 2_000_000n,
1238
- opened: true,
1239
- })
1240
- })
1241
-
1242
- test.each([
1243
- ['new', false],
1244
- ['replacement', true],
1245
- ] as const)('removes a failed %s durable channel', async (_kind, seeded) => {
1246
- const { backend, store } = makeDurableChannelStore()
1247
- if (seeded) await store.set(channelEntry())
1248
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1249
- const authorization = new Headers(init?.headers).get(Constants.Headers.authorization)
1250
- return Promise.resolve(
1251
- authorization ? new Response('failed', { status: 500 }) : make402Response(),
1252
- )
1253
- })
1254
- const s = sessionManager({
1255
- account,
1256
- client,
1257
- fetch: mockFetch as typeof globalThis.fetch,
1258
- channelStore: store,
1259
- })
1260
-
1261
- expect((await s.fetch('https://api.example.com/data')).status).toBe(500)
1262
- expect(s.channelId).toBeUndefined()
1263
- expect(backend.size).toBe(0)
1264
- })
1265
- })
1266
-
1267
- describe('.topUp()', () => {
1268
- test('posts a precompile top-up credential for the active channel', async () => {
1269
- const postedPayloads: SessionCredentialPayload[] = []
1270
- let callCount = 0
1271
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1272
- callCount++
1273
- const authorization = new Headers(init?.headers).get('Authorization')
1274
- if (authorization) {
1275
- postedPayloads.push(
1276
- Credential.deserialize<SessionCredentialPayload>(authorization).payload,
1277
- )
1278
- }
1279
- if (callCount === 1)
1280
- return Promise.resolve(make402Response(makeChallenge({ suggestedDeposit: '5000000' })))
1281
- return Promise.resolve(makeOkResponse())
1282
- })
1283
-
1284
- const s = sessionManager({
1285
- account,
1286
- client,
1287
- fetch: mockFetch as typeof globalThis.fetch,
1288
- maxDeposit: '10',
1289
- })
1290
-
1291
- await s.fetch('https://api.example.com/data')
1292
- expect(s.state).toMatchObject({
1293
- status: 'active',
1294
- acceptedCumulative: '1000000',
1295
- deposit: '5000000',
1296
- })
1297
- const receipt = await s.topUp('1')
1298
-
1299
- expect(receipt).toBeUndefined()
1300
- expect(s.state).toMatchObject({
1301
- status: 'active',
1302
- acceptedCumulative: '1000000',
1303
- deposit: '6000000',
1304
- })
1305
- expect(postedPayloads[0]?.action).toBe('open')
1306
- expect(postedPayloads[1]?.action).toBe('topUp')
1307
- const openPayload = postedPayloads[0]
1308
- const topUpPayload = postedPayloads[1]
1309
- if (openPayload?.action !== 'open' || topUpPayload?.action !== 'topUp') {
1310
- throw new Error('expected open then top-up payloads')
1311
- }
1312
- expect(topUpPayload.channelId).toBe(openPayload.channelId)
1313
- expect(topUpPayload.descriptor).toEqual(openPayload.descriptor)
1314
- expect(topUpPayload.additionalDeposit).toBe('1000000')
1315
- })
1316
-
1317
- test('rejects top-up before a channel is open', async () => {
1318
- const s = sessionManager({
1319
- account,
1320
- client,
1321
- fetch: vi.fn() as typeof globalThis.fetch,
1322
- maxDeposit: '10',
1323
- })
1324
-
1325
- await expect(s.topUp('1')).rejects.toThrow('Cannot top up session: no open channel.')
1326
- })
1327
-
1328
- test('rolls back optimistic vouchers when the paid retry fails', async () => {
1329
- const postedPayloads: SessionCredentialPayload[] = []
1330
- let callCount = 0
1331
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1332
- callCount++
1333
- const authorization = new Headers(init?.headers).get('Authorization')
1334
- if (authorization) {
1335
- postedPayloads.push(
1336
- Credential.deserialize<SessionCredentialPayload>(authorization).payload,
1337
- )
1338
- }
1339
- if (callCount === 1)
1340
- return Promise.resolve(make402Response(makeChallenge({ suggestedDeposit: '3000000' })))
1341
- if (callCount >= 3 && callCount <= 6) return Promise.resolve(make402Response())
1342
- return Promise.resolve(makeOkResponse())
1343
- })
1344
-
1345
- const s = sessionManager({
1346
- account,
1347
- client,
1348
- fetch: mockFetch as typeof globalThis.fetch,
1349
- maxDeposit: '3',
1350
- })
1351
-
1352
- await s.fetch('https://api.example.com/data')
1353
- expect(s.cumulative).toBe(1000000n)
1354
-
1355
- const failed = await s.fetch('https://api.example.com/data')
1356
- expect(failed.status).toBe(402)
1357
- expect(s.cumulative).toBe(1000000n)
1358
-
1359
- await s.topUp('1')
1360
- expect(postedPayloads.map((payload) => payload.action)).toEqual([
1361
- 'open',
1362
- 'voucher',
1363
- 'voucher',
1364
- 'voucher',
1365
- 'topUp',
1366
- ])
1367
- const topUpPayload = postedPayloads[4]
1368
- if (topUpPayload?.action !== 'topUp') throw new Error('expected top-up payload')
1369
- expect(topUpPayload.additionalDeposit).toBe('1000000')
1370
- })
1371
- })
1372
-
1373
- describe('.sse() event parsing', () => {
1374
- test('yields only message data from SSE stream', async () => {
1375
- const events = [
1376
- 'event: message\ndata: chunk1\n\n',
1377
- 'event: message\ndata: chunk2\n\n',
1378
- `event: payment-receipt\ndata: ${JSON.stringify({
1379
- method: 'tempo',
1380
- intent: 'session',
1381
- status: 'success',
1382
- timestamp: '2025-01-01T00:00:00.000Z',
1383
- reference: channelId,
1384
- challengeId,
1385
- channelId,
1386
- acceptedCumulative: '2000000',
1387
- spent: '2000000',
1388
- units: 2,
1389
- } satisfies SessionReceipt)}\n\n`,
1390
- ]
1391
-
1392
- let callCount = 0
1393
- const mockFetch = vi.fn().mockImplementation(() => {
1394
- callCount++
1395
- if (callCount === 1) return Promise.resolve(makeSseResponse(events))
1396
- return Promise.resolve(makeOkResponse())
1397
- })
1398
-
1399
- const s = sessionManager({
1400
- account: '0x0000000000000000000000000000000000000001',
1401
- fetch: mockFetch as typeof globalThis.fetch,
1402
- })
1403
-
1404
- // Manually set channel state to skip auto-open flow
1405
- ;(s as any).__test_setChannel?.()
1406
-
1407
- const receiptCb = vi.fn()
1408
- const iterable = await s.sse('https://api.example.com/stream', {
1409
- onReceipt: receiptCb,
1410
- })
1411
-
1412
- const messages: string[] = []
1413
- for await (const msg of iterable) {
1414
- messages.push(msg)
1415
- }
1416
-
1417
- expect(messages).toEqual(['chunk1', 'chunk2'])
1418
- expect(receiptCb).toHaveBeenCalledOnce()
1419
- expect(receiptCb.mock.calls[0]![0].units).toBe(2)
1420
- })
1421
-
1422
- test('posts precompile SSE top-up vouchers with the channel descriptor', async () => {
1423
- const requestedUrls: string[] = []
1424
- const postedPayloads: SessionCredentialPayload[] = []
1425
- let callCount = 0
1426
- const mockFetch = vi.fn().mockImplementation((input, init?: RequestInit) => {
1427
- callCount++
1428
- requestedUrls.push(input.toString())
1429
- const authorization = new Headers(init?.headers).get('Authorization')
1430
- if (authorization) {
1431
- postedPayloads.push(
1432
- Credential.deserialize<SessionCredentialPayload>(authorization).payload,
1433
- )
1434
- }
1435
- if (callCount === 1) return Promise.resolve(make402Response())
1436
- if (callCount === 2) {
1437
- const openPayload = postedPayloads[0]
1438
- if (openPayload?.action !== 'open') throw new Error('expected open payload')
1439
- const needVoucher: NeedVoucherEvent = {
1440
- channelId: openPayload.channelId,
1441
- requiredCumulative: '2000000',
1442
- acceptedCumulative: '1000000',
1443
- deposit: '10000000',
1444
- }
1445
- return Promise.resolve(
1446
- makeSseResponse([
1447
- 'event: message\ndata: chunk1\n\n',
1448
- formatNeedVoucherEvent(needVoucher),
1449
- 'event: message\ndata: chunk2\n\n',
1450
- ]),
1451
- )
1452
- }
1453
- return Promise.resolve(makeOkResponse())
1454
- })
1455
-
1456
- const s = sessionManager({
1457
- account,
1458
- client,
1459
- fetch: mockFetch as typeof globalThis.fetch,
1460
- maxDeposit: '10',
1461
- })
1462
-
1463
- const iterable = await s.sse('https://api.example.com/stream?prompt=paid')
1464
- const messages: string[] = []
1465
- for await (const msg of iterable) messages.push(msg)
1466
-
1467
- expect(messages).toEqual(['chunk1', 'chunk2'])
1468
- expect(postedPayloads[0]?.action).toBe('open')
1469
- expect(postedPayloads[1]?.action).toBe('voucher')
1470
- const openPayload = postedPayloads[0]
1471
- const voucherPayload = postedPayloads[1]
1472
- if (openPayload?.action !== 'open' || voucherPayload?.action !== 'voucher')
1473
- throw new Error('expected open then voucher payloads')
1474
- expect(voucherPayload.channelId).toBe(openPayload.channelId)
1475
- expect(voucherPayload.descriptor).toEqual(openPayload.descriptor)
1476
- expect(voucherPayload.cumulativeAmount).toBe('2000000')
1477
- expect(requestedUrls[2]).toBe('https://api.example.com/stream?prompt=paid')
1478
- })
1479
-
1480
- test('ignores precompile SSE voucher requests for a different channel', async () => {
1481
- const mismatchedChannelId = `0x${'ff'.repeat(32)}` as Hex
1482
- const needVoucher: NeedVoucherEvent = {
1483
- channelId: mismatchedChannelId,
1484
- requiredCumulative: '2000000',
1485
- acceptedCumulative: '1000000',
1486
- deposit: '10000000',
1487
- }
1488
- const events = [
1489
- 'event: message\ndata: chunk1\n\n',
1490
- formatNeedVoucherEvent(needVoucher),
1491
- 'event: message\ndata: chunk2\n\n',
1492
- ]
1493
- const postedPayloads: SessionCredentialPayload[] = []
1494
- let callCount = 0
1495
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1496
- callCount++
1497
- const authorization = new Headers(init?.headers).get('Authorization')
1498
- if (authorization) {
1499
- postedPayloads.push(
1500
- Credential.deserialize<SessionCredentialPayload>(authorization).payload,
1501
- )
1502
- }
1503
- if (callCount === 1) return Promise.resolve(make402Response())
1504
- if (callCount === 2) return Promise.resolve(makeSseResponse(events))
1505
- return Promise.resolve(makeOkResponse())
1506
- })
1507
-
1508
- const s = sessionManager({
1509
- account,
1510
- client,
1511
- fetch: mockFetch as typeof globalThis.fetch,
1512
- maxDeposit: '10',
1513
- })
1514
-
1515
- const iterable = await s.sse('https://api.example.com/stream')
1516
- const messages: string[] = []
1517
- for await (const msg of iterable) messages.push(msg)
1518
-
1519
- expect(messages).toEqual(['chunk1', 'chunk2'])
1520
- expect(postedPayloads.map((payload) => payload.action)).toEqual(['open'])
1521
- expect(callCount).toBe(2)
1522
- })
1523
-
1524
- test('retries for the event stream after an open management response', async () => {
1525
- const postedPayloads: SessionCredentialPayload[] = []
1526
- let callCount = 0
1527
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1528
- callCount++
1529
- const authorization = new Headers(init?.headers).get('Authorization')
1530
- const payload = authorization
1531
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
1532
- : undefined
1533
- if (payload) postedPayloads.push(payload)
1534
-
1535
- if (!payload) {
1536
- return Promise.resolve(make402Response(makeChallenge({ suggestedDeposit: '5000000' })))
1537
- }
1538
-
1539
- if (payload.action === 'open') {
1540
- return Promise.resolve(
1541
- new Response(null, {
1542
- status: 200,
1543
- headers: {
1544
- 'Payment-Receipt': serializeSessionReceipt(
1545
- createSessionReceipt({
1546
- acceptedCumulative: 1_000_000n,
1547
- challengeId,
1548
- channelId: payload.channelId,
1549
- spent: 1_000_000n,
1550
- units: 1,
1551
- }),
1552
- ),
1553
- },
1554
- }),
1555
- )
1556
- }
1557
-
1558
- if (payload.action === 'voucher') {
1559
- return Promise.resolve(
1560
- makeSseResponse([
1561
- 'event: message\ndata: chunk1\n\n',
1562
- 'event: message\ndata: chunk2\n\n',
1563
- `event: payment-receipt\ndata: ${JSON.stringify(
1564
- createSessionReceipt({
1565
- acceptedCumulative: BigInt(payload.cumulativeAmount),
1566
- challengeId,
1567
- channelId: payload.channelId,
1568
- spent: BigInt(payload.cumulativeAmount),
1569
- units: 2,
1570
- }),
1571
- )}\n\n`,
1572
- ]),
1573
- )
1574
- }
1575
-
1576
- return Promise.resolve(makeOkResponse())
1577
- })
1578
-
1579
- const s = sessionManager({
1580
- account,
1581
- client,
1582
- fetch: mockFetch as typeof globalThis.fetch,
1583
- maxDeposit: '10',
1584
- })
1585
-
1586
- const iterable = await s.sse('https://api.example.com/stream')
1587
- const messages: string[] = []
1588
- for await (const msg of iterable) messages.push(msg)
1589
-
1590
- expect(messages).toEqual(['chunk1', 'chunk2'])
1591
- expect(postedPayloads.map((payload) => payload.action)).toEqual(['open', 'voucher'])
1592
- expect(callCount).toBe(4)
1593
- expect(s.state).toMatchObject({
1594
- status: 'active',
1595
- acceptedCumulative: '2000000',
1596
- deposit: '5000000',
1597
- spent: '2000000',
1598
- units: 2,
1599
- })
1600
- })
1601
- })
1602
-
1603
- describe('error handling', () => {
1604
- test('.sse() silently skips payment-need-voucher when no channel open', async () => {
1605
- const needVoucher: NeedVoucherEvent = {
1606
- channelId,
1607
- requiredCumulative: '2000000',
1608
- acceptedCumulative: '1000000',
1609
- deposit: '10000000',
1610
- }
1611
-
1612
- const events = [
1613
- 'event: message\ndata: chunk1\n\n',
1614
- formatNeedVoucherEvent(needVoucher),
1615
- 'event: message\ndata: chunk2\n\n',
1616
- ]
1617
-
1618
- const mockFetch = vi.fn().mockResolvedValue(makeSseResponse(events))
1619
-
1620
- const s = sessionManager({
1621
- account: '0x0000000000000000000000000000000000000001',
1622
- fetch: mockFetch as typeof globalThis.fetch,
1623
- })
1624
-
1625
- const iterable = await s.sse('https://api.example.com/stream')
1626
-
1627
- const messages: string[] = []
1628
- for await (const msg of iterable) {
1629
- messages.push(msg)
1630
- }
1631
-
1632
- expect(messages).toEqual(['chunk1', 'chunk2'])
1633
- expect(mockFetch).toHaveBeenCalledOnce()
1634
- })
1635
- })
1636
-
1637
- describe('.sse() headers normalization', () => {
1638
- test('preserves Headers instance properties when passed as headers', async () => {
1639
- const mockFetch = vi.fn().mockResolvedValue(makeSseResponse(['event: message\ndata: ok\n\n']))
1640
-
1641
- const s = sessionManager({
1642
- account: '0x0000000000000000000000000000000000000001',
1643
- fetch: mockFetch as typeof globalThis.fetch,
1644
- })
1645
-
1646
- const iterable = await s.sse('https://api.example.com/stream', {
1647
- headers: new Headers({ 'Content-Type': 'application/json', 'X-Custom': 'value' }),
1648
- })
1649
-
1650
- for await (const _ of iterable) {
1651
- // drain
1652
- }
1653
-
1654
- const calledHeaders = new Headers((mockFetch.mock.calls[0]![1] as RequestInit).headers)
1655
- expect(calledHeaders.get('content-type')).toBe('application/json')
1656
- expect(calledHeaders.get('x-custom')).toBe('value')
1657
- expect(calledHeaders.get('accept')).toBe('text/event-stream')
1658
- })
1659
- })
1660
-
1661
- describe('.ws()', () => {
1662
- test('tops up a full persisted channel before constructing the socket', async () => {
1663
- const events: string[] = []
1664
- const { map, set, store } = makeChannelStore([
1665
- channelEntry({ cumulativeAmount: 1_000_000n, deposit: 1_000_000n }),
1666
- ])
1667
- set.mockImplementation((entry) => {
1668
- map.set(entryKey(entry), entry)
1669
- events.push(`set:${entry.deposit}:${entry.cumulativeAmount}`)
1670
- })
1671
- const fetch = vi.fn(async (_input, init?: RequestInit) => {
1672
- const authorization = new Headers(init?.headers).get(Constants.Headers.authorization)
1673
- if (!authorization) {
1674
- events.push('probe')
1675
- return make402Response(makeChallenge({ suggestedDeposit: '1000000' }))
1676
- }
1677
- const payload = Credential.deserialize<SessionCredentialPayload>(authorization).payload
1678
- if (payload.action !== 'topUp') throw new Error(`unexpected ${payload.action} fetch`)
1679
- events.push('topUp')
1680
- return new Response(null, { status: 204 })
1681
- })
1682
- function WebSocket() {
1683
- events.push('socket')
1684
- throw new Error('stop after preparation')
1685
- }
1686
- const s = sessionManager({
1687
- account,
1688
- client,
1689
- fetch: fetch as typeof globalThis.fetch,
1690
- maxDeposit: '3',
1691
- channelStore: store,
1692
- webSocket: WebSocket as never,
1693
- })
1694
-
1695
- await expect(s.ws('wss://api.example.com/socket')).rejects.toThrow('stop after preparation')
1696
- expect(events).toEqual([
1697
- 'probe',
1698
- 'topUp',
1699
- 'set:2000000:1000000',
1700
- 'set:2000000:2000000',
1701
- 'socket',
1702
- ])
1703
- })
1704
- })
1705
-
1706
- describe('.close()', () => {
1707
- test('is no-op when not opened', async () => {
1708
- const mockFetch = vi.fn()
1709
-
1710
- const s = sessionManager({
1711
- account: '0x0000000000000000000000000000000000000001',
1712
- fetch: mockFetch as typeof globalThis.fetch,
1713
- })
1714
-
1715
- await s.close()
1716
- expect(mockFetch).not.toHaveBeenCalled()
1717
- })
1718
-
1719
- test('tracks spent from HTTP error receipts and closes at that amount', async () => {
1720
- const postedPayloads: SessionCredentialPayload[] = []
1721
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1722
- const authorization = new Headers(init?.headers).get('Authorization')
1723
- const payload = authorization
1724
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
1725
- : undefined
1726
- if (payload) postedPayloads.push(payload)
1727
-
1728
- if (!payload)
1729
- return Promise.resolve(
1730
- make402Response(makeChallenge({ amount: '1', suggestedDeposit: '2' })),
1731
- )
1732
- if (payload.action === 'open') {
1733
- return Promise.resolve(
1734
- new Response('upstream failed', {
1735
- status: 500,
1736
- headers: {
1737
- 'Payment-Receipt': serializeSessionReceipt(
1738
- createSessionReceipt({
1739
- acceptedCumulative: BigInt(payload.cumulativeAmount),
1740
- challengeId,
1741
- channelId: payload.channelId,
1742
- spent: 1n,
1743
- units: 1,
1744
- }),
1745
- ),
1746
- },
1747
- }),
1748
- )
1749
- }
1750
- if (payload.action === 'close') {
1751
- return Promise.resolve(
1752
- new Response(null, {
1753
- status: 200,
1754
- headers: {
1755
- 'Payment-Receipt': serializeSessionReceipt(
1756
- createSessionReceipt({
1757
- acceptedCumulative: BigInt(payload.cumulativeAmount),
1758
- challengeId,
1759
- channelId: payload.channelId,
1760
- spent: BigInt(payload.cumulativeAmount),
1761
- txHash: `0x${'aa'.repeat(32)}` as Hex,
1762
- units: 1,
1763
- }),
1764
- ),
1765
- },
1766
- }),
1767
- )
1768
- }
1769
- return Promise.resolve(makeOkResponse())
1770
- })
1771
-
1772
- const s = sessionManager({
1773
- account,
1774
- client,
1775
- decimals: 0,
1776
- fetch: mockFetch as typeof globalThis.fetch,
1777
- maxDeposit: '2',
1778
- })
1779
-
1780
- const response = await s.fetch('https://api.example.com/resource')
1781
- expect(response.status).toBe(500)
1782
- expect(response.receipt?.spent).toBe('1')
1783
-
1784
- const closeReceipt = await s.close()
1785
- expect(closeReceipt?.status).toBe('success')
1786
- expect(closeReceipt?.spent).toBe('1')
1787
- expect(s.state).toMatchObject({
1788
- status: 'closed',
1789
- channelId: closeReceipt?.channelId,
1790
- })
1791
- const closePayload = postedPayloads.find((payload) => payload.action === 'close')
1792
- expect(closePayload?.cumulativeAmount).toBe('1')
1793
- })
1794
-
1795
- test('rejects receipts that exceed the locally signed voucher', async () => {
1796
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1797
- const authorization = new Headers(init?.headers).get('Authorization')
1798
- const payload = authorization
1799
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
1800
- : undefined
1801
-
1802
- if (!payload)
1803
- return Promise.resolve(
1804
- make402Response(makeChallenge({ amount: '1', suggestedDeposit: '3' })),
1805
- )
1806
- if (payload.action === 'open') {
1807
- return Promise.resolve(
1808
- new Response('ok', {
1809
- status: 200,
1810
- headers: {
1811
- 'Payment-Receipt': serializeSessionReceipt(
1812
- createSessionReceipt({
1813
- acceptedCumulative: 3n,
1814
- challengeId,
1815
- channelId: payload.channelId,
1816
- spent: 3n,
1817
- units: 1,
1818
- }),
1819
- ),
1820
- },
1821
- }),
1822
- )
1823
- }
1824
- return Promise.resolve(makeOkResponse())
1825
- })
1826
-
1827
- const s = sessionManager({
1828
- account,
1829
- client,
1830
- decimals: 0,
1831
- fetch: mockFetch as typeof globalThis.fetch,
1832
- maxDeposit: '3',
1833
- })
1834
-
1835
- await expect(s.fetch('https://api.example.com/resource')).rejects.toThrow(
1836
- 'receipt accepted cumulative exceeds local voucher state',
1837
- )
1838
- })
1839
-
1840
- test('surfaces close failure problem details', async () => {
1841
- const mockFetch = vi.fn().mockImplementation((_input, init?: RequestInit) => {
1842
- const authorization = new Headers(init?.headers).get('Authorization')
1843
- const payload = authorization
1844
- ? Credential.deserialize<SessionCredentialPayload>(authorization).payload
1845
- : undefined
1846
-
1847
- if (!payload)
1848
- return Promise.resolve(
1849
- make402Response(makeChallenge({ amount: '1', suggestedDeposit: '2' })),
1850
- )
1851
- if (payload.action === 'open') {
1852
- return Promise.resolve(
1853
- new Response('ok', {
1854
- status: 200,
1855
- headers: {
1856
- 'Payment-Receipt': serializeSessionReceipt(
1857
- createSessionReceipt({
1858
- acceptedCumulative: BigInt(payload.cumulativeAmount),
1859
- challengeId,
1860
- channelId: payload.channelId,
1861
- spent: 1n,
1862
- units: 1,
1863
- }),
1864
- ),
1865
- },
1866
- }),
1867
- )
1868
- }
1869
- if (payload.action === 'close') {
1870
- return Promise.resolve(
1871
- new Response('close failed', {
1872
- status: 500,
1873
- headers: {
1874
- 'WWW-Authenticate': 'Payment error="close_failed"',
1875
- },
1876
- }),
1877
- )
1878
- }
1879
- return Promise.resolve(makeOkResponse())
1880
- })
1881
-
1882
- const s = sessionManager({
1883
- account,
1884
- client,
1885
- decimals: 0,
1886
- fetch: mockFetch as typeof globalThis.fetch,
1887
- maxDeposit: '2',
1888
- })
1889
-
1890
- const response = await s.fetch('https://api.example.com/resource')
1891
- expect(response.status).toBe(200)
1892
- expect(response.receipt?.spent).toBe('1')
1893
-
1894
- await expect(s.close()).rejects.toThrow(
1895
- 'Close request failed with status 500: close failed [WWW-Authenticate: Payment error="close_failed"]',
1896
- )
1897
- })
1898
- })
1899
- })