mppx 0.6.31 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (477) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/Challenge.d.ts.map +1 -1
  3. package/dist/Challenge.js +9 -7
  4. package/dist/Challenge.js.map +1 -1
  5. package/dist/Constants.d.ts +46 -0
  6. package/dist/Constants.d.ts.map +1 -0
  7. package/dist/Constants.js +46 -0
  8. package/dist/Constants.js.map +1 -0
  9. package/dist/Credential.d.ts.map +1 -1
  10. package/dist/Credential.js +5 -4
  11. package/dist/Credential.js.map +1 -1
  12. package/dist/Method.d.ts +32 -4
  13. package/dist/Method.d.ts.map +1 -1
  14. package/dist/Method.js +5 -2
  15. package/dist/Method.js.map +1 -1
  16. package/dist/Receipt.d.ts.map +1 -1
  17. package/dist/Receipt.js +3 -2
  18. package/dist/Receipt.js.map +1 -1
  19. package/dist/cli/cli.d.ts.map +1 -1
  20. package/dist/cli/cli.js +19 -11
  21. package/dist/cli/cli.js.map +1 -1
  22. package/dist/cli/plugins/tempo.d.ts.map +1 -1
  23. package/dist/cli/plugins/tempo.js +17 -6
  24. package/dist/cli/plugins/tempo.js.map +1 -1
  25. package/dist/cli/utils.d.ts +5 -0
  26. package/dist/cli/utils.d.ts.map +1 -1
  27. package/dist/cli/utils.js +10 -0
  28. package/dist/cli/utils.js.map +1 -1
  29. package/dist/client/Methods.d.ts +5 -2
  30. package/dist/client/Methods.d.ts.map +1 -1
  31. package/dist/client/Methods.js +5 -2
  32. package/dist/client/Methods.js.map +1 -1
  33. package/dist/client/Transport.d.ts.map +1 -1
  34. package/dist/client/Transport.js +4 -5
  35. package/dist/client/Transport.js.map +1 -1
  36. package/dist/client/index.d.ts +2 -1
  37. package/dist/client/index.d.ts.map +1 -1
  38. package/dist/client/index.js +2 -1
  39. package/dist/client/index.js.map +1 -1
  40. package/dist/client/internal/Fetch.d.ts.map +1 -1
  41. package/dist/client/internal/Fetch.js +14 -6
  42. package/dist/client/internal/Fetch.js.map +1 -1
  43. package/dist/evm/server/Methods.d.ts +1 -1
  44. package/dist/evm/server/Methods.d.ts.map +1 -1
  45. package/dist/index.d.ts +1 -0
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +1 -0
  48. package/dist/index.js.map +1 -1
  49. package/dist/internal/AcceptPayment.d.ts +3 -0
  50. package/dist/internal/AcceptPayment.d.ts.map +1 -1
  51. package/dist/internal/AcceptPayment.js +15 -11
  52. package/dist/internal/AcceptPayment.js.map +1 -1
  53. package/dist/mcp-sdk/client/McpClient.d.ts +12 -5
  54. package/dist/mcp-sdk/client/McpClient.d.ts.map +1 -1
  55. package/dist/mcp-sdk/client/McpClient.js +55 -42
  56. package/dist/mcp-sdk/client/McpClient.js.map +1 -1
  57. package/dist/server/Mppx.d.ts +11 -3
  58. package/dist/server/Mppx.d.ts.map +1 -1
  59. package/dist/server/Mppx.js +76 -27
  60. package/dist/server/Mppx.js.map +1 -1
  61. package/dist/server/Response.d.ts.map +1 -1
  62. package/dist/server/Response.js +2 -1
  63. package/dist/server/Response.js.map +1 -1
  64. package/dist/server/Transport.d.ts.map +1 -1
  65. package/dist/server/Transport.js +4 -3
  66. package/dist/server/Transport.js.map +1 -1
  67. package/dist/server/index.d.ts +1 -0
  68. package/dist/server/index.d.ts.map +1 -1
  69. package/dist/server/index.js +1 -0
  70. package/dist/server/index.js.map +1 -1
  71. package/dist/stripe/client/Charge.d.ts +1 -1
  72. package/dist/stripe/client/Charge.d.ts.map +1 -1
  73. package/dist/stripe/client/Charge.js +3 -1
  74. package/dist/stripe/client/Charge.js.map +1 -1
  75. package/dist/stripe/server/Charge.d.ts +1 -1
  76. package/dist/stripe/server/Charge.d.ts.map +1 -1
  77. package/dist/stripe/server/Charge.js +9 -2
  78. package/dist/stripe/server/Charge.js.map +1 -1
  79. package/dist/stripe/server/Methods.d.ts +1 -1
  80. package/dist/stripe/server/Methods.d.ts.map +1 -1
  81. package/dist/stripe/server/internal/html.gen.d.ts +1 -1
  82. package/dist/stripe/server/internal/html.gen.d.ts.map +1 -1
  83. package/dist/stripe/server/internal/html.gen.js +1 -1
  84. package/dist/stripe/server/internal/html.gen.js.map +1 -1
  85. package/dist/tempo/Methods.d.ts +18 -0
  86. package/dist/tempo/Methods.d.ts.map +1 -1
  87. package/dist/tempo/Methods.js +16 -1
  88. package/dist/tempo/Methods.js.map +1 -1
  89. package/dist/tempo/client/Charge.d.ts +6 -0
  90. package/dist/tempo/client/Charge.d.ts.map +1 -1
  91. package/dist/tempo/client/Charge.js +9 -2
  92. package/dist/tempo/client/Charge.js.map +1 -1
  93. package/dist/tempo/client/Methods.d.ts +36 -7
  94. package/dist/tempo/client/Methods.d.ts.map +1 -1
  95. package/dist/tempo/client/Methods.js +12 -5
  96. package/dist/tempo/client/Methods.js.map +1 -1
  97. package/dist/tempo/client/index.d.ts +7 -4
  98. package/dist/tempo/client/index.d.ts.map +1 -1
  99. package/dist/tempo/client/index.js +5 -3
  100. package/dist/tempo/client/index.js.map +1 -1
  101. package/dist/tempo/index.d.ts +1 -0
  102. package/dist/tempo/index.d.ts.map +1 -1
  103. package/dist/tempo/index.js +1 -0
  104. package/dist/tempo/index.js.map +1 -1
  105. package/dist/tempo/internal/fee-payer.d.ts +21 -1
  106. package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
  107. package/dist/tempo/internal/fee-payer.js +109 -4
  108. package/dist/tempo/internal/fee-payer.js.map +1 -1
  109. package/dist/tempo/{client → legacy/client}/ChannelOps.d.ts +19 -6
  110. package/dist/tempo/legacy/client/ChannelOps.d.ts.map +1 -0
  111. package/dist/tempo/{client → legacy/client}/ChannelOps.js +9 -3
  112. package/dist/tempo/legacy/client/ChannelOps.js.map +1 -0
  113. package/dist/tempo/{client → legacy/client}/Session.d.ts +23 -4
  114. package/dist/tempo/legacy/client/Session.d.ts.map +1 -0
  115. package/dist/tempo/{client → legacy/client}/Session.js +14 -7
  116. package/dist/tempo/legacy/client/Session.js.map +1 -0
  117. package/dist/tempo/{client → legacy/client}/SessionManager.d.ts +20 -5
  118. package/dist/tempo/legacy/client/SessionManager.d.ts.map +1 -0
  119. package/dist/tempo/{client → legacy/client}/SessionManager.js +20 -16
  120. package/dist/tempo/legacy/client/SessionManager.js.map +1 -0
  121. package/dist/tempo/legacy/client/index.d.ts +7 -0
  122. package/dist/tempo/legacy/client/index.d.ts.map +1 -0
  123. package/dist/tempo/legacy/client/index.js +5 -0
  124. package/dist/tempo/legacy/client/index.js.map +1 -0
  125. package/dist/tempo/legacy/index.d.ts +7 -0
  126. package/dist/tempo/legacy/index.d.ts.map +1 -0
  127. package/dist/tempo/legacy/index.js +7 -0
  128. package/dist/tempo/legacy/index.js.map +1 -0
  129. package/dist/tempo/{server → legacy/server}/Session.d.ts +28 -11
  130. package/dist/tempo/legacy/server/Session.d.ts.map +1 -0
  131. package/dist/tempo/{server → legacy/server}/Session.js +12 -10
  132. package/dist/tempo/legacy/server/Session.js.map +1 -0
  133. package/dist/tempo/legacy/server/index.d.ts +5 -0
  134. package/dist/tempo/legacy/server/index.d.ts.map +1 -0
  135. package/dist/tempo/legacy/server/index.js +5 -0
  136. package/dist/tempo/legacy/server/index.js.map +1 -0
  137. package/dist/tempo/{session → legacy/session}/Chain.d.ts +30 -23
  138. package/dist/tempo/legacy/session/Chain.d.ts.map +1 -0
  139. package/dist/tempo/{session → legacy/session}/Chain.js +12 -11
  140. package/dist/tempo/legacy/session/Chain.js.map +1 -0
  141. package/dist/tempo/{session → legacy/session}/Channel.d.ts +1 -0
  142. package/dist/tempo/legacy/session/Channel.d.ts.map +1 -0
  143. package/dist/tempo/legacy/session/Channel.js.map +1 -0
  144. package/dist/tempo/legacy/session/ChannelStore.d.ts +22 -0
  145. package/dist/tempo/legacy/session/ChannelStore.d.ts.map +1 -0
  146. package/dist/tempo/legacy/session/ChannelStore.js +6 -0
  147. package/dist/tempo/legacy/session/ChannelStore.js.map +1 -0
  148. package/dist/tempo/legacy/session/Types.d.ts +73 -0
  149. package/dist/tempo/legacy/session/Types.d.ts.map +1 -0
  150. package/dist/tempo/legacy/session/Types.js.map +1 -0
  151. package/dist/tempo/{session → legacy/session}/Voucher.d.ts +4 -4
  152. package/dist/tempo/legacy/session/Voucher.d.ts.map +1 -0
  153. package/dist/tempo/{session → legacy/session}/Voucher.js +1 -1
  154. package/dist/tempo/legacy/session/Voucher.js.map +1 -0
  155. package/dist/tempo/{session → legacy/session}/escrow.abi.d.ts +1 -0
  156. package/dist/tempo/{session → legacy/session}/escrow.abi.d.ts.map +1 -1
  157. package/dist/tempo/{session → legacy/session}/escrow.abi.js +1 -0
  158. package/dist/tempo/legacy/session/escrow.abi.js.map +1 -0
  159. package/dist/tempo/legacy/session/index.d.ts +9 -0
  160. package/dist/tempo/legacy/session/index.d.ts.map +1 -0
  161. package/dist/tempo/legacy/session/index.js +9 -0
  162. package/dist/tempo/legacy/session/index.js.map +1 -0
  163. package/dist/tempo/server/Charge.d.ts +1 -1
  164. package/dist/tempo/server/Charge.d.ts.map +1 -1
  165. package/dist/tempo/server/Charge.js +13 -16
  166. package/dist/tempo/server/Charge.js.map +1 -1
  167. package/dist/tempo/server/Methods.d.ts +63 -6
  168. package/dist/tempo/server/Methods.d.ts.map +1 -1
  169. package/dist/tempo/server/Methods.js +36 -8
  170. package/dist/tempo/server/Methods.js.map +1 -1
  171. package/dist/tempo/server/Subscription.d.ts +1 -1
  172. package/dist/tempo/server/Subscription.d.ts.map +1 -1
  173. package/dist/tempo/server/index.d.ts +6 -5
  174. package/dist/tempo/server/index.d.ts.map +1 -1
  175. package/dist/tempo/server/index.js +5 -5
  176. package/dist/tempo/server/index.js.map +1 -1
  177. package/dist/tempo/server/internal/html.gen.d.ts +1 -1
  178. package/dist/tempo/server/internal/html.gen.d.ts.map +1 -1
  179. package/dist/tempo/server/internal/html.gen.js +1 -1
  180. package/dist/tempo/server/internal/html.gen.js.map +1 -1
  181. package/dist/tempo/server/internal/request-body.d.ts +7 -2
  182. package/dist/tempo/server/internal/request-body.d.ts.map +1 -1
  183. package/dist/tempo/server/internal/request-body.js +20 -3
  184. package/dist/tempo/server/internal/request-body.js.map +1 -1
  185. package/dist/tempo/server/internal/transport.d.ts +8 -4
  186. package/dist/tempo/server/internal/transport.d.ts.map +1 -1
  187. package/dist/tempo/server/internal/transport.js +8 -7
  188. package/dist/tempo/server/internal/transport.js.map +1 -1
  189. package/dist/tempo/session/Snapshot.d.ts +32 -0
  190. package/dist/tempo/session/Snapshot.d.ts.map +1 -0
  191. package/dist/tempo/session/Snapshot.js +37 -0
  192. package/dist/tempo/session/Snapshot.js.map +1 -0
  193. package/dist/tempo/session/client/ChannelOps.d.ts +82 -0
  194. package/dist/tempo/session/client/ChannelOps.d.ts.map +1 -0
  195. package/dist/tempo/session/client/ChannelOps.js +204 -0
  196. package/dist/tempo/session/client/ChannelOps.js.map +1 -0
  197. package/dist/tempo/session/client/CredentialState.d.ts +262 -0
  198. package/dist/tempo/session/client/CredentialState.d.ts.map +1 -0
  199. package/dist/tempo/session/client/CredentialState.js +417 -0
  200. package/dist/tempo/session/client/CredentialState.js.map +1 -0
  201. package/dist/tempo/session/client/ReceiptCoordinator.d.ts +26 -0
  202. package/dist/tempo/session/client/ReceiptCoordinator.d.ts.map +1 -0
  203. package/dist/tempo/session/client/ReceiptCoordinator.js +61 -0
  204. package/dist/tempo/session/client/ReceiptCoordinator.js.map +1 -0
  205. package/dist/tempo/session/client/Runtime.d.ts +464 -0
  206. package/dist/tempo/session/client/Runtime.d.ts.map +1 -0
  207. package/dist/tempo/session/client/Runtime.js +499 -0
  208. package/dist/tempo/session/client/Runtime.js.map +1 -0
  209. package/dist/tempo/session/client/Session.d.ts +132 -0
  210. package/dist/tempo/session/client/Session.d.ts.map +1 -0
  211. package/dist/tempo/session/client/Session.js +55 -0
  212. package/dist/tempo/session/client/Session.js.map +1 -0
  213. package/dist/tempo/session/client/SessionManager.d.ts +120 -0
  214. package/dist/tempo/session/client/SessionManager.d.ts.map +1 -0
  215. package/dist/tempo/session/client/SessionManager.js +627 -0
  216. package/dist/tempo/session/client/SessionManager.js.map +1 -0
  217. package/dist/tempo/session/client/Transports.d.ts +449 -0
  218. package/dist/tempo/session/client/Transports.d.ts.map +1 -0
  219. package/dist/tempo/session/client/Transports.js +721 -0
  220. package/dist/tempo/session/client/Transports.js.map +1 -0
  221. package/dist/tempo/session/client/index.d.ts +12 -0
  222. package/dist/tempo/session/client/index.d.ts.map +1 -0
  223. package/dist/tempo/session/client/index.js +5 -0
  224. package/dist/tempo/session/client/index.js.map +1 -0
  225. package/dist/tempo/session/index.d.ts +7 -8
  226. package/dist/tempo/session/index.d.ts.map +1 -1
  227. package/dist/tempo/session/index.js +7 -8
  228. package/dist/tempo/session/index.js.map +1 -1
  229. package/dist/tempo/session/precompile/Chain.d.ts +319 -0
  230. package/dist/tempo/session/precompile/Chain.d.ts.map +1 -0
  231. package/dist/tempo/session/precompile/Chain.js +492 -0
  232. package/dist/tempo/session/precompile/Chain.js.map +1 -0
  233. package/dist/tempo/session/precompile/Channel.d.ts +46 -0
  234. package/dist/tempo/session/precompile/Channel.d.ts.map +1 -0
  235. package/dist/tempo/session/precompile/Channel.js +56 -0
  236. package/dist/tempo/session/precompile/Channel.js.map +1 -0
  237. package/dist/tempo/session/precompile/Protocol.d.ts +308 -0
  238. package/dist/tempo/session/precompile/Protocol.d.ts.map +1 -0
  239. package/dist/tempo/session/precompile/Protocol.js +264 -0
  240. package/dist/tempo/session/precompile/Protocol.js.map +1 -0
  241. package/dist/tempo/session/precompile/Voucher.d.ts +40 -0
  242. package/dist/tempo/session/precompile/Voucher.d.ts.map +1 -0
  243. package/dist/tempo/session/precompile/Voucher.js +126 -0
  244. package/dist/tempo/session/precompile/Voucher.js.map +1 -0
  245. package/dist/tempo/session/precompile/escrow.abi.d.ts +522 -0
  246. package/dist/tempo/session/precompile/escrow.abi.d.ts.map +1 -0
  247. package/dist/tempo/session/precompile/escrow.abi.js +224 -0
  248. package/dist/tempo/session/precompile/escrow.abi.js.map +1 -0
  249. package/dist/tempo/session/precompile/index.d.ts +24 -0
  250. package/dist/tempo/session/precompile/index.d.ts.map +1 -0
  251. package/dist/tempo/session/precompile/index.js +22 -0
  252. package/dist/tempo/session/precompile/index.js.map +1 -0
  253. package/dist/tempo/session/server/ChannelOps.d.ts +56 -0
  254. package/dist/tempo/session/server/ChannelOps.d.ts.map +1 -0
  255. package/dist/tempo/session/server/ChannelOps.js +91 -0
  256. package/dist/tempo/session/server/ChannelOps.js.map +1 -0
  257. package/dist/tempo/session/server/ChannelStore.d.ts +347 -0
  258. package/dist/tempo/session/server/ChannelStore.d.ts.map +1 -0
  259. package/dist/tempo/session/server/ChannelStore.js +404 -0
  260. package/dist/tempo/session/server/ChannelStore.js.map +1 -0
  261. package/dist/tempo/session/server/CredentialVerification.d.ts +85 -0
  262. package/dist/tempo/session/server/CredentialVerification.d.ts.map +1 -0
  263. package/dist/tempo/session/server/CredentialVerification.js +494 -0
  264. package/dist/tempo/session/server/CredentialVerification.js.map +1 -0
  265. package/dist/tempo/session/server/MeteredStream.d.ts +40 -0
  266. package/dist/tempo/session/server/MeteredStream.d.ts.map +1 -0
  267. package/dist/tempo/session/server/MeteredStream.js +42 -0
  268. package/dist/tempo/session/server/MeteredStream.js.map +1 -0
  269. package/dist/tempo/session/server/RequestState.d.ts +208 -0
  270. package/dist/tempo/session/server/RequestState.d.ts.map +1 -0
  271. package/dist/tempo/session/server/RequestState.js +252 -0
  272. package/dist/tempo/session/server/RequestState.js.map +1 -0
  273. package/dist/tempo/session/server/Session.d.ts +169 -0
  274. package/dist/tempo/session/server/Session.d.ts.map +1 -0
  275. package/dist/tempo/session/server/Session.js +351 -0
  276. package/dist/tempo/session/server/Session.js.map +1 -0
  277. package/dist/tempo/session/server/Settlement.d.ts +185 -0
  278. package/dist/tempo/session/server/Settlement.d.ts.map +1 -0
  279. package/dist/tempo/session/server/Settlement.js +250 -0
  280. package/dist/tempo/session/server/Settlement.js.map +1 -0
  281. package/dist/tempo/session/{Sse.d.ts → server/Sse.d.ts} +9 -56
  282. package/dist/tempo/session/server/Sse.d.ts.map +1 -0
  283. package/dist/tempo/session/server/Sse.js +184 -0
  284. package/dist/tempo/session/server/Sse.js.map +1 -0
  285. package/dist/tempo/session/server/Transports.d.ts +89 -0
  286. package/dist/tempo/session/server/Transports.d.ts.map +1 -0
  287. package/dist/tempo/session/server/Transports.js +149 -0
  288. package/dist/tempo/session/server/Transports.js.map +1 -0
  289. package/dist/tempo/session/server/Ws.d.ts +48 -0
  290. package/dist/tempo/session/server/Ws.d.ts.map +1 -0
  291. package/dist/tempo/session/server/Ws.js +244 -0
  292. package/dist/tempo/session/server/Ws.js.map +1 -0
  293. package/dist/tempo/session/server/index.d.ts +4 -0
  294. package/dist/tempo/session/server/index.d.ts.map +1 -0
  295. package/dist/tempo/session/server/index.js +2 -0
  296. package/dist/tempo/session/server/index.js.map +1 -0
  297. package/package.json +6 -1
  298. package/src/Challenge.ts +9 -7
  299. package/src/Constants.ts +58 -0
  300. package/src/Credential.ts +5 -4
  301. package/src/Method.ts +46 -5
  302. package/src/Receipt.ts +3 -2
  303. package/src/cli/cli.test.ts +23 -28
  304. package/src/cli/cli.ts +23 -10
  305. package/src/cli/mcp.test.ts +21 -7
  306. package/src/cli/plugins/tempo.ts +21 -8
  307. package/src/cli/utils.test.ts +25 -1
  308. package/src/cli/utils.ts +10 -0
  309. package/src/client/Methods.ts +5 -2
  310. package/src/client/Mppx.test-d.ts +10 -0
  311. package/src/client/Mppx.test.ts +75 -0
  312. package/src/client/Transport.ts +4 -5
  313. package/src/client/index.ts +11 -1
  314. package/src/client/internal/Fetch.test.ts +29 -4
  315. package/src/client/internal/Fetch.ts +17 -5
  316. package/src/env.d.ts +1 -1
  317. package/src/index.ts +1 -0
  318. package/src/internal/AcceptPayment.test.ts +61 -0
  319. package/src/internal/AcceptPayment.ts +21 -14
  320. package/src/mcp-sdk/client/McpClient.integration.test.ts +8 -7
  321. package/src/mcp-sdk/client/McpClient.test-d.ts +7 -0
  322. package/src/mcp-sdk/client/McpClient.ts +99 -67
  323. package/src/mcp-sdk/client/McpClient.unit.test.ts +131 -0
  324. package/src/middlewares/elysia.test.ts +8 -4
  325. package/src/middlewares/express.test.ts +8 -4
  326. package/src/middlewares/hono.test.ts +4 -4
  327. package/src/middlewares/nextjs.test.ts +8 -4
  328. package/src/proxy/Proxy.test.ts +8 -8
  329. package/src/server/Mppx.test-d.ts +54 -0
  330. package/src/server/Mppx.test.ts +200 -7
  331. package/src/server/Mppx.ts +487 -406
  332. package/src/server/Response.ts +2 -1
  333. package/src/server/Transport.ts +4 -3
  334. package/src/server/index.ts +1 -0
  335. package/src/stripe/client/Charge.test.ts +20 -5
  336. package/src/stripe/client/Charge.ts +6 -2
  337. package/src/stripe/server/Charge.test.ts +114 -1
  338. package/src/stripe/server/Charge.ts +13 -2
  339. package/src/stripe/server/internal/html.gen.ts +1 -1
  340. package/src/tempo/AccessKeyAuthorization.test.ts +4 -94
  341. package/src/tempo/Methods.test.ts +45 -17
  342. package/src/tempo/Methods.ts +22 -0
  343. package/src/tempo/PublicExports.test-d.ts +105 -0
  344. package/src/tempo/client/Charge.test.ts +85 -0
  345. package/src/tempo/client/Charge.ts +19 -2
  346. package/src/tempo/client/Methods.ts +18 -6
  347. package/src/tempo/client/index.ts +15 -4
  348. package/src/tempo/index.ts +1 -0
  349. package/src/tempo/internal/fee-payer.test.ts +241 -17
  350. package/src/tempo/internal/fee-payer.ts +150 -4
  351. package/src/tempo/internal/fee-token.test.ts +14 -9
  352. package/src/tempo/legacy/AccessKeyAuthorization.test.ts +162 -0
  353. package/src/tempo/legacy/README.md +9 -0
  354. package/src/tempo/{client → legacy/client}/ChannelOps.test.ts +6 -7
  355. package/src/tempo/{client → legacy/client}/ChannelOps.ts +22 -9
  356. package/src/tempo/{client → legacy/client}/Session.test.ts +51 -9
  357. package/src/tempo/{client → legacy/client}/Session.ts +25 -11
  358. package/src/tempo/{client → legacy/client}/SessionManager.test.ts +81 -9
  359. package/src/tempo/{client → legacy/client}/SessionManager.ts +41 -20
  360. package/src/tempo/legacy/client/index.ts +6 -0
  361. package/src/tempo/legacy/index.ts +6 -0
  362. package/src/tempo/{server → legacy/server}/Session.test.ts +45 -45
  363. package/src/tempo/{server → legacy/server}/Session.ts +32 -23
  364. package/src/tempo/legacy/server/index.ts +4 -0
  365. package/src/tempo/{session → legacy/session}/Chain.test.ts +3 -4
  366. package/src/tempo/{session → legacy/session}/Chain.ts +94 -63
  367. package/src/tempo/{session → legacy/session}/Channel.ts +1 -0
  368. package/src/tempo/legacy/session/ChannelStore.test.ts +58 -0
  369. package/src/tempo/legacy/session/ChannelStore.ts +39 -0
  370. package/src/tempo/legacy/session/Types.ts +91 -0
  371. package/src/tempo/{session → legacy/session}/Voucher.ts +12 -8
  372. package/src/tempo/{session → legacy/session}/escrow.abi.ts +1 -0
  373. package/src/tempo/legacy/session/index.ts +8 -0
  374. package/src/tempo/server/AtomicStore.test-d.ts +16 -11
  375. package/src/tempo/server/Charge.test.ts +92 -14
  376. package/src/tempo/server/Charge.ts +18 -16
  377. package/src/tempo/server/Methods.ts +54 -8
  378. package/src/tempo/server/Sse.test.ts +2 -2
  379. package/src/tempo/server/index.ts +6 -5
  380. package/src/tempo/server/internal/html.gen.ts +1 -1
  381. package/src/tempo/server/internal/request-body.test.ts +37 -4
  382. package/src/tempo/server/internal/request-body.ts +25 -6
  383. package/src/tempo/server/internal/transport.test.ts +4 -4
  384. package/src/tempo/server/internal/transport.ts +19 -10
  385. package/src/tempo/session/Snapshot.test.ts +41 -0
  386. package/src/tempo/session/Snapshot.ts +74 -0
  387. package/src/tempo/session/client/ChannelOps.test.ts +163 -0
  388. package/src/tempo/session/client/ChannelOps.ts +344 -0
  389. package/src/tempo/session/client/CredentialState.test.ts +645 -0
  390. package/src/tempo/session/client/CredentialState.ts +814 -0
  391. package/src/tempo/session/client/ReceiptCoordinator.ts +95 -0
  392. package/src/tempo/session/client/Runtime.test.ts +1092 -0
  393. package/src/tempo/session/client/Runtime.ts +986 -0
  394. package/src/tempo/session/client/Session.test.ts +734 -0
  395. package/src/tempo/session/client/Session.ts +97 -0
  396. package/src/tempo/session/client/SessionManager.test.ts +1308 -0
  397. package/src/tempo/session/client/SessionManager.ts +845 -0
  398. package/src/tempo/session/client/Transports.test.ts +837 -0
  399. package/src/tempo/session/client/Transports.ts +1292 -0
  400. package/src/tempo/session/client/index.ts +37 -0
  401. package/src/tempo/session/index.ts +7 -8
  402. package/src/tempo/session/precompile/Chain.integration.test.ts +321 -0
  403. package/src/tempo/session/precompile/Chain.test.ts +1258 -0
  404. package/src/tempo/session/precompile/Chain.ts +979 -0
  405. package/src/tempo/session/precompile/Channel.test.ts +138 -0
  406. package/src/tempo/session/precompile/Channel.ts +103 -0
  407. package/src/tempo/session/precompile/Protocol.test.ts +358 -0
  408. package/src/tempo/session/precompile/Protocol.ts +520 -0
  409. package/src/tempo/session/precompile/Voucher.test.ts +316 -0
  410. package/src/tempo/session/precompile/Voucher.ts +160 -0
  411. package/src/tempo/session/precompile/escrow.abi.ts +226 -0
  412. package/src/tempo/session/precompile/index.ts +33 -0
  413. package/src/tempo/session/server/ChannelOps.test.ts +129 -0
  414. package/src/tempo/session/server/ChannelOps.ts +157 -0
  415. package/src/tempo/session/{ChannelStore.test.ts → server/ChannelStore.test.ts} +536 -29
  416. package/src/tempo/session/server/ChannelStore.ts +835 -0
  417. package/src/tempo/session/server/CredentialVerification.test.ts +146 -0
  418. package/src/tempo/session/server/CredentialVerification.ts +710 -0
  419. package/src/tempo/session/server/MeteredStream.ts +88 -0
  420. package/src/tempo/session/server/RequestState.test.ts +531 -0
  421. package/src/tempo/session/server/RequestState.ts +499 -0
  422. package/src/tempo/session/server/Session.integration.test.ts +444 -0
  423. package/src/tempo/session/server/Session.test.ts +3253 -0
  424. package/src/tempo/session/server/Session.ts +543 -0
  425. package/src/tempo/session/server/Settlement.test.ts +242 -0
  426. package/src/tempo/session/server/Settlement.ts +470 -0
  427. package/src/tempo/session/{Sse.test.ts → server/Sse.test.ts} +37 -3
  428. package/src/tempo/session/server/Sse.ts +256 -0
  429. package/src/tempo/session/server/Transports.test.ts +346 -0
  430. package/src/tempo/session/server/Transports.ts +255 -0
  431. package/src/tempo/session/{Ws.test.ts → server/Ws.test.ts} +4 -4
  432. package/src/tempo/session/server/Ws.ts +384 -0
  433. package/src/tempo/session/server/index.ts +8 -0
  434. package/dist/tempo/client/ChannelOps.d.ts.map +0 -1
  435. package/dist/tempo/client/ChannelOps.js.map +0 -1
  436. package/dist/tempo/client/Session.d.ts.map +0 -1
  437. package/dist/tempo/client/Session.js.map +0 -1
  438. package/dist/tempo/client/SessionManager.d.ts.map +0 -1
  439. package/dist/tempo/client/SessionManager.js.map +0 -1
  440. package/dist/tempo/server/Session.d.ts.map +0 -1
  441. package/dist/tempo/server/Session.js.map +0 -1
  442. package/dist/tempo/session/Chain.d.ts.map +0 -1
  443. package/dist/tempo/session/Chain.js.map +0 -1
  444. package/dist/tempo/session/Channel.d.ts.map +0 -1
  445. package/dist/tempo/session/Channel.js.map +0 -1
  446. package/dist/tempo/session/ChannelStore.d.ts +0 -117
  447. package/dist/tempo/session/ChannelStore.d.ts.map +0 -1
  448. package/dist/tempo/session/ChannelStore.js +0 -172
  449. package/dist/tempo/session/ChannelStore.js.map +0 -1
  450. package/dist/tempo/session/Receipt.d.ts +0 -22
  451. package/dist/tempo/session/Receipt.d.ts.map +0 -1
  452. package/dist/tempo/session/Receipt.js +0 -34
  453. package/dist/tempo/session/Receipt.js.map +0 -1
  454. package/dist/tempo/session/Sse.d.ts.map +0 -1
  455. package/dist/tempo/session/Sse.js +0 -363
  456. package/dist/tempo/session/Sse.js.map +0 -1
  457. package/dist/tempo/session/Types.d.ts +0 -78
  458. package/dist/tempo/session/Types.d.ts.map +0 -1
  459. package/dist/tempo/session/Types.js.map +0 -1
  460. package/dist/tempo/session/Voucher.d.ts.map +0 -1
  461. package/dist/tempo/session/Voucher.js.map +0 -1
  462. package/dist/tempo/session/Ws.d.ts +0 -87
  463. package/dist/tempo/session/Ws.d.ts.map +0 -1
  464. package/dist/tempo/session/Ws.js +0 -443
  465. package/dist/tempo/session/Ws.js.map +0 -1
  466. package/dist/tempo/session/escrow.abi.js.map +0 -1
  467. package/src/tempo/session/ChannelStore.ts +0 -308
  468. package/src/tempo/session/Receipt.test.ts +0 -89
  469. package/src/tempo/session/Receipt.ts +0 -46
  470. package/src/tempo/session/Sse.ts +0 -462
  471. package/src/tempo/session/Types.ts +0 -86
  472. package/src/tempo/session/Ws.ts +0 -576
  473. /package/dist/tempo/{session → legacy/session}/Channel.js +0 -0
  474. /package/dist/tempo/{session → legacy/session}/Types.js +0 -0
  475. /package/src/tempo/{session → legacy/session}/Channel.test.ts +0 -0
  476. /package/src/tempo/{session → legacy/session}/Voucher.test.ts +0 -0
  477. /package/src/tempo/session/{Sse.fuzz.test.ts → server/Sse.fuzz.test.ts} +0 -0
