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,721 @@
1
+ import * as Challenge from '../../../Challenge.js';
2
+ import * as Fetch from '../../../client/internal/Fetch.js';
3
+ import * as Constants from '../../../Constants.js';
4
+ import * as PaymentCredential from '../../../Credential.js';
5
+ import { deserializeSessionReceipt, isEventStream, parseEvent, readSessionChallengeAmount, uint96, } from '../precompile/Protocol.js';
6
+ import * as Ws from '../precompile/Protocol.js';
7
+ import { activeStateFromChannel, activeStateFromReceipt, isExpectedCloseReceipt, parseManagerAmount, } from './Runtime.js';
8
+ /** Numeric ready-state constants used by browser-compatible WebSocket clients. */
9
+ export const WebSocketReadyState = {
10
+ CONNECTING: 0,
11
+ OPEN: 1,
12
+ CLOSING: 2,
13
+ CLOSED: 3,
14
+ };
15
+ // Browser-style WebSocket clients may only initiate close with 1000 or 3000-4999.
16
+ // Keep protocol/policy close codes on the server side and use an app-defined code here.
17
+ /** Client-side close code used for payment protocol errors. */
18
+ export const ClientWebSocketProtocolErrorCloseCode = 3008;
19
+ /** Wraps a raw WebSocket so protocol frames can be handled before user listeners see messages. */
20
+ export function createManagedSocket(socket) {
21
+ const listeners = new Map();
22
+ let emittedClose = false;
23
+ let messageBuffer = [];
24
+ let readyState = socket.readyState;
25
+ const add = (type, listener, options) => {
26
+ let set = listeners.get(type);
27
+ if (!set) {
28
+ set = new Set();
29
+ listeners.set(type, set);
30
+ }
31
+ set.add({
32
+ once: typeof options === 'object' ? options.once === true : false,
33
+ value: listener,
34
+ });
35
+ if (type === 'message' && messageBuffer) {
36
+ const buffered = messageBuffer;
37
+ messageBuffer = null;
38
+ for (const event of buffered)
39
+ emit('message', event);
40
+ }
41
+ };
42
+ const remove = (type, listener) => {
43
+ const set = listeners.get(type);
44
+ if (!set)
45
+ return;
46
+ for (const entry of set) {
47
+ if (entry.value === listener)
48
+ set.delete(entry);
49
+ }
50
+ };
51
+ function emit(type, event) {
52
+ if (event.type === 'close') {
53
+ if (emittedClose)
54
+ return;
55
+ emittedClose = true;
56
+ readyState = WebSocketReadyState.CLOSED;
57
+ messageBuffer = null;
58
+ }
59
+ if (event.type === 'open')
60
+ readyState = WebSocketReadyState.OPEN;
61
+ if (event.type === 'message' && messageBuffer) {
62
+ messageBuffer.push(event);
63
+ return;
64
+ }
65
+ switch (event.type) {
66
+ case 'close':
67
+ managed.onclose?.(event);
68
+ break;
69
+ case 'error':
70
+ managed.onerror?.(event);
71
+ break;
72
+ case 'message':
73
+ managed.onmessage?.(event);
74
+ break;
75
+ case 'open':
76
+ managed.onopen?.(event);
77
+ break;
78
+ }
79
+ const set = listeners.get(type);
80
+ if (!set)
81
+ return;
82
+ for (const entry of Array.from(set)) {
83
+ if (typeof entry.value === 'function')
84
+ entry.value(event);
85
+ else
86
+ entry.value.handleEvent(event);
87
+ if (entry.once)
88
+ set.delete(entry);
89
+ }
90
+ }
91
+ let onmessage = null;
92
+ const managed = {
93
+ addEventListener: add,
94
+ close(code, reason) {
95
+ socket.close(code, reason);
96
+ },
97
+ get bufferedAmount() {
98
+ return socket.bufferedAmount;
99
+ },
100
+ get extensions() {
101
+ return socket.extensions;
102
+ },
103
+ on(type, listener) {
104
+ add(type, listener);
105
+ },
106
+ onclose: null,
107
+ onerror: null,
108
+ get onmessage() {
109
+ return onmessage;
110
+ },
111
+ set onmessage(fn) {
112
+ onmessage = fn;
113
+ if (fn && messageBuffer) {
114
+ const buffered = messageBuffer;
115
+ messageBuffer = null;
116
+ for (const event of buffered)
117
+ emit('message', event);
118
+ }
119
+ },
120
+ onopen: null,
121
+ off(type, listener) {
122
+ remove(type, listener);
123
+ },
124
+ get protocol() {
125
+ return socket.protocol;
126
+ },
127
+ get readyState() {
128
+ return readyState;
129
+ },
130
+ removeEventListener: remove,
131
+ send(data) {
132
+ socket.send(data);
133
+ },
134
+ get url() {
135
+ return socket.url;
136
+ },
137
+ };
138
+ return {
139
+ emit,
140
+ socket: managed,
141
+ };
142
+ }
143
+ /** Parses raw-unit numeric fields from a need-voucher event. */
144
+ export function readNeedVoucherEventAmounts(event) {
145
+ return {
146
+ acceptedCumulative: BigInt(event.acceptedCumulative),
147
+ deposit: BigInt(event.deposit),
148
+ requiredCumulative: BigInt(event.requiredCumulative),
149
+ };
150
+ }
151
+ /** Validates local manager state and returns the concrete top-up operation to execute. */
152
+ export function resolveManualTopUp(parameters) {
153
+ const { amount, assertVoucherWithinLocalLimit, channel, decimals, lastChallenge, lastUrl } = parameters;
154
+ if (!channel?.opened)
155
+ throw new Error('Cannot top up session: no open channel.');
156
+ if (!lastChallenge) {
157
+ throw new Error('Cannot top up session: no challenge available. Make a request first.');
158
+ }
159
+ if (!lastUrl) {
160
+ throw new Error('Cannot top up session: no URL available. Call fetch(), sse(), or ws() first.');
161
+ }
162
+ const additionalDeposit = parseManagerAmount(amount, decimals);
163
+ if (additionalDeposit <= 0n)
164
+ throw new Error('Top-up amount must be greater than zero.');
165
+ assertVoucherWithinLocalLimit(channel.cumulativeAmount + additionalDeposit);
166
+ return {
167
+ additionalDeposit,
168
+ challenge: lastChallenge,
169
+ channelId: channel.channelId,
170
+ input: lastUrl,
171
+ };
172
+ }
173
+ /**
174
+ * Applies local deposit and state bookkeeping for a top-up response.
175
+ *
176
+ * `deposit` is updated from the top-up amount. Receipt cumulative values only
177
+ * update accepted spend authorization; they do not replace deposit.
178
+ */
179
+ export function applyTopUpResult(parameters) {
180
+ const { additionalDeposit, channel, channelId, challengeId, currentState, receipt, spent } = parameters;
181
+ if (channel?.channelId !== channelId)
182
+ return undefined;
183
+ channel.deposit += additionalDeposit;
184
+ if (receipt)
185
+ return { channel, state: activeStateFromReceipt(receipt, channel) };
186
+ if (!challengeId)
187
+ return { channel };
188
+ return {
189
+ channel,
190
+ state: activeStateFromChannel({
191
+ challengeId,
192
+ entry: channel,
193
+ spent: spent.toString(),
194
+ units: currentState.status === 'active' ? currentState.units : 0,
195
+ }),
196
+ };
197
+ }
198
+ /**
199
+ * Applies local top-up/cumulative bookkeeping for a need-voucher event and
200
+ * returns an explicit transport decision.
201
+ */
202
+ export async function resolveNeedVoucherContext(parameters) {
203
+ if (parameters.event.channelId !== parameters.expectedChannelId) {
204
+ return { status: 'ignored', reason: 'channel-mismatch' };
205
+ }
206
+ const eventAmounts = readNeedVoucherEventAmounts(parameters.event);
207
+ parameters.assertVoucherWithinLocalLimit(eventAmounts.requiredCumulative);
208
+ await parameters.topUpIfNeeded({
209
+ challenge: parameters.challenge,
210
+ input: parameters.input,
211
+ channelId: parameters.expectedChannelId,
212
+ deposit: eventAmounts.deposit,
213
+ requiredCumulative: eventAmounts.requiredCumulative,
214
+ });
215
+ const channel = parameters.getChannel();
216
+ if (!channel || channel.channelId !== parameters.expectedChannelId) {
217
+ return { status: 'ignored', reason: 'missing-channel' };
218
+ }
219
+ const cumulativeAmount = channel.cumulativeAmount > eventAmounts.requiredCumulative
220
+ ? channel.cumulativeAmount
221
+ : uint96(eventAmounts.requiredCumulative);
222
+ return {
223
+ status: 'ready',
224
+ context: {
225
+ action: 'voucher',
226
+ channelId: parameters.expectedChannelId,
227
+ descriptor: channel.descriptor,
228
+ cumulativeAmountRaw: cumulativeAmount.toString(),
229
+ },
230
+ };
231
+ }
232
+ /** Returns true when a payment challenge is the built-in `tempo/session` method. */
233
+ export function isTempoSessionChallenge(challenge) {
234
+ return (challenge.method === Constants.Methods.tempo && challenge.intent === Constants.Intents.session);
235
+ }
236
+ /** Reads a server-provided session snapshot from challenge method details. */
237
+ export function getSessionSnapshot(challenge) {
238
+ return Constants.getMethodDetail(challenge.request.methodDetails, Constants.MethodDetailKeys.sessionSnapshot);
239
+ }
240
+ /** Merges request headers and sets the payment authorization header for a retry. */
241
+ export function requestInitWithAuthorization(input, init, credential) {
242
+ const requestHeaders = input instanceof Request ? input.headers : undefined;
243
+ return {
244
+ ...init,
245
+ headers: {
246
+ ...Fetch.normalizeHeaders(requestHeaders),
247
+ ...Fetch.normalizeHeaders(init?.headers),
248
+ [Constants.Headers.authorization]: credential,
249
+ },
250
+ };
251
+ }
252
+ /** Returns the URL used for out-of-band management POSTs, stripping resource query state. */
253
+ export function managementInput(input) {
254
+ try {
255
+ const base = typeof location === 'undefined' ? undefined : location.href;
256
+ const url = input instanceof Request
257
+ ? new URL(input.url)
258
+ : input instanceof URL
259
+ ? new URL(input)
260
+ : new URL(String(input), base);
261
+ url.search = '';
262
+ return url;
263
+ }
264
+ catch {
265
+ return input;
266
+ }
267
+ }
268
+ /** Converts a WebSocket URL into the HTTP URL used for its payment challenge probe. */
269
+ export function webSocketProbeUrl(input) {
270
+ const url = new URL(input.toString());
271
+ if (url.protocol === 'ws:')
272
+ url.protocol = 'http:';
273
+ if (url.protocol === 'wss:')
274
+ url.protocol = 'https:';
275
+ return url;
276
+ }
277
+ /** Reads an HTTP problem detail body, falling back to raw text for non-problem responses. */
278
+ export async function readProblemDetail(response) {
279
+ const body = await response.text().catch(() => '');
280
+ if (!body)
281
+ return '';
282
+ if (!response.headers.get('Content-Type')?.includes('application/problem+json'))
283
+ return body;
284
+ try {
285
+ const problem = JSON.parse(body);
286
+ return problem.detail ?? body;
287
+ }
288
+ catch {
289
+ return body;
290
+ }
291
+ }
292
+ /** Posts a top-up management credential and returns its receipt, when present. */
293
+ export async function postTopUp(parameters) {
294
+ const { channel, channelId } = parameters;
295
+ if (!channel?.descriptor || channel.channelId !== channelId) {
296
+ throw new Error('Cannot top up session: no local channel descriptor available.');
297
+ }
298
+ const credential = await parameters.createSessionCredential(parameters.challenge, {
299
+ action: 'topUp',
300
+ channelId,
301
+ descriptor: channel.descriptor,
302
+ additionalDepositRaw: parameters.additionalDeposit.toString(),
303
+ });
304
+ const response = await parameters.fetch(managementInput(parameters.input), {
305
+ method: 'POST',
306
+ headers: { [Constants.Headers.authorization]: credential },
307
+ });
308
+ if (!response.ok)
309
+ throw new Error(`Top-up POST failed with status ${response.status}`);
310
+ const receiptHeader = response.headers.get(Constants.Headers.paymentReceipt);
311
+ return receiptHeader ? deserializeSessionReceipt(receiptHeader) : undefined;
312
+ }
313
+ /** Retries an HTTP 402 when the server snapshot asks for more voucher headroom. */
314
+ export async function retryHttpPaymentRequired(parameters) {
315
+ const context = resolveRetryHttpPaymentContext({
316
+ channel: parameters.getChannel(),
317
+ response: parameters.response,
318
+ });
319
+ if (!context)
320
+ return undefined;
321
+ const { channel, challenge, snapshot } = context;
322
+ parameters.setChallenge(challenge);
323
+ const requiredCumulative = BigInt(snapshot.requiredCumulative);
324
+ const cumulativeBeforeVoucher = channel.cumulativeAmount;
325
+ await parameters.topUpIfNeeded({
326
+ challenge,
327
+ input: parameters.input,
328
+ channelId: snapshot.channelId,
329
+ deposit: BigInt(snapshot.deposit),
330
+ requiredCumulative,
331
+ });
332
+ const currentChannel = parameters.getChannel();
333
+ if (!currentChannel?.descriptor || currentChannel.channelId !== snapshot.channelId) {
334
+ return undefined;
335
+ }
336
+ const cumulativeAmount = currentChannel.cumulativeAmount > requiredCumulative
337
+ ? currentChannel.cumulativeAmount
338
+ : requiredCumulative;
339
+ const credential = await parameters.createSessionCredential(challenge, {
340
+ action: 'voucher',
341
+ channelId: snapshot.channelId,
342
+ descriptor: currentChannel.descriptor,
343
+ cumulativeAmountRaw: cumulativeAmount.toString(),
344
+ });
345
+ const retry = await parameters.fetch(parameters.input, requestInitWithAuthorization(parameters.input, parameters.init, credential));
346
+ if (!retry.ok && !retry.headers.get(Constants.Headers.paymentReceipt)) {
347
+ parameters.restoreCumulative(snapshot.channelId, cumulativeBeforeVoucher);
348
+ }
349
+ return retry;
350
+ }
351
+ /** Resolves whether a 402 response can be handled by an automatic session voucher retry. */
352
+ export function resolveRetryHttpPaymentContext(parameters) {
353
+ const challenge = Challenge.fromResponseList(parameters.response).find(isTempoSessionChallenge);
354
+ if (!challenge)
355
+ return undefined;
356
+ const snapshot = getSessionSnapshot(challenge);
357
+ if (!snapshot)
358
+ return undefined;
359
+ const { channel } = parameters;
360
+ if (!channel?.descriptor || channel.channelId !== snapshot.channelId)
361
+ return undefined;
362
+ return { channel, challenge, snapshot };
363
+ }
364
+ /** Posts a cooperative close credential over HTTP and returns its receipt, when present. */
365
+ export async function closeHttpSession(parameters) {
366
+ if (!parameters.lastUrl) {
367
+ throw new Error('Cannot close session: no URL available. This usually means close() was called on a SessionManager instance that was recreated after the session was opened. Use the same SessionManager instance that opened the session, or call fetch()/sse() before close().');
368
+ }
369
+ const postClose = async (challenge) => {
370
+ const credential = await parameters.createSessionCredential(challenge, {
371
+ action: 'close',
372
+ channelId: parameters.target.channelId,
373
+ descriptor: parameters.target.channel.descriptor,
374
+ cumulativeAmountRaw: parameters.signedCloseAmount,
375
+ });
376
+ return parameters.fetch(parameters.lastUrl, {
377
+ method: 'POST',
378
+ headers: { [Constants.Headers.authorization]: credential },
379
+ });
380
+ };
381
+ let response = await postClose(parameters.target.challenge);
382
+ if (response.status === 402) {
383
+ const challenge = Challenge.fromResponseList(response).find(isTempoSessionChallenge);
384
+ if (challenge) {
385
+ parameters.setChallenge?.(challenge);
386
+ response = await postClose(challenge);
387
+ }
388
+ }
389
+ if (!response.ok) {
390
+ const detail = await readProblemDetail(response);
391
+ const wwwAuth = response.headers.get(Constants.Headers.wwwAuthenticate) ?? '';
392
+ throw new Error(`Close request failed with status ${response.status}${detail ? `: ${detail}` : ''}${wwwAuth ? ` [${Constants.Headers.wwwAuthenticate}: ${wwwAuth}]` : ''}`);
393
+ }
394
+ const receiptHeader = response.headers.get(Constants.Headers.paymentReceipt);
395
+ return receiptHeader ? deserializeSessionReceipt(receiptHeader) : undefined;
396
+ }
397
+ /**
398
+ * Opens an auto-driving paid SSE stream.
399
+ *
400
+ * The driver owns only transport parsing and management posts. Session state,
401
+ * credential creation, and top-up policy stay in `SessionManager`.
402
+ */
403
+ export async function openSseSession(input, init, driver) {
404
+ const { onReceipt, signal, ...fetchInit } = init ?? {};
405
+ const sseInit = {
406
+ ...fetchInit,
407
+ headers: {
408
+ ...Fetch.normalizeHeaders(fetchInit.headers),
409
+ Accept: 'text/event-stream',
410
+ },
411
+ ...(signal ? { signal } : {}),
412
+ };
413
+ let response = await driver.doFetch(input, sseInit);
414
+ if (!isEventStream(response) && driver.getChannel()?.opened)
415
+ response = await driver.doFetch(input, sseInit);
416
+ const challenge = driver.getChallenge();
417
+ if (!isEventStream(response))
418
+ throw new Error('SSE response is not an event stream.');
419
+ if (!response.body)
420
+ throw new Error('Response has no body.');
421
+ return iterateSseResponse({
422
+ challenge,
423
+ driver,
424
+ input,
425
+ onReceipt,
426
+ response,
427
+ signal,
428
+ });
429
+ }
430
+ async function* iterateSseResponse(parameters) {
431
+ const reader = parameters.response.body.getReader();
432
+ const decoder = new TextDecoder();
433
+ let buffer = '';
434
+ try {
435
+ while (true) {
436
+ if (parameters.signal?.aborted)
437
+ break;
438
+ const { done, value } = await reader.read();
439
+ if (done)
440
+ break;
441
+ buffer += decoder.decode(value, { stream: true });
442
+ const parts = buffer.split('\n\n');
443
+ buffer = parts.pop();
444
+ for (const part of parts) {
445
+ if (!part.trim())
446
+ continue;
447
+ const event = parseEvent(part);
448
+ if (!event)
449
+ continue;
450
+ switch (event.type) {
451
+ case 'message':
452
+ yield event.data;
453
+ break;
454
+ case 'payment-need-voucher':
455
+ await handleSseNeedVoucher(parameters, event.data);
456
+ break;
457
+ case 'payment-receipt':
458
+ parameters.driver.acceptReceipt(event.data);
459
+ parameters.onReceipt?.(event.data);
460
+ break;
461
+ }
462
+ }
463
+ }
464
+ }
465
+ finally {
466
+ reader.releaseLock();
467
+ }
468
+ }
469
+ async function handleSseNeedVoucher(parameters, event) {
470
+ const channel = parameters.driver.getChannel();
471
+ if (!channel || !parameters.challenge)
472
+ return;
473
+ const resolution = await resolveNeedVoucherContext({
474
+ assertVoucherWithinLocalLimit: parameters.driver.assertVoucherWithinLocalLimit,
475
+ challenge: parameters.challenge,
476
+ event,
477
+ expectedChannelId: channel.channelId,
478
+ getChannel: parameters.driver.getChannel,
479
+ input: parameters.input,
480
+ topUpIfNeeded: parameters.driver.topUpIfNeeded,
481
+ });
482
+ if (resolution.status !== 'ready')
483
+ return;
484
+ const credential = await parameters.driver.createSessionCredential(parameters.challenge, resolution.context);
485
+ const voucherResponse = await parameters.driver.fetch(parameters.driver.managementInput(parameters.input), {
486
+ method: 'POST',
487
+ headers: { [Constants.Headers.authorization]: credential },
488
+ });
489
+ if (!voucherResponse.ok) {
490
+ throw new Error(`Voucher POST failed with status ${voucherResponse.status}`);
491
+ }
492
+ }
493
+ /** Probes a WebSocket endpoint over HTTP and creates the opening credential. */
494
+ export async function prepareWebSocketSession(parameters) {
495
+ const wsUrl = new URL(parameters.input.toString());
496
+ const httpUrl = webSocketProbeUrl(wsUrl);
497
+ parameters.onProbeUrl?.(httpUrl);
498
+ const probe = await parameters.fetch(httpUrl, {
499
+ ...parameters.probeInit,
500
+ ...(parameters.signal ? { signal: parameters.signal } : {}),
501
+ });
502
+ if (probe.status !== 402) {
503
+ throw new Error(`Expected a 402 payment challenge from ${httpUrl}, received ${probe.status} instead.`);
504
+ }
505
+ const challenge = Challenge.fromResponseList(probe).find(isTempoSessionChallenge);
506
+ if (!challenge) {
507
+ throw new Error('No payment challenge received from HTTP endpoint for this WebSocket URL. The server may not require payment or did not advertise a challenge.');
508
+ }
509
+ return {
510
+ challenge,
511
+ credential: await parameters.createSessionCredential(challenge, {}),
512
+ httpUrl,
513
+ wsUrl,
514
+ };
515
+ }
516
+ /** Creates the initial runtime state for a paid WebSocket from its opening credential. */
517
+ export function createActiveSocketSession(parameters) {
518
+ const { challenge, credential, socket } = parameters;
519
+ return {
520
+ challenge,
521
+ channelId: PaymentCredential.deserialize(credential).payload.channelId,
522
+ closeReadyReceipt: null,
523
+ deliveredChunks: 0n,
524
+ expectedCloseAmount: null,
525
+ socket,
526
+ tickCost: readSessionChallengeAmount(challenge),
527
+ };
528
+ }
529
+ /** Returns whether a receipt belongs to the active WebSocket session. */
530
+ export function isExpectedSocketReceipt(parameters) {
531
+ const { challengeId, channelId, receipt } = parameters;
532
+ return receipt.challengeId === challengeId && receipt.channelId === channelId;
533
+ }
534
+ /** Returns a protocol failure message when a close-ready receipt is invalid. */
535
+ export function validateSocketCloseReadyReceipt(parameters) {
536
+ if (!isExpectedSocketReceipt(parameters))
537
+ return 'received mismatched payment-close-ready frame';
538
+ if (BigInt(parameters.receipt.spent) > parameters.cumulativeAmount) {
539
+ return 'received payment-close-ready beyond local voucher state';
540
+ }
541
+ return undefined;
542
+ }
543
+ /** Returns a protocol failure message when a payment receipt is invalid. */
544
+ export function validateSocketPaymentReceipt(parameters) {
545
+ const { challengeId, channelId, expectedCloseAmount, receipt } = parameters;
546
+ if (!isExpectedSocketReceipt(parameters))
547
+ return 'received mismatched payment-receipt frame';
548
+ if (expectedCloseAmount !== null &&
549
+ Boolean(receipt.txHash) &&
550
+ !isExpectedCloseReceipt({ challengeId, channelId, expectedCloseAmount, receipt })) {
551
+ return 'received mismatched payment-close receipt frame';
552
+ }
553
+ return undefined;
554
+ }
555
+ /**
556
+ * Opens an auto-driving paid WebSocket session.
557
+ *
558
+ * The driver owns socket protocol frames. Session state, credential creation,
559
+ * and top-up policy remain supplied by `SessionManager`.
560
+ */
561
+ export async function openWebSocketSession(parameters) {
562
+ const { challenge, credential, options, WebSocket: WebSocketImpl, wsUrl } = parameters;
563
+ const rawSocket = new WebSocketImpl(wsUrl, options?.protocols);
564
+ const socketState = createActiveSocketSession({
565
+ challenge,
566
+ credential,
567
+ socket: rawSocket,
568
+ });
569
+ parameters.setSocketSession(socketState);
570
+ const managedSocket = createManagedSocket(rawSocket);
571
+ const failSocketFlow = (message) => {
572
+ parameters.rejectReceipt(new Error(message));
573
+ parameters.rejectCloseReady(new Error(message));
574
+ if (rawSocket.readyState === WebSocketReadyState.CONNECTING ||
575
+ rawSocket.readyState === WebSocketReadyState.OPEN) {
576
+ rawSocket.close(ClientWebSocketProtocolErrorCloseCode, message);
577
+ }
578
+ };
579
+ rawSocket.addEventListener('close', (event) => {
580
+ socketState.socket = null;
581
+ socketState.expectedCloseAmount = null;
582
+ parameters.rejectReceipt(new Error('WebSocket closed before the payment flow completed.'));
583
+ parameters.rejectCloseReady(new Error('WebSocket closed before the payment flow completed.'));
584
+ managedSocket.emit('close', {
585
+ code: event.code ?? 1000,
586
+ reason: event.reason ?? '',
587
+ type: 'close',
588
+ wasClean: true,
589
+ });
590
+ });
591
+ rawSocket.addEventListener('error', () => {
592
+ managedSocket.emit('error', { type: 'error' });
593
+ });
594
+ rawSocket.addEventListener('message', async (event) => {
595
+ const raw = typeof event.data === 'string' ? event.data : undefined;
596
+ if (!raw)
597
+ return;
598
+ await handleSocketMessage({
599
+ driver: parameters,
600
+ failSocketFlow,
601
+ managedEmit: managedSocket.emit,
602
+ message: raw,
603
+ rawSocket,
604
+ socketState,
605
+ });
606
+ });
607
+ options?.signal?.addEventListener('abort', () => {
608
+ parameters.rejectReceipt(new Error('WebSocket payment flow aborted.'));
609
+ parameters.rejectCloseReady(new Error('WebSocket payment flow aborted.'));
610
+ rawSocket.close();
611
+ }, { once: true });
612
+ await waitForSocketOpen(rawSocket, managedSocket.emit, wsUrl);
613
+ rawSocket.send(Ws.formatAuthorizationMessage(credential));
614
+ await parameters.waitForReceipt();
615
+ return managedSocket.socket;
616
+ }
617
+ function waitForSocketOpen(rawSocket, managedEmit, wsUrl) {
618
+ return new Promise((resolve, reject) => {
619
+ const onOpen = () => {
620
+ rawSocket.removeEventListener('error', onError);
621
+ managedEmit('open', { type: 'open' });
622
+ resolve();
623
+ };
624
+ const onError = () => {
625
+ rawSocket.removeEventListener('open', onOpen);
626
+ reject(new Error(`WebSocket connection to ${wsUrl} failed to open.`));
627
+ };
628
+ rawSocket.addEventListener('open', onOpen, { once: true });
629
+ rawSocket.addEventListener('error', onError, { once: true });
630
+ });
631
+ }
632
+ async function handleSocketMessage(parameters) {
633
+ const parsed = Ws.parseMessage(parameters.message);
634
+ if (!parsed) {
635
+ parameters.managedEmit('message', { data: parameters.message, type: 'message' });
636
+ return;
637
+ }
638
+ switch (parsed.mpp) {
639
+ case 'authorization':
640
+ return;
641
+ case 'message':
642
+ parameters.socketState.deliveredChunks += 1n;
643
+ parameters.managedEmit('message', { data: parsed.data, type: 'message' });
644
+ return;
645
+ case 'payment-close-ready':
646
+ handleCloseReady(parameters, parsed.data);
647
+ return;
648
+ case 'payment-error':
649
+ parameters.driver.rejectReceipt(new Error(parsed.message));
650
+ parameters.driver.rejectCloseReady(new Error(parsed.message));
651
+ return;
652
+ case 'payment-need-voucher':
653
+ await handleNeedVoucher(parameters, parsed.data);
654
+ return;
655
+ case 'payment-receipt':
656
+ handleReceipt(parameters, parsed.data);
657
+ return;
658
+ }
659
+ }
660
+ function handleCloseReady(parameters, receipt) {
661
+ const cumulativeAmount = parameters.driver.getChannel()?.cumulativeAmount ?? 0n;
662
+ const error = validateSocketCloseReadyReceipt({
663
+ challengeId: parameters.driver.challenge.id,
664
+ channelId: parameters.socketState.channelId,
665
+ cumulativeAmount,
666
+ receipt,
667
+ });
668
+ if (error) {
669
+ parameters.failSocketFlow(error);
670
+ return;
671
+ }
672
+ parameters.driver.acceptReceipt(receipt);
673
+ parameters.driver.options?.onReceipt?.(receipt);
674
+ parameters.driver.settleCloseReady(receipt);
675
+ parameters.managedEmit('close', {
676
+ code: 1000,
677
+ reason: 'stream complete',
678
+ type: 'close',
679
+ wasClean: true,
680
+ });
681
+ }
682
+ async function handleNeedVoucher(parameters, event) {
683
+ try {
684
+ const resolution = await resolveNeedVoucherContext({
685
+ assertVoucherWithinLocalLimit: parameters.driver.assertVoucherWithinLocalLimit,
686
+ challenge: parameters.driver.challenge,
687
+ event,
688
+ expectedChannelId: parameters.socketState.channelId,
689
+ getChannel: parameters.driver.getChannel,
690
+ input: parameters.driver.httpUrl,
691
+ topUpIfNeeded: parameters.driver.topUpIfNeeded,
692
+ });
693
+ if (resolution.status === 'ignored') {
694
+ parameters.failSocketFlow(resolution.reason === 'channel-mismatch'
695
+ ? 'received mismatched payment-need-voucher frame'
696
+ : 'cannot create voucher: no active channel');
697
+ return;
698
+ }
699
+ const voucher = await parameters.driver.createSessionCredential(parameters.driver.challenge, resolution.context);
700
+ parameters.rawSocket.send(Ws.formatAuthorizationMessage(voucher));
701
+ }
702
+ catch (error) {
703
+ parameters.failSocketFlow(error instanceof Error ? error.message : 'failed to create websocket voucher');
704
+ }
705
+ }
706
+ function handleReceipt(parameters, receipt) {
707
+ const error = validateSocketPaymentReceipt({
708
+ challengeId: parameters.driver.challenge.id,
709
+ channelId: parameters.socketState.channelId,
710
+ expectedCloseAmount: parameters.socketState.expectedCloseAmount,
711
+ receipt,
712
+ });
713
+ if (error) {
714
+ parameters.failSocketFlow(error);
715
+ return;
716
+ }
717
+ parameters.driver.acceptReceipt(receipt);
718
+ parameters.driver.options?.onReceipt?.(receipt);
719
+ parameters.driver.settleReceipt(receipt);
720
+ }
721
+ //# sourceMappingURL=Transports.js.map