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,470 @@
1
+ import {
2
+ isAddress,
3
+ isAddressEqual,
4
+ parseUnits,
5
+ zeroAddress,
6
+ type Account as viem_Account,
7
+ type Address,
8
+ type Hex,
9
+ } from 'viem'
10
+
11
+ import type * as Credential from '../../../Credential.js'
12
+ import {
13
+ BadRequestError,
14
+ ChannelClosedError,
15
+ ChannelNotFoundError,
16
+ InsufficientBalanceError,
17
+ VerificationFailedError,
18
+ } from '../../../Errors.js'
19
+ import type * as Method from '../../../Method.js'
20
+ import * as Store from '../../../Store.js'
21
+ import type * as FeePayer from '../../internal/fee-payer.js'
22
+ import { isSessionContentRequest } from '../../server/internal/request-body.js'
23
+ import * as Chain from '../precompile/Chain.js'
24
+ import { readSettledReceiptFields } from '../precompile/Chain.js'
25
+ import {
26
+ uint96,
27
+ type SessionCredentialPayload,
28
+ type SessionReceipt,
29
+ } from '../precompile/Protocol.js'
30
+ import * as ChannelStore from './ChannelStore.js'
31
+
32
+ /** Fee-payer parameter accepted by the server session method. */
33
+ export type ParameterFeePayer = viem_Account | string | true | undefined
34
+
35
+ /** Minimum method details needed to decide credential-time fee sponsorship. */
36
+ export type CredentialFeePayerMethodDetails = {
37
+ /** Whether the challenge advertised fee-payer support. */
38
+ feePayer?: boolean | undefined
39
+ }
40
+
41
+ /** Inputs used to resolve request-time fee sponsorship policy. */
42
+ export type ResolveRequestFeePayerParameters = {
43
+ /** Incoming credential, present for verification/management requests. */
44
+ credential: Credential.Credential | null | undefined
45
+ /** Default fee-payer account resolved from server parameters. */
46
+ defaultFeePayer?: viem_Account | undefined
47
+ /** Server-level fee-payer parameter. */
48
+ parameterFeePayer?: ParameterFeePayer
49
+ /** Per-request fee-payer override. */
50
+ requestFeePayer?: boolean | viem_Account | undefined
51
+ }
52
+
53
+ /** Inputs used to resolve credential-time fee sponsorship account. */
54
+ export type ResolveCredentialFeePayerParameters = {
55
+ /** Request object being verified. */
56
+ request: unknown
57
+ /** Challenge method details echoed by the credential. */
58
+ methodDetails: CredentialFeePayerMethodDetails
59
+ /** Default fee-payer account resolved from server parameters. */
60
+ feePayer?: viem_Account | undefined
61
+ }
62
+
63
+ /** Fee-payer value read from an untrusted credential challenge request. */
64
+ export type RequestFeePayerValue = boolean | viem_Account | undefined
65
+
66
+ function isObject(value: unknown): value is Record<string, unknown> {
67
+ return typeof value === 'object' && value !== null
68
+ }
69
+
70
+ function isAccount(value: unknown): value is viem_Account {
71
+ return isObject(value) && typeof value.address === 'string' && isAddress(value.address)
72
+ }
73
+
74
+ /** Reads the optional `feePayer` field from an untrusted request object. */
75
+ export function readRequestFeePayer(value: unknown): RequestFeePayerValue {
76
+ if (!isObject(value)) return undefined
77
+ const feePayer = value.feePayer
78
+ if (feePayer === undefined || typeof feePayer === 'boolean') return feePayer
79
+ if (isAccount(feePayer)) return feePayer
80
+ return undefined
81
+ }
82
+
83
+ /** Resolves whether a challenge should advertise fee sponsorship or a credential can use it. */
84
+ export function resolveRequestFeePayer(
85
+ parameters: ResolveRequestFeePayerParameters,
86
+ ): boolean | viem_Account | undefined {
87
+ const { credential, defaultFeePayer, parameterFeePayer, requestFeePayer } = parameters
88
+ if (requestFeePayer === false) return credential ? false : undefined
89
+
90
+ const account = typeof requestFeePayer === 'object' ? requestFeePayer : defaultFeePayer
91
+ if (credential) return account ?? undefined
92
+ if (account || defaultFeePayer || parameterFeePayer === true) return true
93
+ return undefined
94
+ }
95
+
96
+ /** Resolves the fee-payer account allowed for an incoming credential. */
97
+ export function resolveCredentialFeePayer(
98
+ parameters: ResolveCredentialFeePayerParameters,
99
+ ): viem_Account | undefined {
100
+ const { feePayer, methodDetails, request } = parameters
101
+ const requestFeePayer = readRequestFeePayer(request)
102
+ const requestAllowsFeePayer =
103
+ requestFeePayer === undefined || requestFeePayer === true || typeof requestFeePayer === 'object'
104
+ if (methodDetails.feePayer !== true || !requestAllowsFeePayer) return undefined
105
+ return typeof requestFeePayer === 'object' ? requestFeePayer : feePayer
106
+ }
107
+
108
+ /** Declarative server-side settlement cadence for automatic session settlement. */
109
+ export type SettlementSchedule = {
110
+ /** Settle after this many additional paid units since the previous scheduled settlement. */
111
+ units?: number | undefined
112
+ /** Settle after this much additional settlement amount since the previous scheduled settlement. */
113
+ amount?: string | bigint | undefined
114
+ /** Settle after this many milliseconds since the previous scheduled settlement. */
115
+ intervalMs?: number | undefined
116
+ }
117
+
118
+ /** Settlement schedule normalized into raw token units. */
119
+ export type ResolvedSettlementSchedule = {
120
+ /** Raw token amount threshold. */
121
+ amount?: bigint | undefined
122
+ /** Elapsed-time threshold since previous settlement. */
123
+ intervalMs?: number | undefined
124
+ /** Paid unit threshold. */
125
+ units?: number | undefined
126
+ }
127
+
128
+ /** Progress counters compared against a server-owned settlement schedule. */
129
+ export type SettlementProgress = {
130
+ /** Additional raw spend since the previous scheduled settlement boundary. */
131
+ amount: bigint
132
+ /** Milliseconds elapsed since the previous scheduled settlement boundary. */
133
+ elapsedMs?: number | undefined
134
+ /** Additional paid units since the previous scheduled settlement boundary. */
135
+ units: number
136
+ }
137
+
138
+ /** Inputs used to mark a channel after automatic scheduled settlement succeeds. */
139
+ export type MarkSettlementCompleteParameters = {
140
+ channelId: ChannelStore.State['channelId']
141
+ settledAt?: string | undefined
142
+ store: ChannelStore.ChannelStore
143
+ }
144
+
145
+ /** Converts a public settlement schedule into raw-unit thresholds. */
146
+ export function resolveSettlementSchedule(
147
+ schedule: SettlementSchedule | undefined,
148
+ decimals: number,
149
+ ): ResolvedSettlementSchedule | undefined {
150
+ if (!schedule) return undefined
151
+ return {
152
+ ...(schedule.amount !== undefined && {
153
+ amount:
154
+ typeof schedule.amount === 'bigint'
155
+ ? schedule.amount
156
+ : parseUnits(schedule.amount, decimals),
157
+ }),
158
+ ...(schedule.intervalMs !== undefined && { intervalMs: schedule.intervalMs }),
159
+ ...(schedule.units !== undefined && { units: schedule.units }),
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Computes the schedule progress for an unsettled precompile-backed channel.
165
+ *
166
+ * Returns `undefined` for channels that cannot be scheduled: non-precompile
167
+ * records, channels without an accepted voucher, or channels with no unsettled
168
+ * voucher amount.
169
+ */
170
+ export function resolveSettlementProgress(
171
+ channel: ChannelStore.State,
172
+ ): SettlementProgress | undefined {
173
+ if (!ChannelStore.isPrecompileState(channel)) return undefined
174
+ if (!channel.highestVoucher) return undefined
175
+ if (channel.highestVoucher.cumulativeAmount <= channel.settledOnChain) return undefined
176
+
177
+ const amountBoundary = channel.lastSettlementSpent ?? channel.settledOnChain
178
+ const timestampBoundary = Date.parse(channel.lastSettlementAt ?? channel.createdAt)
179
+
180
+ return {
181
+ amount: channel.spent - amountBoundary,
182
+ ...(Number.isFinite(timestampBoundary) && {
183
+ elapsedMs: Date.now() - timestampBoundary,
184
+ }),
185
+ units: channel.units - (channel.lastSettlementUnits ?? 0),
186
+ }
187
+ }
188
+
189
+ /** Returns whether the precompile channel has crossed any configured settlement threshold. */
190
+ export function isSettlementDue(
191
+ channel: ChannelStore.State,
192
+ schedule: ResolvedSettlementSchedule | undefined,
193
+ ): boolean {
194
+ if (!schedule) return false
195
+ const progress = resolveSettlementProgress(channel)
196
+ if (!progress) return false
197
+
198
+ if (schedule.units !== undefined && progress.units >= schedule.units) return true
199
+
200
+ if (schedule.amount !== undefined && progress.amount >= schedule.amount) return true
201
+
202
+ if (schedule.intervalMs !== undefined && (progress.elapsedMs ?? 0) >= schedule.intervalMs)
203
+ return true
204
+
205
+ return false
206
+ }
207
+
208
+ /** Records the channel spend/unit counters that a scheduled settlement captured. */
209
+ export async function markSettlementComplete(parameters: MarkSettlementCompleteParameters) {
210
+ const { channelId, store, settledAt = new Date().toISOString() } = parameters
211
+ await store.updateChannel(channelId, (current) =>
212
+ current
213
+ ? {
214
+ ...current,
215
+ lastSettlementAt: settledAt,
216
+ lastSettlementSpent: current.spent,
217
+ lastSettlementUnits: current.units,
218
+ }
219
+ : current,
220
+ )
221
+ }
222
+
223
+ /** Callback used by post-verification accounting to deduct spend from a channel. */
224
+ export type ChargeSessionChannel = (channelId: Hex, amount: bigint) => Promise<ChannelStore.State>
225
+
226
+ /** Callback used by post-verification accounting to run server-owned settlement policy. */
227
+ export type SettleChargedSessionChannel = (channel: ChannelStore.State) => Promise<Hex | undefined>
228
+
229
+ /** Inputs for charging a precompile-backed session channel. */
230
+ export type ChargeParameters = {
231
+ /** Server-side channel store. */
232
+ store: ChannelStore.ChannelStore
233
+ /** Channel ID to deduct from. */
234
+ channelId: Hex
235
+ /** Raw token amount to charge. */
236
+ amount: bigint
237
+ }
238
+
239
+ /** Inputs used to apply default HTTP request/response accounting after credential verification. */
240
+ export type ApplyVerifiedHttpAccountingParameters = {
241
+ /** Captured request metadata from the verified envelope, when this is a request-backed flow. */
242
+ capturedRequest?: Method.CapturedRequest | undefined
243
+ /** Deducts the configured request amount from channel spend. */
244
+ charge: ChargeSessionChannel
245
+ /** Returns the raw request amount to deduct for one content response. Called only when charging. */
246
+ getRequestAmount: () => bigint
247
+ /** Credential action that produced the receipt. Only open/voucher can pay for content. */
248
+ payloadAction: SessionCredentialPayload['action']
249
+ /** Receipt returned by credential verification before content accounting. */
250
+ receipt: SessionReceipt
251
+ /** Marks an SSE receipt whose first content unit was charged during verification. */
252
+ markPrepaidReceipt?: ((receipt: SessionReceipt) => SessionReceipt) | undefined
253
+ /** Whether SSE transport is enabled. SSE accounting is stream-driven, not HTTP-response-driven. */
254
+ sseEnabled: boolean
255
+ /** Runs optional server settlement policy after a successful content charge. */
256
+ settleCharged: SettleChargedSessionChannel
257
+ }
258
+
259
+ /** Applies the default HTTP content charge after a session credential has been accepted. */
260
+ export async function applyVerifiedHttpAccounting(
261
+ parameters: ApplyVerifiedHttpAccountingParameters,
262
+ ): Promise<SessionReceipt> {
263
+ const { capturedRequest, payloadAction, receipt, sseEnabled } = parameters
264
+ if (!capturedRequest) return receipt
265
+ if (!isSessionContentRequest(capturedRequest)) return receipt
266
+ if (payloadAction !== 'open' && payloadAction !== 'voucher') return receipt
267
+
268
+ const requestAmount = parameters.getRequestAmount()
269
+ const charged = await parameters.charge(receipt.channelId, requestAmount)
270
+ const settlementTxHash = await parameters.settleCharged(charged)
271
+ const chargedReceipt = {
272
+ ...receipt,
273
+ spent: charged.spent.toString(),
274
+ units: charged.units,
275
+ ...(settlementTxHash ? { txHash: settlementTxHash } : {}),
276
+ }
277
+ return sseEnabled
278
+ ? (parameters.markPrepaidReceipt?.(chargedReceipt) ?? chargedReceipt)
279
+ : chargedReceipt
280
+ }
281
+
282
+ /** Atomically deducts spend from a channel and maps store failures to typed session errors. */
283
+ export async function chargeSessionChannel(
284
+ parameters: ChargeParameters,
285
+ ): Promise<ChannelStore.State> {
286
+ const { store, channelId, amount } = parameters
287
+ let result: Awaited<ReturnType<typeof ChannelStore.deductFromChannel>>
288
+ try {
289
+ result = await ChannelStore.deductFromChannel(store, channelId, amount)
290
+ } catch {
291
+ throw new ChannelClosedError({ reason: 'channel not found' })
292
+ }
293
+ if (!result.ok) {
294
+ if (result.channel.finalized) throw new ChannelClosedError({ reason: 'channel is finalized' })
295
+ if (result.channel.closeRequestedAt !== 0n)
296
+ throw new ChannelClosedError({ reason: 'channel has a pending close request' })
297
+ const available = result.channel.highestVoucherAmount - result.channel.spent
298
+ throw new InsufficientBalanceError({
299
+ reason: `requested ${amount}, available ${available}`,
300
+ })
301
+ }
302
+ return result.channel
303
+ }
304
+
305
+ /** Store accepted by public settlement controls. */
306
+ export type SessionStoreInput = Store.Store | ChannelStore.ChannelStore
307
+
308
+ /** Inputs used to validate who may submit payee-side settlement transactions. */
309
+ export type SettlementSenderParameters = {
310
+ channelId: Hex
311
+ operation: 'close' | 'settle'
312
+ operator: Address
313
+ payee: Address
314
+ sender: Address | undefined
315
+ }
316
+
317
+ /** Options for server-driven precompile settlement transactions. */
318
+ export type SettlementTransactionOptions = {
319
+ /** Account used to send the settlement transaction. Defaults to the viem client account. */
320
+ account?: viem_Account | undefined
321
+ /** Candidate fee tokens for sponsored settlement. Defaults to the channel token. */
322
+ candidateFeeTokens?: readonly Address[] | undefined
323
+ /** TIP20EscrowChannel precompile address override. */
324
+ escrowContract?: Address | undefined
325
+ /** Optional fee-payer account for sponsored settlement. */
326
+ feePayer?: viem_Account | undefined
327
+ /** Optional policy for sponsored settlement. */
328
+ feePayerPolicy?: Partial<FeePayer.Policy> | undefined
329
+ /** Optional fee token override for settlement. */
330
+ feeToken?: Address | undefined
331
+ }
332
+
333
+ /** Inputs for applying a server-owned automatic settlement schedule. */
334
+ export type MaybeSettleScheduledParameters = {
335
+ /** Account used to send the settlement transaction. */
336
+ account?: viem_Account | undefined
337
+ /** Channel that was just charged. */
338
+ channel: ChannelStore.State
339
+ /** viem client used to settle on-chain. */
340
+ client: Chain.TransactionClient
341
+ /** Optional fee-payer account for sponsored settlement. */
342
+ feePayer?: viem_Account | undefined
343
+ /** Optional policy for sponsored settlement. */
344
+ feePayerPolicy?: Partial<FeePayer.Policy> | undefined
345
+ /** Optional fee token override for settlement. */
346
+ feeToken?: Address | undefined
347
+ /** Resolved server-owned settlement cadence. */
348
+ schedule: ResolvedSettlementSchedule | undefined
349
+ /** Server-side channel store. */
350
+ store: ChannelStore.ChannelStore
351
+ }
352
+
353
+ /** Resolves either a generic mppx store or an already-wrapped channel store. */
354
+ export function resolveChannelStore(store: SessionStoreInput): ChannelStore.ChannelStore {
355
+ return 'getChannel' in store ? store : ChannelStore.fromStore(store)
356
+ }
357
+
358
+ /** Returns the account attached to a viem client, when one exists. */
359
+ export function getClientAccount(client: { account?: viem_Account | undefined }) {
360
+ return client.account
361
+ }
362
+
363
+ /** Validates that the transaction sender is the channel payee or nonzero operator. */
364
+ export function assertSettlementSender(parameters: SettlementSenderParameters) {
365
+ const { operation, channelId, operator, payee, sender } = parameters
366
+ if (!sender)
367
+ throw new Error(
368
+ `Cannot ${operation} precompile channel ${channelId}: no account available. Pass an account override, or provide a getClient() that returns an account-bearing client.`,
369
+ )
370
+ if (isAddressEqual(sender, payee)) return
371
+ if (!isAddressEqual(operator, zeroAddress) && isAddressEqual(sender, operator)) return
372
+ throw new BadRequestError({
373
+ reason:
374
+ `Cannot ${operation} precompile channel ${channelId}: tx sender ${sender} is not the channel payee ${payee}` +
375
+ (isAddressEqual(operator, zeroAddress) ? '.' : ` or operator ${operator}.`) +
376
+ ' If using an access key, pass a Tempo access-key account whose address is the payee/operator wallet, not the raw delegated key address.',
377
+ })
378
+ }
379
+
380
+ /** Applies automatic settlement when the server-owned schedule is due. */
381
+ export async function maybeSettleScheduled(
382
+ parameters: MaybeSettleScheduledParameters,
383
+ ): Promise<Hex | undefined> {
384
+ const { channel, schedule, store } = parameters
385
+ if (!isSettlementDue(channel, schedule)) return undefined
386
+ const txHash = await settle(store, parameters.client, channel.channelId, {
387
+ account: parameters.account,
388
+ ...(parameters.feePayer ? { feePayer: parameters.feePayer } : {}),
389
+ ...(parameters.feePayerPolicy ? { feePayerPolicy: parameters.feePayerPolicy } : {}),
390
+ ...(parameters.feeToken ? { feeToken: parameters.feeToken } : {}),
391
+ })
392
+ await markSettlementComplete({ channelId: channel.channelId, store })
393
+ return txHash
394
+ }
395
+
396
+ /** Settles the highest accepted voucher for a precompile-backed session channel. */
397
+ export async function settle(
398
+ store_: SessionStoreInput,
399
+ client: Chain.TransactionClient,
400
+ channelId_: Hex,
401
+ options?: SettlementTransactionOptions,
402
+ ): Promise<Hex> {
403
+ const store = resolveChannelStore(store_)
404
+ const channelId = ChannelStore.normalizeChannelId(channelId_)
405
+ const channel = await store.getChannel(channelId)
406
+ if (!channel) throw new ChannelNotFoundError({ reason: 'channel not found' })
407
+ if (!ChannelStore.isPrecompileState(channel))
408
+ throw new VerificationFailedError({ reason: 'channel is not precompile-backed' })
409
+ if (!channel.highestVoucher) throw new VerificationFailedError({ reason: 'no voucher to settle' })
410
+ const escrow = options?.escrowContract ?? channel.escrowContract
411
+ const account = options?.account ?? getClientAccount(client)
412
+ assertSettlementSender({
413
+ operation: 'settle',
414
+ channelId,
415
+ operator: channel.operator,
416
+ payee: channel.payee,
417
+ sender: account?.address,
418
+ })
419
+ const amount = uint96(channel.highestVoucher.cumulativeAmount)
420
+ const txHash = await Chain.settleOnChain(
421
+ client,
422
+ channel.descriptor,
423
+ amount,
424
+ channel.highestVoucher.signature,
425
+ escrow,
426
+ account
427
+ ? {
428
+ account,
429
+ ...(options?.feePayer ? { feePayer: options.feePayer } : {}),
430
+ ...(options?.feePayerPolicy ? { feePayerPolicy: options.feePayerPolicy } : {}),
431
+ ...(options?.feeToken ? { feeToken: options.feeToken } : {}),
432
+ candidateFeeTokens: options?.candidateFeeTokens ?? [channel.token],
433
+ }
434
+ : undefined,
435
+ )
436
+ const receipt = await Chain.waitForSuccessfulReceipt(client, txHash)
437
+ const settled = readSettledReceiptFields(Chain.getChannelEvent(receipt, 'Settled', channelId))
438
+ const { newSettled } = settled
439
+ if (newSettled < amount)
440
+ throw new VerificationFailedError({ reason: 'Settled event is below voucher amount' })
441
+ const state = await Chain.getChannelState(client, channelId, escrow)
442
+ if (state.settled !== newSettled)
443
+ throw new VerificationFailedError({
444
+ reason: 'on-chain channel state does not match settle receipt',
445
+ })
446
+ await store.updateChannel(channelId, (current) =>
447
+ current
448
+ ? {
449
+ ...current,
450
+ settledOnChain: newSettled > current.settledOnChain ? newSettled : current.settledOnChain,
451
+ lastSettlementAt: new Date().toISOString(),
452
+ lastSettlementSpent: current.spent,
453
+ lastSettlementUnits: current.units,
454
+ }
455
+ : current,
456
+ )
457
+ return txHash
458
+ }
459
+
460
+ /** Settles multiple precompile-backed session channels with the same validation as {@link settle}. */
461
+ export async function settleBatch(
462
+ store: SessionStoreInput,
463
+ client: Chain.TransactionClient,
464
+ channelIds: readonly Hex[],
465
+ options?: SettlementTransactionOptions,
466
+ ): Promise<Hex[]> {
467
+ const hashes: Hex[] = []
468
+ for (const channelId of channelIds) hashes.push(await settle(store, client, channelId, options))
469
+ return hashes
470
+ }
@@ -1,11 +1,11 @@
1
1
  import type { Address, Hex } from 'viem'
2
2
  import { describe, expect, test } from 'vp/test'
3
3
 
4
- import { ChannelClosedError } from '../../Errors.js'
5
- import { chainId, escrowContract as escrowContractDefaults } from '../internal/defaults.js'
4
+ import { ChannelClosedError } from '../../../Errors.js'
5
+ import { chainId, escrowContract as escrowContractDefaults } from '../../internal/defaults.js'
6
+ import type { NeedVoucherEvent, SessionReceipt } from '../precompile/Protocol.js'
6
7
  import type * as ChannelStore from './ChannelStore.js'
7
8
  import { formatNeedVoucherEvent, formatReceiptEvent, parseEvent, serve } from './Sse.js'
8
- import type { NeedVoucherEvent, SessionReceipt } from './Types.js'
9
9
 
10
10
  const channelId = '0x0000000000000000000000000000000000000000000000000000000000000001' as Hex
11
11
  const challengeId = 'challenge-1'
@@ -369,6 +369,40 @@ describe('serve', () => {
369
369
  expect(all).toContain('event: payment-receipt\n')
370
370
  })
371
371
 
372
+ test('resumes when the client updates voucher state before reading the next stream chunk', async () => {
373
+ const storage = memoryStore()
374
+ await seedChannel(storage, 1000000n)
375
+
376
+ const streamResult = serve({
377
+ store: storage,
378
+ channelId,
379
+ challengeId,
380
+ tickCost: 1000000n,
381
+ generate: generate(['first', 'second']),
382
+ pollIntervalMs: 10,
383
+ })
384
+
385
+ const reader = streamResult.getReader()
386
+ const decoder = new TextDecoder()
387
+
388
+ const first = await reader.read()
389
+ expect(decoder.decode(first.value, { stream: true })).toContain(
390
+ 'event: message\ndata: first\n\n',
391
+ )
392
+
393
+ const need = await reader.read()
394
+ expect(decoder.decode(need.value, { stream: true })).toContain('event: payment-need-voucher\n')
395
+
396
+ await storage.updateChannel(channelId, (current) =>
397
+ current ? { ...current, highestVoucherAmount: 2000000n } : current,
398
+ )
399
+
400
+ const second = await reader.read()
401
+ expect(decoder.decode(second.value, { stream: true })).toContain(
402
+ 'event: message\ndata: second\n\n',
403
+ )
404
+ })
405
+
372
406
  test('respects abort signal', async () => {
373
407
  const storage = memoryStore()
374
408
  await seedChannel(storage, 10000000n)