@@ -0,0 +1,845 @@
1
+ import type { Hex } from 'ox'
2
+ import { parseUnits, type Address } from 'viem'
3
+
4
+ import * as Challenge from '../../../Challenge.js'
5
+ import * as Fetch from '../../../client/internal/Fetch.js'
6
+ import * as Constants from '../../../Constants.js'
7
+ import type * as Account from '../../../viem/Account.js'
8
+ import type * as Client from '../../../viem/Client.js'
9
+ import { charge as chargePlugin } from '../../client/Charge.js'
10
+ import type { ChannelEntry } from '../client/ChannelOps.js'
11
+ import type { SessionContext } from '../client/CredentialState.js'
12
+ import { session as sessionPlugin } from '../client/Session.js'
13
+ import type { ChannelDescriptor } from '../precompile/Protocol.js'
14
+ import { deserializeSessionReceipt } from '../precompile/Protocol.js'
15
+ import { readSessionChallengeAmount, type SessionReceipt } from '../precompile/Protocol.js'
16
+ import {
17
+ deserializeSnapshot as deserializeSessionSnapshot,
18
+ serializeSnapshot as serializeSessionSnapshot,
19
+ } from '../Snapshot.js'
20
+ import { createSessionReceiptCoordinator } from './ReceiptCoordinator.js'
21
+ import { resolveCloseTarget, type CloseTarget } from './Runtime.js'
22
+ import { assertVoucherWithinLocalLimit as assertVoucherWithinLocalAuthorization } from './Runtime.js'
23
+ import type { SessionState } from './Runtime.js'
24
+ import {
25
+ applySessionReceiptToRuntime,
26
+ captureRuntimeSnapshot as captureRuntimeStateSnapshot,
27
+ computeFallbackCloseAmount,
28
+ createSessionManagerRuntime,
29
+ dispatchSessionEvent,
30
+ restoreCumulativeAuthorization,
31
+ restoreRuntimeSnapshot as restoreRuntimeStateSnapshot,
32
+ type RuntimeSnapshot,
33
+ } from './Runtime.js'
34
+ import { closeSocketSession } from './Runtime.js'
35
+ import {
36
+ closeHttpSession,
37
+ getSessionSnapshot,
38
+ isTempoSessionChallenge,
39
+ managementInput,
40
+ postTopUp,
41
+ retryHttpPaymentRequired,
42
+ type TempoSessionChallenge,
43
+ webSocketProbeUrl,
44
+ } from './Transports.js'
45
+ import {
46
+ type SessionManagedWebSocket,
47
+ type WebSocketConstructor,
48
+ WebSocketReadyState,
49
+ } from './Transports.js'
50
+ import { openSseSession, type SseDriverOptions } from './Transports.js'
51
+ import { applyTopUpResult, resolveManualTopUp, type TopUpRequirement } from './Transports.js'
52
+ import {
53
+ openWebSocketSession,
54
+ prepareWebSocketSession,
55
+ type WebSocketDriverOptions,
56
+ } from './Transports.js'
57
+
58
+ export { computeFallbackCloseAmount, type FallbackCloseAmountParameters } from './Runtime.js'
59
+
60
+ /** Auto-driving client manager for HTTP, SSE, and WebSocket TIP-1034 sessions. */
61
+ export type SessionManager = {
62
+ /** Active channel ID, when a channel has been opened or recovered. */
63
+ readonly channelId: Hex.Hex | undefined
64
+ /** Local cumulative voucher authorization in raw token units. */
65
+ readonly cumulative: bigint
66
+ /** Whether the manager currently has an open local channel. */
67
+ readonly opened: boolean
68
+ /** Current pure session state-machine state. */
69
+ readonly state: SessionState
70
+
71
+ /** Runs the HTTP 402 probe, signs/open/top-ups as needed, retries, and returns receipt metadata. */
72
+ fetch(input: RequestInfo | URL, init?: RequestInit): Promise<PaymentResponse>
73
+ /** Opens a paid SSE stream and auto-posts vouchers/top-ups when the server requests more headroom. */
74
+ sse(input: RequestInfo | URL, init?: SessionManagerSseOptions): Promise<AsyncIterable<string>>
75
+ /** Opens a paid WebSocket session after an HTTP challenge probe and manages in-band voucher frames. */
76
+ ws(input: string | URL, init?: SessionManagerWebSocketOptions): Promise<SessionManagedWebSocket>
77
+ /** Tops up the active channel deposit. String amounts are parsed with the manager decimals; bigint amounts are raw units. */
78
+ topUp(amount: string | bigint): Promise<SessionReceipt | undefined>
79
+ /** Cooperatively closes the active channel using the latest locally authorized spend boundary. */
80
+ close(): Promise<SessionReceipt | undefined>
81
+ }
82
+
83
+ /** Options for `SessionManager.sse()`. */
84
+ export type SessionManagerSseOptions = SseDriverOptions
85
+
86
+ /** Options for `SessionManager.ws()`. */
87
+ export type SessionManagerWebSocketOptions = WebSocketDriverOptions
88
+
89
+ /** HTTP response enriched with the latest session payment metadata. */
90
+ export type PaymentResponse = Response & {
91
+ /** Parsed payment receipt, when the response included one. */
92
+ receipt: SessionReceipt | null
93
+ /** Last session challenge observed by the manager. */
94
+ challenge: TempoSessionChallenge | null
95
+ /** Active channel ID, when available. */
96
+ channelId: Hex.Hex | null
97
+ /** Local cumulative voucher authorization in raw token units. */
98
+ cumulative: bigint
99
+ }
100
+
101
+ /** Serializable client-side channel snapshot stored between manager instances. */
102
+ export type StoredSessionChannel = {
103
+ /** Latest known channel ID. Used as the next request's channel hint. */
104
+ channelId: Hex.Hex
105
+ /** Latest local cumulative voucher authorization in raw token units. */
106
+ cumulativeAmount: string
107
+ /** Latest known deposit in raw token units. */
108
+ deposit: string
109
+ /** TIP-1034 channel descriptor, used as a fallback when the server cannot snapshot. */
110
+ descriptor: ChannelDescriptor
111
+ /** Escrow address used to derive the channel ID. */
112
+ escrow: Address
113
+ /** Chain ID used to derive the channel ID. */
114
+ chainId: number
115
+ /** Whether the channel was open when stored. Closed channels are not used as hints. */
116
+ opened: boolean
117
+ /** Client timestamp for debugging or app-level eviction. */
118
+ updatedAt: number
119
+ }
120
+
121
+ /** Optional per-manager store for channel hints and restart recovery. */
122
+ export type SessionStore = {
123
+ /** Reads the latest stored channel snapshot for this manager scope. */
124
+ get(): Promise<StoredSessionChannel | null | undefined> | StoredSessionChannel | null | undefined
125
+ /** Persists the latest channel snapshot. */
126
+ set(channel: StoredSessionChannel): Promise<void> | void
127
+ /** Deletes the stored snapshot when a channel is closed, when supported. */
128
+ delete?(): Promise<void> | void
129
+ }
130
+
131
+ /** Normalized runtime dependencies derived from `sessionManager()` parameters. */
132
+ type SessionManagerConfig = {
133
+ /** Decimal precision used when parsing human-readable manager amounts. */
134
+ decimals: number
135
+ /** Fetch implementation used for probes, retries, and management posts. */
136
+ fetch: typeof globalThis.fetch
137
+ /** Local maximum cumulative voucher authorization, or null when uncapped. */
138
+ maxVoucherCumulative: bigint | null
139
+ /** WebSocket constructor available in the current runtime, when configured. */
140
+ WebSocket: WebSocketConstructor | undefined
141
+ }
142
+
143
+ function isTempoChargeChallenge(challenge: Challenge.Challenge) {
144
+ return (
145
+ challenge.method === Constants.Methods.tempo && challenge.intent === Constants.Intents.charge
146
+ )
147
+ }
148
+
149
+ function isZeroAmountChargeChallenge(challenge: Challenge.Challenge) {
150
+ if (!isTempoChargeChallenge(challenge)) return false
151
+ if (typeof challenge.request.amount !== 'string') return false
152
+ try {
153
+ return BigInt(challenge.request.amount) === 0n
154
+ } catch {
155
+ return false
156
+ }
157
+ }
158
+
159
+ function storedChannelFromEntry(entry: ChannelEntry): StoredSessionChannel {
160
+ return {
161
+ channelId: entry.channelId,
162
+ cumulativeAmount: entry.cumulativeAmount.toString(),
163
+ deposit: entry.deposit.toString(),
164
+ descriptor: entry.descriptor,
165
+ escrow: entry.escrow,
166
+ chainId: entry.chainId,
167
+ opened: entry.opened,
168
+ updatedAt: Date.now(),
169
+ }
170
+ }
171
+
172
+ function storedChannelContext(channel: StoredSessionChannel): SessionContext {
173
+ return {
174
+ channelId: channel.channelId,
175
+ cumulativeAmountRaw: channel.cumulativeAmount,
176
+ descriptor: channel.descriptor,
177
+ }
178
+ }
179
+
180
+ function storedChannelFromSnapshot(
181
+ snapshot: ReturnType<typeof deserializeSessionSnapshot>,
182
+ ): StoredSessionChannel {
183
+ return {
184
+ channelId: snapshot.channelId,
185
+ cumulativeAmount: snapshot.acceptedCumulative,
186
+ deposit: snapshot.deposit,
187
+ descriptor: snapshot.descriptor,
188
+ escrow: snapshot.escrow,
189
+ chainId: snapshot.chainId,
190
+ opened: true,
191
+ updatedAt: Date.now(),
192
+ }
193
+ }
194
+
195
+ type CredentialContextResolution = {
196
+ context: SessionContext
197
+ usedStoredChannel: boolean
198
+ }
199
+
200
+ function resolveCredentialContext(parameters: {
201
+ channel: ChannelEntry | null
202
+ challenge: TempoSessionChallenge
203
+ context: SessionContext
204
+ storedChannel: StoredSessionChannel | null
205
+ }): CredentialContextResolution {
206
+ const { channel, challenge, context, storedChannel } = parameters
207
+ if (
208
+ context.action ||
209
+ channel?.opened ||
210
+ !storedChannel?.opened ||
211
+ getSessionSnapshot(challenge)
212
+ ) {
213
+ return { context, usedStoredChannel: false }
214
+ }
215
+ return {
216
+ context: { ...context, ...storedChannelContext(storedChannel) },
217
+ usedStoredChannel: true,
218
+ }
219
+ }
220
+
221
+ function requestInitWithSessionHint(
222
+ input: RequestInfo | URL,
223
+ init: RequestInit | undefined,
224
+ channelId: Hex.Hex | undefined,
225
+ ): RequestInit | undefined {
226
+ if (!channelId) return init
227
+ const requestHeaders = input instanceof Request ? input.headers : undefined
228
+ const headers = {
229
+ ...Fetch.normalizeHeaders(requestHeaders),
230
+ ...Fetch.normalizeHeaders(init?.headers),
231
+ }
232
+ if (
233
+ Object.keys(headers).some(
234
+ (key) => key.toLowerCase() === Constants.Headers.paymentSession.toLowerCase(),
235
+ )
236
+ )
237
+ return init
238
+ return {
239
+ ...init,
240
+ headers: {
241
+ ...headers,
242
+ [Constants.Headers.paymentSession]: channelId,
243
+ },
244
+ }
245
+ }
246
+
247
+ function resolveSessionManagerConfig(parameters: sessionManager.Parameters): SessionManagerConfig {
248
+ const decimals = parameters.decimals ?? 6
249
+ const WebSocket =
250
+ parameters.webSocket ??
251
+ (globalThis as typeof globalThis & { WebSocket?: WebSocketConstructor }).WebSocket
252
+
253
+ return {
254
+ decimals,
255
+ fetch: parameters.fetch ?? globalThis.fetch.bind(globalThis),
256
+ maxVoucherCumulative:
257
+ parameters.maxDeposit !== undefined ? parseUnits(parameters.maxDeposit, decimals) : null,
258
+ WebSocket,
259
+ }
260
+ }
261
+
262
+ /**
263
+ * Creates a session manager that handles the full client payment lifecycle:
264
+ * channel open, incremental vouchers, SSE streaming, and channel close.
265
+ *
266
+ * Internally delegates to the `session()` method for all
267
+ * channel state management and credential creation, and to `Fetch.from`
268
+ * for the 402 challenge/retry flow.
269
+ *
270
+ * ## Session resumption
271
+ *
272
+ * The manager only keeps active client transport state in memory. Channel
273
+ * descriptors and cumulative voucher state are hydrated from server snapshots
274
+ * when challenges include them; otherwise the next request opens a fresh
275
+ * TIP-1034 channel. `maxDeposit` remains the local cap for all automatic
276
+ * voucher and top-up decisions.
277
+ */
278
+ export function sessionManager(parameters: sessionManager.Parameters): SessionManager {
279
+ const config = resolveSessionManagerConfig(parameters)
280
+ const sessionStore = parameters.sessionStore
281
+ let storedChannel: StoredSessionChannel | null = null
282
+ let bootstrapChannelId: Hex.Hex | null = null
283
+ const ignoredStoredChannelIds = new Set<Hex.Hex>()
284
+ const runtime = createSessionManagerRuntime()
285
+ const receipts = createSessionReceiptCoordinator({
286
+ getSocketSession: () => runtime.socketSession,
287
+ })
288
+
289
+ function dispatch(event: Parameters<typeof dispatchSessionEvent>[1]) {
290
+ return dispatchSessionEvent(runtime, event)
291
+ }
292
+
293
+ const method = sessionPlugin({
294
+ account: parameters.account,
295
+ authorizedSigner: parameters.authorizedSigner,
296
+ getClient: parameters.client ? () => parameters.client! : parameters.getClient,
297
+ escrow: parameters.escrow,
298
+ decimals: config.decimals,
299
+ maxDeposit: parameters.maxDeposit,
300
+ onChannelUpdate(entry) {
301
+ if (entry.channelId !== runtime.channel?.channelId) runtime.spent = 0n
302
+ runtime.channel = entry
303
+ persistStoredChannel(entry)
304
+ if (runtime.lastChallenge) {
305
+ dispatch({
306
+ type: 'activated',
307
+ challengeId: runtime.lastChallenge.id,
308
+ entry,
309
+ spent: runtime.spent.toString(),
310
+ units: 0,
311
+ })
312
+ }
313
+ },
314
+ })
315
+ const chargeMethod = chargePlugin({
316
+ account: parameters.account,
317
+ getClient: parameters.client ? () => parameters.client! : parameters.getClient,
318
+ })
319
+
320
+ const wrappedFetch = Fetch.from({
321
+ fetch: config.fetch,
322
+ methods: [method],
323
+ onChallenge: async (challenge, _helpers) => {
324
+ if (!isTempoSessionChallenge(challenge)) return undefined
325
+ runtime.lastChallenge = challenge
326
+ dispatch({ type: 'challengeReceived', challengeId: challenge.id })
327
+ if (runtime.channel?.opened && runtime.lastUrl) {
328
+ const requiredCumulative =
329
+ runtime.channel.cumulativeAmount + readSessionChallengeAmount(challenge)
330
+ await topUpIfNeeded({
331
+ challenge,
332
+ input: runtime.lastUrl,
333
+ channelId: runtime.channel.channelId,
334
+ deposit: runtime.channel.deposit,
335
+ requiredCumulative,
336
+ })
337
+ }
338
+ const resolved = resolveCredentialContext({
339
+ challenge,
340
+ channel: runtime.channel,
341
+ context: {},
342
+ storedChannel,
343
+ })
344
+ if (resolved.usedStoredChannel) return _helpers.createCredential(resolved.context)
345
+ return undefined
346
+ },
347
+ })
348
+
349
+ function createSessionCredential(challenge: TempoSessionChallenge, context: SessionContext) {
350
+ const resolved = resolveCredentialContext({
351
+ challenge,
352
+ channel: runtime.channel,
353
+ context,
354
+ storedChannel,
355
+ })
356
+ return method.createCredential({
357
+ challenge,
358
+ context: resolved.context,
359
+ })
360
+ }
361
+
362
+ function updateSpentFromReceipt(receipt: SessionReceipt | null | undefined) {
363
+ applySessionReceiptToRuntime({
364
+ maxVoucherCumulative: config.maxVoucherCumulative,
365
+ receipt,
366
+ runtime,
367
+ })
368
+ }
369
+
370
+ function activateCurrentChannel(
371
+ units = runtime.state.status === 'active' ? runtime.state.units : 0,
372
+ ) {
373
+ if (!runtime.channel || !runtime.lastChallenge) return
374
+ if (
375
+ runtime.state.status === 'active' ||
376
+ runtime.state.status === 'withdrawable' ||
377
+ runtime.state.status === 'closeRequested'
378
+ )
379
+ return
380
+ dispatch({
381
+ type: 'activated',
382
+ challengeId: runtime.lastChallenge.id,
383
+ entry: runtime.channel,
384
+ spent: runtime.spent.toString(),
385
+ units,
386
+ })
387
+ }
388
+
389
+ async function getStoredChannel() {
390
+ if (!sessionStore) return null
391
+ if (storedChannel) return storedChannel
392
+ const channel = await sessionStore.get()
393
+ storedChannel =
394
+ channel?.opened && !ignoredStoredChannelIds.has(channel.channelId) ? channel : null
395
+ return storedChannel
396
+ }
397
+
398
+ async function clearStoredChannel() {
399
+ if (!sessionStore) {
400
+ storedChannel = null
401
+ bootstrapChannelId = null
402
+ return
403
+ }
404
+ const channel = storedChannel
405
+ if (channel) ignoredStoredChannelIds.add(channel.channelId)
406
+ storedChannel = null
407
+ bootstrapChannelId = null
408
+ if (sessionStore.delete) {
409
+ await Promise.resolve(sessionStore.delete()).catch(() => undefined)
410
+ return
411
+ }
412
+ if (channel) {
413
+ await Promise.resolve(
414
+ sessionStore.set({ ...channel, opened: false, updatedAt: Date.now() }),
415
+ ).catch(() => undefined)
416
+ }
417
+ }
418
+
419
+ async function storeSnapshotHeader(response: Response) {
420
+ const header = response.headers.get(Constants.Headers.paymentSessionSnapshot)
421
+ if (!header) return
422
+ const snapshot = deserializeSessionSnapshot(header)
423
+ bootstrapChannelId = snapshot.channelId
424
+ const channel = storedChannelFromSnapshot(snapshot)
425
+ storedChannel = channel
426
+ if (sessionStore) await Promise.resolve(sessionStore.set(channel)).catch(() => undefined)
427
+ }
428
+
429
+ async function bootstrapSession(input: RequestInfo | URL, init?: RequestInit | undefined) {
430
+ if (!parameters.bootstrap) return
431
+ if (runtime.channel?.opened) return
432
+ if (await getStoredChannel()) return
433
+
434
+ const requestHeaders = input instanceof Request ? input.headers : undefined
435
+ const { body: _body, method: _method, ...bootstrapInit } = init ?? {}
436
+ const bootstrapInput = input instanceof Request ? input.url : input
437
+ const headInit: RequestInit = {
438
+ ...bootstrapInit,
439
+ method: 'HEAD',
440
+ headers: {
441
+ ...Fetch.normalizeHeaders(requestHeaders),
442
+ ...Fetch.normalizeHeaders(init?.headers),
443
+ [Constants.Headers.acceptPayment]: `${Constants.Methods.tempo}/${Constants.Intents.charge}`,
444
+ },
445
+ }
446
+
447
+ try {
448
+ const challengeResponse = await config.fetch(bootstrapInput, headInit)
449
+ if (challengeResponse.status !== 402) {
450
+ await storeSnapshotHeader(challengeResponse)
451
+ return
452
+ }
453
+ const challenge = Challenge.fromResponseList(challengeResponse).find(isTempoChargeChallenge)
454
+ if (!challenge) return
455
+ if (!isZeroAmountChargeChallenge(challenge)) return
456
+ const credential = await chargeMethod.createCredential({
457
+ challenge: challenge as never,
458
+ context: {},
459
+ })
460
+ const response = await config.fetch(bootstrapInput, {
461
+ ...headInit,
462
+ headers: {
463
+ ...Fetch.normalizeHeaders(headInit.headers),
464
+ [Constants.Headers.authorization]: credential,
465
+ },
466
+ })
467
+ if (response.ok) await storeSnapshotHeader(response)
468
+ } catch {
469
+ return
470
+ }
471
+ }
472
+
473
+ function persistStoredChannel(entry: ChannelEntry) {
474
+ if (!sessionStore) return
475
+ const channel = storedChannelFromEntry(entry)
476
+ ignoredStoredChannelIds.delete(channel.channelId)
477
+ const operation =
478
+ entry.opened || !sessionStore.delete ? sessionStore.set(channel) : sessionStore.delete()
479
+ void Promise.resolve(operation).catch(() => undefined)
480
+ storedChannel = entry.opened ? channel : null
481
+ }
482
+
483
+ function getFallbackCloseAmount(challenge: TempoSessionChallenge, channelId: Hex.Hex): bigint {
484
+ const currentSocket = runtime.socketSession
485
+ return computeFallbackCloseAmount({
486
+ challengeId: challenge.id,
487
+ channelId,
488
+ closeReadyReceipt: currentSocket?.closeReadyReceipt,
489
+ cumulativeAmount:
490
+ runtime.channel?.channelId === channelId ? runtime.channel.cumulativeAmount : 0n,
491
+ deliveredChunks: currentSocket?.deliveredChunks,
492
+ socketChallengeId: currentSocket?.challenge.id,
493
+ socketChannelId: currentSocket?.channelId,
494
+ spent: runtime.spent,
495
+ tickCost: currentSocket?.tickCost,
496
+ })
497
+ }
498
+
499
+ function getValidatedFallbackCloseAmount(target: CloseTarget) {
500
+ const closeAmount = getFallbackCloseAmount(target.challenge, target.channelId)
501
+ if (closeAmount > target.channel.cumulativeAmount) {
502
+ throw new Error('fallback close amount exceeds local voucher state')
503
+ }
504
+ assertVoucherWithinLocalLimit(closeAmount)
505
+ return closeAmount.toString()
506
+ }
507
+
508
+ function assertVoucherWithinLocalLimit(cumulativeAmount: bigint) {
509
+ assertVoucherWithinLocalAuthorization({
510
+ cumulativeAmount,
511
+ maxVoucherCumulative: config.maxVoucherCumulative,
512
+ })
513
+ }
514
+
515
+ async function postTopUpAndApply(parameters: {
516
+ additionalDeposit: bigint
517
+ challenge: TempoSessionChallenge
518
+ channelId: Hex.Hex
519
+ input: RequestInfo | URL
520
+ }) {
521
+ const receipt = await postTopUp({
522
+ ...parameters,
523
+ channel: runtime.channel,
524
+ createSessionCredential,
525
+ fetch: config.fetch,
526
+ })
527
+ updateSpentFromReceipt(receipt)
528
+ const applied = applyTopUpResult({
529
+ additionalDeposit: parameters.additionalDeposit,
530
+ channel: runtime.channel,
531
+ channelId: parameters.channelId,
532
+ challengeId: runtime.lastChallenge?.id,
533
+ currentState: runtime.state,
534
+ receipt,
535
+ spent: runtime.spent,
536
+ })
537
+ if (applied?.channel && runtime.lastChallenge) {
538
+ dispatch({
539
+ type: 'activated',
540
+ challengeId: runtime.lastChallenge.id,
541
+ entry: applied.channel,
542
+ spent: runtime.spent.toString(),
543
+ units: runtime.state.status === 'active' ? runtime.state.units : 0,
544
+ })
545
+ }
546
+ return receipt
547
+ }
548
+
549
+ async function topUpIfNeeded(parameters: TopUpRequirement) {
550
+ if (parameters.requiredCumulative <= parameters.deposit) return
551
+ assertVoucherWithinLocalLimit(parameters.requiredCumulative)
552
+ await postTopUpAndApply({
553
+ challenge: parameters.challenge,
554
+ input: parameters.input,
555
+ channelId: parameters.channelId,
556
+ additionalDeposit: parameters.requiredCumulative - parameters.deposit,
557
+ })
558
+ }
559
+
560
+ function restoreCumulative(channelId: Hex.Hex, cumulativeAmount: bigint) {
561
+ const restored = restoreCumulativeAuthorization({
562
+ channel: runtime.channel,
563
+ channelId,
564
+ challengeId: runtime.lastChallenge?.id,
565
+ cumulativeAmount,
566
+ spent: runtime.spent,
567
+ state: runtime.state,
568
+ })
569
+ if (restored && runtime.channel) {
570
+ dispatch({
571
+ type: 'activated',
572
+ challengeId: restored.challengeId,
573
+ entry: runtime.channel,
574
+ spent: restored.spent,
575
+ units: restored.units,
576
+ })
577
+ }
578
+ }
579
+
580
+ function restoreRuntime(snapshot: RuntimeSnapshot) {
581
+ const restored = restoreRuntimeStateSnapshot(snapshot, runtime.channel)
582
+ runtime.channel = restored.channel
583
+ runtime.spent = restored.spent
584
+ runtime.state = restored.state
585
+ }
586
+
587
+ function toPaymentResponse(response: Response): PaymentResponse {
588
+ const receiptHeader = response.headers.get(Constants.Headers.paymentReceipt)
589
+ const receipt = receiptHeader ? deserializeSessionReceipt(receiptHeader) : null
590
+ updateSpentFromReceipt(receipt)
591
+ return Object.assign(response, {
592
+ receipt,
593
+ challenge: runtime.lastChallenge,
594
+ channelId: runtime.channel?.channelId ?? null,
595
+ cumulative: runtime.channel?.cumulativeAmount ?? 0n,
596
+ })
597
+ }
598
+
599
+ async function doFetch(input: RequestInfo | URL, init?: RequestInit): Promise<PaymentResponse> {
600
+ runtime.lastUrl = input
601
+ const stored = await getStoredChannel()
602
+ await bootstrapSession(input, init)
603
+ const hintedInit = requestInitWithSessionHint(
604
+ input,
605
+ init,
606
+ (await getStoredChannel())?.channelId ?? bootstrapChannelId ?? stored?.channelId,
607
+ )
608
+ const previous = captureRuntimeStateSnapshot({
609
+ channel: runtime.channel,
610
+ spent: runtime.spent,
611
+ state: runtime.state,
612
+ })
613
+
614
+ let effectiveInit = hintedInit
615
+ let canRetryWithoutStoredHint = Boolean(stored?.opened && !previous.channel?.opened)
616
+
617
+ for (;;) {
618
+ let response: Response
619
+ try {
620
+ response = await wrappedFetch(input, effectiveInit)
621
+ } catch (error) {
622
+ restoreRuntime(previous)
623
+ if (!canRetryWithoutStoredHint) throw error
624
+ canRetryWithoutStoredHint = false
625
+ await clearStoredChannel()
626
+ await bootstrapSession(input, init)
627
+ effectiveInit = requestInitWithSessionHint(input, init, bootstrapChannelId ?? undefined)
628
+ continue
629
+ }
630
+
631
+ let paymentResponse = toPaymentResponse(response)
632
+ let attemptedHttpManagement = false
633
+ if (paymentResponse.status === 402) {
634
+ const retry = await retryHttpPaymentRequired({
635
+ input,
636
+ init: effectiveInit,
637
+ response: paymentResponse,
638
+ createSessionCredential,
639
+ fetch: config.fetch,
640
+ getChannel: () => runtime.channel,
641
+ restoreCumulative,
642
+ setChallenge(challenge) {
643
+ runtime.lastChallenge = challenge
644
+ },
645
+ topUpIfNeeded,
646
+ })
647
+ if (retry) {
648
+ attemptedHttpManagement = true
649
+ paymentResponse = toPaymentResponse(retry)
650
+ }
651
+ }
652
+ if (!attemptedHttpManagement && !paymentResponse.ok && !paymentResponse.receipt) {
653
+ restoreRuntime(previous)
654
+ if (!canRetryWithoutStoredHint) return paymentResponse
655
+ canRetryWithoutStoredHint = false
656
+ await clearStoredChannel()
657
+ await bootstrapSession(input, init)
658
+ effectiveInit = requestInitWithSessionHint(input, init, bootstrapChannelId ?? undefined)
659
+ continue
660
+ }
661
+ return paymentResponse
662
+ }
663
+ }
664
+
665
+ async function closeHttpSessionAndApply(
666
+ target: CloseTarget,
667
+ ): Promise<SessionReceipt | undefined> {
668
+ const receipt = await closeHttpSession({
669
+ createSessionCredential,
670
+ fetch: config.fetch,
671
+ lastUrl: runtime.lastUrl,
672
+ signedCloseAmount: getValidatedFallbackCloseAmount(target),
673
+ setChallenge(challenge) {
674
+ runtime.lastChallenge = challenge
675
+ },
676
+ target,
677
+ })
678
+ if (receipt) {
679
+ activateCurrentChannel()
680
+ dispatch({ type: 'closeStarted' })
681
+ dispatch({ type: 'closed', receipt })
682
+ }
683
+
684
+ return receipt
685
+ }
686
+
687
+ const self: SessionManager = {
688
+ get channelId() {
689
+ return runtime.channel?.channelId
690
+ },
691
+ get cumulative() {
692
+ return runtime.channel?.cumulativeAmount ?? 0n
693
+ },
694
+ get opened() {
695
+ return runtime.channel?.opened ?? false
696
+ },
697
+ get state() {
698
+ return runtime.state
699
+ },
700
+
701
+ fetch: doFetch,
702
+
703
+ async topUp(amount) {
704
+ const target = resolveManualTopUp({
705
+ amount,
706
+ assertVoucherWithinLocalLimit,
707
+ channel: runtime.channel,
708
+ decimals: config.decimals,
709
+ lastChallenge: runtime.lastChallenge,
710
+ lastUrl: runtime.lastUrl,
711
+ })
712
+
713
+ return postTopUpAndApply({
714
+ additionalDeposit: target.additionalDeposit,
715
+ challenge: target.challenge,
716
+ channelId: target.channelId,
717
+ input: target.input,
718
+ })
719
+ },
720
+
721
+ async sse(input, init) {
722
+ return openSseSession(input, init, {
723
+ createSessionCredential,
724
+ doFetch,
725
+ fetch: config.fetch,
726
+ getChannel: () => runtime.channel,
727
+ getChallenge: () => runtime.lastChallenge,
728
+ assertVoucherWithinLocalLimit,
729
+ managementInput,
730
+ acceptReceipt(receipt) {
731
+ updateSpentFromReceipt(receipt)
732
+ },
733
+ topUpIfNeeded,
734
+ })
735
+ },
736
+
737
+ async ws(input, init) {
738
+ if (!config.WebSocket) {
739
+ throw new Error(
740
+ 'No WebSocket implementation available. Pass `webSocket` to sessionManager() in this runtime.',
741
+ )
742
+ }
743
+ const probeUrl = webSocketProbeUrl(input)
744
+ await bootstrapSession(probeUrl, init?.signal ? { signal: init.signal } : undefined)
745
+
746
+ const prepared = await prepareWebSocketSession({
747
+ createSessionCredential,
748
+ fetch: config.fetch,
749
+ input,
750
+ onProbeUrl(httpUrl) {
751
+ runtime.lastUrl = httpUrl.toString()
752
+ },
753
+ probeInit: requestInitWithSessionHint(
754
+ probeUrl,
755
+ init?.signal ? { signal: init.signal } : undefined,
756
+ (await getStoredChannel())?.channelId ?? bootstrapChannelId ?? undefined,
757
+ ),
758
+ signal: init?.signal,
759
+ })
760
+ const { challenge, credential, httpUrl, wsUrl } = prepared
761
+ runtime.lastChallenge = challenge
762
+
763
+ return openWebSocketSession({
764
+ challenge,
765
+ credential,
766
+ httpUrl,
767
+ WebSocket: config.WebSocket,
768
+ wsUrl,
769
+ options: init,
770
+ createSessionCredential,
771
+ getChannel: () => runtime.channel,
772
+ setSocketSession(session) {
773
+ runtime.socketSession = session
774
+ },
775
+ assertVoucherWithinLocalLimit,
776
+ acceptReceipt: updateSpentFromReceipt,
777
+ rejectCloseReady: receipts.rejectCloseReady,
778
+ rejectReceipt: receipts.rejectReceipt,
779
+ settleCloseReady: receipts.settleCloseReady,
780
+ settleReceipt: receipts.settleReceipt,
781
+ topUpIfNeeded,
782
+ waitForReceipt: receipts.waitForReceipt,
783
+ })
784
+ },
785
+
786
+ async close() {
787
+ const currentSocket = runtime.socketSession
788
+ const target = resolveCloseTarget({
789
+ channel: runtime.channel,
790
+ currentSocket,
791
+ lastChallenge: runtime.lastChallenge,
792
+ })
793
+ if (!target) return undefined
794
+
795
+ const activeSocket = currentSocket?.socket
796
+ if (currentSocket && activeSocket?.readyState === WebSocketReadyState.OPEN) {
797
+ const receipt = await closeSocketSession({
798
+ activeSocket,
799
+ createSessionCredential,
800
+ currentSocket,
801
+ spent: runtime.spent,
802
+ target,
803
+ waitForCloseReady: receipts.waitForCloseReady,
804
+ waitForReceipt: receipts.waitForReceipt,
805
+ })
806
+ activateCurrentChannel()
807
+ dispatch({ type: 'closeStarted' })
808
+ dispatch({ type: 'closed', receipt })
809
+ return receipt
810
+ }
811
+
812
+ return closeHttpSessionAndApply(target)
813
+ },
814
+ }
815
+
816
+ return self
817
+ }
818
+
819
+ /** Type helpers for `sessionManager()`. */
820
+ export namespace sessionManager {
821
+ export const serializeSnapshot = serializeSessionSnapshot
822
+ export const deserializeSnapshot = deserializeSessionSnapshot
823
+
824
+ export type Parameters = Account.getResolver.Parameters &
825
+ Client.getResolver.Parameters & {
826
+ /** Address authorized to sign vouchers. Defaults to the account access key address when available, otherwise the account address. */
827
+ authorizedSigner?: Address | undefined
828
+ /** Enables same-route HEAD bootstrap from a server session snapshot before opening a new channel. */
829
+ bootstrap?: boolean | undefined
830
+ /** Viem client instance. Shorthand for `getClient: () => client`. */
831
+ client?: import('viem').Client | undefined
832
+ /** Token decimals used to convert `maxDeposit` to raw units. Defaults to `6`. */
833
+ decimals?: number | undefined
834
+ /** TIP20EscrowChannel precompile address override. */
835
+ escrow?: Address | undefined
836
+ /** Fetch implementation used for HTTP probes, management posts, and paid retries. */
837
+ fetch?: typeof globalThis.fetch | undefined
838
+ /** Maximum deposit in human-readable units (e.g. `'10'` for 10 tokens). Converted to raw units via `decimals`. */
839
+ maxDeposit?: string | undefined
840
+ /** Optional per-manager store for persisted channel hints and restart recovery. */
841
+ sessionStore?: SessionStore | undefined
842
+ /** Optional websocket constructor for runtimes without a global WebSocket. */
843
+ webSocket?: WebSocketConstructor | undefined
844
+ }
845
+ }