mppx 0.6.31 → 0.8.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 (616) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +20 -11
  3. package/dist/Challenge.d.ts.map +1 -1
  4. package/dist/Challenge.js +27 -13
  5. package/dist/Challenge.js.map +1 -1
  6. package/dist/Constants.d.ts +46 -0
  7. package/dist/Constants.d.ts.map +1 -0
  8. package/dist/Constants.js +46 -0
  9. package/dist/Constants.js.map +1 -0
  10. package/dist/Credential.d.ts.map +1 -1
  11. package/dist/Credential.js +5 -4
  12. package/dist/Credential.js.map +1 -1
  13. package/dist/Mcp.d.ts +3 -0
  14. package/dist/Mcp.d.ts.map +1 -1
  15. package/dist/Mcp.js +2 -0
  16. package/dist/Mcp.js.map +1 -1
  17. package/dist/Method.d.ts +32 -4
  18. package/dist/Method.d.ts.map +1 -1
  19. package/dist/Method.js +5 -2
  20. package/dist/Method.js.map +1 -1
  21. package/dist/PaymentRequest.d.ts +10 -10
  22. package/dist/PaymentRequest.js +8 -8
  23. package/dist/Receipt.d.ts.map +1 -1
  24. package/dist/Receipt.js +3 -2
  25. package/dist/Receipt.js.map +1 -1
  26. package/dist/cli/cli.d.ts.map +1 -1
  27. package/dist/cli/cli.js +19 -11
  28. package/dist/cli/cli.js.map +1 -1
  29. package/dist/cli/plugins/tempo.d.ts.map +1 -1
  30. package/dist/cli/plugins/tempo.js +17 -6
  31. package/dist/cli/plugins/tempo.js.map +1 -1
  32. package/dist/cli/utils.d.ts +5 -0
  33. package/dist/cli/utils.d.ts.map +1 -1
  34. package/dist/cli/utils.js +10 -0
  35. package/dist/cli/utils.js.map +1 -1
  36. package/dist/client/Methods.d.ts +5 -2
  37. package/dist/client/Methods.d.ts.map +1 -1
  38. package/dist/client/Methods.js +5 -2
  39. package/dist/client/Methods.js.map +1 -1
  40. package/dist/client/Mppx.js +2 -2
  41. package/dist/client/Mppx.js.map +1 -1
  42. package/dist/client/Transport.d.ts +11 -16
  43. package/dist/client/Transport.d.ts.map +1 -1
  44. package/dist/client/Transport.js +55 -76
  45. package/dist/client/Transport.js.map +1 -1
  46. package/dist/client/index.d.ts +5 -1
  47. package/dist/client/index.d.ts.map +1 -1
  48. package/dist/client/index.js +3 -1
  49. package/dist/client/index.js.map +1 -1
  50. package/dist/client/internal/Fetch.d.ts.map +1 -1
  51. package/dist/client/internal/Fetch.js +60 -13
  52. package/dist/client/internal/Fetch.js.map +1 -1
  53. package/dist/client/internal/protocols/Mcp.d.ts +7 -0
  54. package/dist/client/internal/protocols/Mcp.d.ts.map +1 -0
  55. package/dist/client/internal/protocols/Mcp.js +159 -0
  56. package/dist/client/internal/protocols/Mcp.js.map +1 -0
  57. package/dist/client/internal/protocols/Mpp.d.ts +4 -0
  58. package/dist/client/internal/protocols/Mpp.d.ts.map +1 -0
  59. package/dist/client/internal/protocols/Mpp.js +18 -0
  60. package/dist/client/internal/protocols/Mpp.js.map +1 -0
  61. package/dist/client/internal/protocols/Protocol.d.ts +10 -0
  62. package/dist/client/internal/protocols/Protocol.d.ts.map +1 -0
  63. package/dist/client/internal/protocols/Protocol.js +2 -0
  64. package/dist/client/internal/protocols/Protocol.js.map +1 -0
  65. package/dist/client/internal/protocols/Shared.d.ts +5 -0
  66. package/dist/client/internal/protocols/Shared.d.ts.map +1 -0
  67. package/dist/client/internal/protocols/Shared.js +20 -0
  68. package/dist/client/internal/protocols/Shared.js.map +1 -0
  69. package/dist/client/internal/protocols/X402.d.ts +8 -0
  70. package/dist/client/internal/protocols/X402.d.ts.map +1 -0
  71. package/dist/client/internal/protocols/X402.js +39 -0
  72. package/dist/client/internal/protocols/X402.js.map +1 -0
  73. package/dist/evm/client/index.d.ts +1 -0
  74. package/dist/evm/client/index.d.ts.map +1 -1
  75. package/dist/evm/client/index.js +1 -0
  76. package/dist/evm/client/index.js.map +1 -1
  77. package/dist/evm/index.d.ts +2 -0
  78. package/dist/evm/index.d.ts.map +1 -1
  79. package/dist/evm/index.js +2 -0
  80. package/dist/evm/index.js.map +1 -1
  81. package/dist/evm/server/Methods.d.ts +1 -1
  82. package/dist/evm/server/Methods.d.ts.map +1 -1
  83. package/dist/evm/server/index.d.ts +1 -0
  84. package/dist/evm/server/index.d.ts.map +1 -1
  85. package/dist/evm/server/index.js +1 -0
  86. package/dist/evm/server/index.js.map +1 -1
  87. package/dist/index.d.ts +1 -0
  88. package/dist/index.d.ts.map +1 -1
  89. package/dist/index.js +1 -0
  90. package/dist/index.js.map +1 -1
  91. package/dist/internal/AcceptPayment.d.ts +3 -0
  92. package/dist/internal/AcceptPayment.d.ts.map +1 -1
  93. package/dist/internal/AcceptPayment.js +15 -11
  94. package/dist/internal/AcceptPayment.js.map +1 -1
  95. package/dist/mcp/client/McpClient.d.ts +101 -0
  96. package/dist/mcp/client/McpClient.d.ts.map +1 -0
  97. package/dist/mcp/client/McpClient.js +162 -0
  98. package/dist/mcp/client/McpClient.js.map +1 -0
  99. package/dist/mcp/client/index.d.ts.map +1 -0
  100. package/dist/mcp/client/index.js.map +1 -0
  101. package/dist/mcp/server/Transport.d.ts.map +1 -0
  102. package/dist/mcp/server/Transport.js.map +1 -0
  103. package/dist/mcp/server/index.d.ts.map +1 -0
  104. package/dist/mcp/server/index.js.map +1 -0
  105. package/dist/server/Mppx.d.ts +12 -4
  106. package/dist/server/Mppx.d.ts.map +1 -1
  107. package/dist/server/Mppx.js +85 -27
  108. package/dist/server/Mppx.js.map +1 -1
  109. package/dist/server/Response.d.ts.map +1 -1
  110. package/dist/server/Response.js +2 -1
  111. package/dist/server/Response.js.map +1 -1
  112. package/dist/server/Transport.d.ts +1 -1
  113. package/dist/server/Transport.d.ts.map +1 -1
  114. package/dist/server/Transport.js +5 -4
  115. package/dist/server/Transport.js.map +1 -1
  116. package/dist/server/index.d.ts +1 -0
  117. package/dist/server/index.d.ts.map +1 -1
  118. package/dist/server/index.js +1 -0
  119. package/dist/server/index.js.map +1 -1
  120. package/dist/stripe/client/Charge.d.ts +1 -1
  121. package/dist/stripe/client/Charge.d.ts.map +1 -1
  122. package/dist/stripe/client/Charge.js +3 -1
  123. package/dist/stripe/client/Charge.js.map +1 -1
  124. package/dist/stripe/server/Charge.d.ts +1 -1
  125. package/dist/stripe/server/Charge.d.ts.map +1 -1
  126. package/dist/stripe/server/Charge.js +9 -2
  127. package/dist/stripe/server/Charge.js.map +1 -1
  128. package/dist/stripe/server/Methods.d.ts +1 -1
  129. package/dist/stripe/server/Methods.d.ts.map +1 -1
  130. package/dist/stripe/server/internal/html.gen.d.ts +1 -1
  131. package/dist/stripe/server/internal/html.gen.d.ts.map +1 -1
  132. package/dist/stripe/server/internal/html.gen.js +1 -1
  133. package/dist/stripe/server/internal/html.gen.js.map +1 -1
  134. package/dist/tempo/Methods.d.ts +18 -0
  135. package/dist/tempo/Methods.d.ts.map +1 -1
  136. package/dist/tempo/Methods.js +16 -1
  137. package/dist/tempo/Methods.js.map +1 -1
  138. package/dist/tempo/Proof.d.ts +85 -1
  139. package/dist/tempo/Proof.d.ts.map +1 -1
  140. package/dist/tempo/Proof.js +35 -0
  141. package/dist/tempo/Proof.js.map +1 -1
  142. package/dist/tempo/client/Charge.d.ts +19 -1
  143. package/dist/tempo/client/Charge.d.ts.map +1 -1
  144. package/dist/tempo/client/Charge.js +47 -27
  145. package/dist/tempo/client/Charge.js.map +1 -1
  146. package/dist/tempo/client/Methods.d.ts +41 -10
  147. package/dist/tempo/client/Methods.d.ts.map +1 -1
  148. package/dist/tempo/client/Methods.js +16 -7
  149. package/dist/tempo/client/Methods.js.map +1 -1
  150. package/dist/tempo/client/ResolveAccount.d.ts +40 -0
  151. package/dist/tempo/client/ResolveAccount.d.ts.map +1 -0
  152. package/dist/tempo/client/ResolveAccount.js +2 -0
  153. package/dist/tempo/client/ResolveAccount.js.map +1 -0
  154. package/dist/tempo/client/index.d.ts +7 -4
  155. package/dist/tempo/client/index.d.ts.map +1 -1
  156. package/dist/tempo/client/index.js +5 -3
  157. package/dist/tempo/client/index.js.map +1 -1
  158. package/dist/tempo/index.d.ts +1 -0
  159. package/dist/tempo/index.d.ts.map +1 -1
  160. package/dist/tempo/index.js +1 -0
  161. package/dist/tempo/index.js.map +1 -1
  162. package/dist/tempo/internal/fee-payer.d.ts +29 -1
  163. package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
  164. package/dist/tempo/internal/fee-payer.js +138 -4
  165. package/dist/tempo/internal/fee-payer.js.map +1 -1
  166. package/dist/tempo/internal/proof.d.ts +71 -5
  167. package/dist/tempo/internal/proof.d.ts.map +1 -1
  168. package/dist/tempo/internal/proof.js +42 -6
  169. package/dist/tempo/internal/proof.js.map +1 -1
  170. package/dist/tempo/{client → legacy/client}/ChannelOps.d.ts +19 -6
  171. package/dist/tempo/legacy/client/ChannelOps.d.ts.map +1 -0
  172. package/dist/tempo/{client → legacy/client}/ChannelOps.js +9 -3
  173. package/dist/tempo/legacy/client/ChannelOps.js.map +1 -0
  174. package/dist/tempo/{client → legacy/client}/Session.d.ts +23 -4
  175. package/dist/tempo/legacy/client/Session.d.ts.map +1 -0
  176. package/dist/tempo/{client → legacy/client}/Session.js +14 -7
  177. package/dist/tempo/legacy/client/Session.js.map +1 -0
  178. package/dist/tempo/{client → legacy/client}/SessionManager.d.ts +20 -5
  179. package/dist/tempo/legacy/client/SessionManager.d.ts.map +1 -0
  180. package/dist/tempo/{client → legacy/client}/SessionManager.js +30 -19
  181. package/dist/tempo/legacy/client/SessionManager.js.map +1 -0
  182. package/dist/tempo/legacy/client/index.d.ts +7 -0
  183. package/dist/tempo/legacy/client/index.d.ts.map +1 -0
  184. package/dist/tempo/legacy/client/index.js +5 -0
  185. package/dist/tempo/legacy/client/index.js.map +1 -0
  186. package/dist/tempo/legacy/index.d.ts +7 -0
  187. package/dist/tempo/legacy/index.d.ts.map +1 -0
  188. package/dist/tempo/legacy/index.js +7 -0
  189. package/dist/tempo/legacy/index.js.map +1 -0
  190. package/dist/tempo/{server → legacy/server}/Session.d.ts +28 -11
  191. package/dist/tempo/legacy/server/Session.d.ts.map +1 -0
  192. package/dist/tempo/{server → legacy/server}/Session.js +12 -10
  193. package/dist/tempo/legacy/server/Session.js.map +1 -0
  194. package/dist/tempo/legacy/server/index.d.ts +5 -0
  195. package/dist/tempo/legacy/server/index.d.ts.map +1 -0
  196. package/dist/tempo/legacy/server/index.js +5 -0
  197. package/dist/tempo/legacy/server/index.js.map +1 -0
  198. package/dist/tempo/{session → legacy/session}/Chain.d.ts +30 -23
  199. package/dist/tempo/legacy/session/Chain.d.ts.map +1 -0
  200. package/dist/tempo/{session → legacy/session}/Chain.js +12 -11
  201. package/dist/tempo/legacy/session/Chain.js.map +1 -0
  202. package/dist/tempo/{session → legacy/session}/Channel.d.ts +1 -0
  203. package/dist/tempo/legacy/session/Channel.d.ts.map +1 -0
  204. package/dist/tempo/legacy/session/Channel.js.map +1 -0
  205. package/dist/tempo/legacy/session/ChannelStore.d.ts +22 -0
  206. package/dist/tempo/legacy/session/ChannelStore.d.ts.map +1 -0
  207. package/dist/tempo/legacy/session/ChannelStore.js +6 -0
  208. package/dist/tempo/legacy/session/ChannelStore.js.map +1 -0
  209. package/dist/tempo/legacy/session/Types.d.ts +73 -0
  210. package/dist/tempo/legacy/session/Types.d.ts.map +1 -0
  211. package/dist/tempo/legacy/session/Types.js.map +1 -0
  212. package/dist/tempo/{session → legacy/session}/Voucher.d.ts +4 -4
  213. package/dist/tempo/legacy/session/Voucher.d.ts.map +1 -0
  214. package/dist/tempo/{session → legacy/session}/Voucher.js +1 -1
  215. package/dist/tempo/legacy/session/Voucher.js.map +1 -0
  216. package/dist/tempo/{session → legacy/session}/escrow.abi.d.ts +1 -0
  217. package/dist/tempo/{session → legacy/session}/escrow.abi.d.ts.map +1 -1
  218. package/dist/tempo/{session → legacy/session}/escrow.abi.js +1 -0
  219. package/dist/tempo/legacy/session/escrow.abi.js.map +1 -0
  220. package/dist/tempo/legacy/session/index.d.ts +9 -0
  221. package/dist/tempo/legacy/session/index.d.ts.map +1 -0
  222. package/dist/tempo/legacy/session/index.js +9 -0
  223. package/dist/tempo/legacy/session/index.js.map +1 -0
  224. package/dist/tempo/server/Charge.d.ts +1 -1
  225. package/dist/tempo/server/Charge.d.ts.map +1 -1
  226. package/dist/tempo/server/Charge.js +51 -30
  227. package/dist/tempo/server/Charge.js.map +1 -1
  228. package/dist/tempo/server/Methods.d.ts +67 -8
  229. package/dist/tempo/server/Methods.d.ts.map +1 -1
  230. package/dist/tempo/server/Methods.js +40 -10
  231. package/dist/tempo/server/Methods.js.map +1 -1
  232. package/dist/tempo/server/Subscription.d.ts +11 -1
  233. package/dist/tempo/server/Subscription.d.ts.map +1 -1
  234. package/dist/tempo/server/Subscription.js +135 -23
  235. package/dist/tempo/server/Subscription.js.map +1 -1
  236. package/dist/tempo/server/index.d.ts +6 -5
  237. package/dist/tempo/server/index.d.ts.map +1 -1
  238. package/dist/tempo/server/index.js +5 -5
  239. package/dist/tempo/server/index.js.map +1 -1
  240. package/dist/tempo/server/internal/html.gen.d.ts +1 -1
  241. package/dist/tempo/server/internal/html.gen.d.ts.map +1 -1
  242. package/dist/tempo/server/internal/html.gen.js +1 -1
  243. package/dist/tempo/server/internal/html.gen.js.map +1 -1
  244. package/dist/tempo/server/internal/request-body.d.ts +7 -2
  245. package/dist/tempo/server/internal/request-body.d.ts.map +1 -1
  246. package/dist/tempo/server/internal/request-body.js +20 -3
  247. package/dist/tempo/server/internal/request-body.js.map +1 -1
  248. package/dist/tempo/server/internal/transport.d.ts +8 -4
  249. package/dist/tempo/server/internal/transport.d.ts.map +1 -1
  250. package/dist/tempo/server/internal/transport.js +8 -7
  251. package/dist/tempo/server/internal/transport.js.map +1 -1
  252. package/dist/tempo/session/Snapshot.d.ts +32 -0
  253. package/dist/tempo/session/Snapshot.d.ts.map +1 -0
  254. package/dist/tempo/session/Snapshot.js +37 -0
  255. package/dist/tempo/session/Snapshot.js.map +1 -0
  256. package/dist/tempo/session/client/ChannelOps.d.ts +81 -0
  257. package/dist/tempo/session/client/ChannelOps.d.ts.map +1 -0
  258. package/dist/tempo/session/client/ChannelOps.js +201 -0
  259. package/dist/tempo/session/client/ChannelOps.js.map +1 -0
  260. package/dist/tempo/session/client/ChannelStore.d.ts +51 -0
  261. package/dist/tempo/session/client/ChannelStore.d.ts.map +1 -0
  262. package/dist/tempo/session/client/ChannelStore.js +63 -0
  263. package/dist/tempo/session/client/ChannelStore.js.map +1 -0
  264. package/dist/tempo/session/client/CredentialState.d.ts +245 -0
  265. package/dist/tempo/session/client/CredentialState.d.ts.map +1 -0
  266. package/dist/tempo/session/client/CredentialState.js +419 -0
  267. package/dist/tempo/session/client/CredentialState.js.map +1 -0
  268. package/dist/tempo/session/client/ReceiptCoordinator.d.ts +26 -0
  269. package/dist/tempo/session/client/ReceiptCoordinator.d.ts.map +1 -0
  270. package/dist/tempo/session/client/ReceiptCoordinator.js +61 -0
  271. package/dist/tempo/session/client/ReceiptCoordinator.js.map +1 -0
  272. package/dist/tempo/session/client/Runtime.d.ts +464 -0
  273. package/dist/tempo/session/client/Runtime.d.ts.map +1 -0
  274. package/dist/tempo/session/client/Runtime.js +499 -0
  275. package/dist/tempo/session/client/Runtime.js.map +1 -0
  276. package/dist/tempo/session/client/Session.d.ts +138 -0
  277. package/dist/tempo/session/client/Session.d.ts.map +1 -0
  278. package/dist/tempo/session/client/Session.js +69 -0
  279. package/dist/tempo/session/client/Session.js.map +1 -0
  280. package/dist/tempo/session/client/SessionManager.d.ts +84 -0
  281. package/dist/tempo/session/client/SessionManager.d.ts.map +1 -0
  282. package/dist/tempo/session/client/SessionManager.js +577 -0
  283. package/dist/tempo/session/client/SessionManager.js.map +1 -0
  284. package/dist/tempo/session/client/Transports.d.ts +449 -0
  285. package/dist/tempo/session/client/Transports.d.ts.map +1 -0
  286. package/dist/tempo/session/client/Transports.js +721 -0
  287. package/dist/tempo/session/client/Transports.js.map +1 -0
  288. package/dist/tempo/session/client/index.d.ts +11 -0
  289. package/dist/tempo/session/client/index.d.ts.map +1 -0
  290. package/dist/tempo/session/client/index.js +6 -0
  291. package/dist/tempo/session/client/index.js.map +1 -0
  292. package/dist/tempo/session/index.d.ts +7 -8
  293. package/dist/tempo/session/index.d.ts.map +1 -1
  294. package/dist/tempo/session/index.js +7 -8
  295. package/dist/tempo/session/index.js.map +1 -1
  296. package/dist/tempo/session/precompile/Chain.d.ts +319 -0
  297. package/dist/tempo/session/precompile/Chain.d.ts.map +1 -0
  298. package/dist/tempo/session/precompile/Chain.js +492 -0
  299. package/dist/tempo/session/precompile/Chain.js.map +1 -0
  300. package/dist/tempo/session/precompile/Channel.d.ts +46 -0
  301. package/dist/tempo/session/precompile/Channel.d.ts.map +1 -0
  302. package/dist/tempo/session/precompile/Channel.js +56 -0
  303. package/dist/tempo/session/precompile/Channel.js.map +1 -0
  304. package/dist/tempo/session/precompile/Protocol.d.ts +308 -0
  305. package/dist/tempo/session/precompile/Protocol.d.ts.map +1 -0
  306. package/dist/tempo/session/precompile/Protocol.js +264 -0
  307. package/dist/tempo/session/precompile/Protocol.js.map +1 -0
  308. package/dist/tempo/session/precompile/Voucher.d.ts +40 -0
  309. package/dist/tempo/session/precompile/Voucher.d.ts.map +1 -0
  310. package/dist/tempo/session/precompile/Voucher.js +125 -0
  311. package/dist/tempo/session/precompile/Voucher.js.map +1 -0
  312. package/dist/tempo/session/precompile/escrow.abi.d.ts +522 -0
  313. package/dist/tempo/session/precompile/escrow.abi.d.ts.map +1 -0
  314. package/dist/tempo/session/precompile/escrow.abi.js +224 -0
  315. package/dist/tempo/session/precompile/escrow.abi.js.map +1 -0
  316. package/dist/tempo/session/precompile/index.d.ts +24 -0
  317. package/dist/tempo/session/precompile/index.d.ts.map +1 -0
  318. package/dist/tempo/session/precompile/index.js +22 -0
  319. package/dist/tempo/session/precompile/index.js.map +1 -0
  320. package/dist/tempo/session/server/ChannelOps.d.ts +56 -0
  321. package/dist/tempo/session/server/ChannelOps.d.ts.map +1 -0
  322. package/dist/tempo/session/server/ChannelOps.js +91 -0
  323. package/dist/tempo/session/server/ChannelOps.js.map +1 -0
  324. package/dist/tempo/session/server/ChannelStore.d.ts +347 -0
  325. package/dist/tempo/session/server/ChannelStore.d.ts.map +1 -0
  326. package/dist/tempo/session/server/ChannelStore.js +404 -0
  327. package/dist/tempo/session/server/ChannelStore.js.map +1 -0
  328. package/dist/tempo/session/server/CredentialVerification.d.ts +85 -0
  329. package/dist/tempo/session/server/CredentialVerification.d.ts.map +1 -0
  330. package/dist/tempo/session/server/CredentialVerification.js +494 -0
  331. package/dist/tempo/session/server/CredentialVerification.js.map +1 -0
  332. package/dist/tempo/session/server/MeteredStream.d.ts +40 -0
  333. package/dist/tempo/session/server/MeteredStream.d.ts.map +1 -0
  334. package/dist/tempo/session/server/MeteredStream.js +42 -0
  335. package/dist/tempo/session/server/MeteredStream.js.map +1 -0
  336. package/dist/tempo/session/server/RequestState.d.ts +208 -0
  337. package/dist/tempo/session/server/RequestState.d.ts.map +1 -0
  338. package/dist/tempo/session/server/RequestState.js +252 -0
  339. package/dist/tempo/session/server/RequestState.js.map +1 -0
  340. package/dist/tempo/session/server/Session.d.ts +169 -0
  341. package/dist/tempo/session/server/Session.d.ts.map +1 -0
  342. package/dist/tempo/session/server/Session.js +351 -0
  343. package/dist/tempo/session/server/Session.js.map +1 -0
  344. package/dist/tempo/session/server/Settlement.d.ts +185 -0
  345. package/dist/tempo/session/server/Settlement.d.ts.map +1 -0
  346. package/dist/tempo/session/server/Settlement.js +252 -0
  347. package/dist/tempo/session/server/Settlement.js.map +1 -0
  348. package/dist/tempo/session/{Sse.d.ts → server/Sse.d.ts} +9 -56
  349. package/dist/tempo/session/server/Sse.d.ts.map +1 -0
  350. package/dist/tempo/session/server/Sse.js +184 -0
  351. package/dist/tempo/session/server/Sse.js.map +1 -0
  352. package/dist/tempo/session/server/Transports.d.ts +89 -0
  353. package/dist/tempo/session/server/Transports.d.ts.map +1 -0
  354. package/dist/tempo/session/server/Transports.js +149 -0
  355. package/dist/tempo/session/server/Transports.js.map +1 -0
  356. package/dist/tempo/session/server/Ws.d.ts +48 -0
  357. package/dist/tempo/session/server/Ws.d.ts.map +1 -0
  358. package/dist/tempo/session/server/Ws.js +244 -0
  359. package/dist/tempo/session/server/Ws.js.map +1 -0
  360. package/dist/tempo/session/server/index.d.ts +4 -0
  361. package/dist/tempo/session/server/index.d.ts.map +1 -0
  362. package/dist/tempo/session/server/index.js +2 -0
  363. package/dist/tempo/session/server/index.js.map +1 -0
  364. package/dist/tempo/subscription/KeyAuthorization.d.ts +712 -1
  365. package/dist/tempo/subscription/KeyAuthorization.d.ts.map +1 -1
  366. package/dist/tempo/subscription/Store.d.ts +2 -0
  367. package/dist/tempo/subscription/Store.d.ts.map +1 -1
  368. package/dist/tempo/subscription/Store.js +16 -1
  369. package/dist/tempo/subscription/Store.js.map +1 -1
  370. package/dist/x402/index.d.ts +1 -0
  371. package/dist/x402/index.d.ts.map +1 -1
  372. package/dist/x402/index.js +1 -0
  373. package/dist/x402/index.js.map +1 -1
  374. package/package.json +25 -9
  375. package/src/Challenge.test.ts +40 -0
  376. package/src/Challenge.ts +28 -13
  377. package/src/Constants.ts +58 -0
  378. package/src/Credential.ts +5 -4
  379. package/src/Mcp.ts +4 -0
  380. package/src/Method.ts +46 -5
  381. package/src/PaymentRequest.ts +10 -10
  382. package/src/Receipt.ts +3 -2
  383. package/src/cli/cli.test.ts +38 -43
  384. package/src/cli/cli.ts +23 -10
  385. package/src/cli/mcp.test.ts +21 -7
  386. package/src/cli/plugins/tempo.ts +21 -8
  387. package/src/cli/utils.test.ts +25 -1
  388. package/src/cli/utils.ts +10 -0
  389. package/src/client/Methods.ts +5 -2
  390. package/src/client/Mppx.test-d.ts +31 -1
  391. package/src/client/Mppx.test.ts +76 -1
  392. package/src/client/Mppx.ts +2 -2
  393. package/src/client/Transport.test.ts +225 -178
  394. package/src/client/Transport.ts +77 -84
  395. package/src/client/index.ts +25 -1
  396. package/src/client/internal/Fetch.test.ts +236 -6
  397. package/src/client/internal/Fetch.ts +69 -11
  398. package/src/client/internal/protocols/Mcp.test.ts +220 -0
  399. package/src/client/internal/protocols/Mcp.ts +162 -0
  400. package/src/client/internal/protocols/Mpp.ts +21 -0
  401. package/src/client/internal/protocols/Protocol.ts +10 -0
  402. package/src/client/internal/protocols/Shared.ts +25 -0
  403. package/src/client/internal/protocols/X402.ts +42 -0
  404. package/src/discovery/OpenApi.test.ts +1 -1
  405. package/src/env.d.ts +1 -1
  406. package/src/evm/PublicInterface.test-d.ts +1 -1
  407. package/src/evm/client/index.ts +1 -0
  408. package/src/evm/index.ts +2 -0
  409. package/src/evm/server/Charge.test.ts +1 -1
  410. package/src/evm/server/index.ts +1 -0
  411. package/src/index.ts +1 -0
  412. package/src/internal/AcceptPayment.test.ts +61 -0
  413. package/src/internal/AcceptPayment.ts +21 -14
  414. package/src/{mcp-sdk → mcp}/client/McpClient.integration.test.ts +18 -11
  415. package/src/{mcp-sdk → mcp}/client/McpClient.test-d.ts +45 -11
  416. package/src/{mcp-sdk → mcp}/client/McpClient.test.ts +211 -5
  417. package/src/mcp/client/McpClient.ts +307 -0
  418. package/src/mcp/client/McpClient.unit.test.ts +135 -0
  419. package/src/middlewares/elysia.test.ts +9 -5
  420. package/src/middlewares/express.test.ts +9 -5
  421. package/src/middlewares/hono.test.ts +5 -5
  422. package/src/middlewares/internal/mppx.test.ts +1 -1
  423. package/src/middlewares/nextjs.test.ts +9 -5
  424. package/src/proxy/Proxy.test.ts +9 -9
  425. package/src/proxy/services/anthropic.test.ts +1 -1
  426. package/src/proxy/services/openai.test.ts +1 -1
  427. package/src/proxy/services/stripe.test.ts +1 -1
  428. package/src/server/Mppx.authorize.test.ts +1 -1
  429. package/src/server/Mppx.test-d.ts +55 -1
  430. package/src/server/Mppx.test.ts +220 -9
  431. package/src/server/Mppx.ts +501 -407
  432. package/src/server/Response.ts +2 -1
  433. package/src/server/Transport.test.ts +6 -6
  434. package/src/server/Transport.ts +5 -4
  435. package/src/server/index.ts +1 -0
  436. package/src/stripe/Charge.integration.test.ts +1 -1
  437. package/src/stripe/client/Charge.test.ts +21 -6
  438. package/src/stripe/client/Charge.ts +6 -2
  439. package/src/stripe/server/Charge.test.ts +115 -2
  440. package/src/stripe/server/Charge.ts +13 -2
  441. package/src/stripe/server/internal/html/package.json +1 -1
  442. package/src/stripe/server/internal/html.gen.ts +1 -1
  443. package/src/tempo/AccessKeyAuthorization.test.ts +4 -94
  444. package/src/tempo/Methods.test.ts +45 -17
  445. package/src/tempo/Methods.ts +22 -0
  446. package/src/tempo/Proof.conformance.test.ts +146 -0
  447. package/src/tempo/Proof.test-d.ts +15 -0
  448. package/src/tempo/Proof.ts +52 -1
  449. package/src/tempo/PublicExports.test-d.ts +105 -0
  450. package/src/tempo/Subscription.integration.test.ts +1 -1
  451. package/src/tempo/client/Charge.test.ts +258 -0
  452. package/src/tempo/client/Charge.ts +84 -38
  453. package/src/tempo/client/Methods.ts +22 -8
  454. package/src/tempo/client/ResolveAccount.ts +46 -0
  455. package/src/tempo/client/index.ts +15 -4
  456. package/src/tempo/index.ts +1 -0
  457. package/src/tempo/internal/fee-payer.test.ts +296 -17
  458. package/src/tempo/internal/fee-payer.ts +186 -4
  459. package/src/tempo/internal/fee-token.test.ts +14 -9
  460. package/src/tempo/internal/proof.test.ts +12 -4
  461. package/src/tempo/internal/proof.ts +55 -6
  462. package/src/tempo/legacy/AccessKeyAuthorization.test.ts +162 -0
  463. package/src/tempo/legacy/README.md +9 -0
  464. package/src/tempo/{client → legacy/client}/ChannelOps.test.ts +6 -7
  465. package/src/tempo/{client → legacy/client}/ChannelOps.ts +22 -9
  466. package/src/tempo/{client → legacy/client}/Session.test.ts +51 -9
  467. package/src/tempo/{client → legacy/client}/Session.ts +25 -11
  468. package/src/tempo/{client → legacy/client}/SessionManager.test.ts +81 -9
  469. package/src/tempo/{client → legacy/client}/SessionManager.ts +52 -23
  470. package/src/tempo/legacy/client/index.ts +6 -0
  471. package/src/tempo/legacy/index.ts +6 -0
  472. package/src/tempo/{server → legacy/server}/Session.test.ts +136 -71
  473. package/src/tempo/{server → legacy/server}/Session.ts +32 -23
  474. package/src/tempo/legacy/server/index.ts +4 -0
  475. package/src/tempo/{session → legacy/session}/Chain.test.ts +3 -4
  476. package/src/tempo/{session → legacy/session}/Chain.ts +94 -63
  477. package/src/tempo/{session → legacy/session}/Channel.ts +1 -0
  478. package/src/tempo/legacy/session/ChannelStore.test.ts +58 -0
  479. package/src/tempo/legacy/session/ChannelStore.ts +39 -0
  480. package/src/tempo/legacy/session/Types.ts +91 -0
  481. package/src/tempo/{session → legacy/session}/Voucher.ts +12 -8
  482. package/src/tempo/{session → legacy/session}/escrow.abi.ts +1 -0
  483. package/src/tempo/legacy/session/index.ts +8 -0
  484. package/src/tempo/server/AtomicStore.test-d.ts +16 -11
  485. package/src/tempo/server/Charge.test.ts +480 -31
  486. package/src/tempo/server/Charge.ts +54 -30
  487. package/src/tempo/server/Methods.ts +58 -10
  488. package/src/tempo/server/Sse.test.ts +2 -2
  489. package/src/tempo/server/Subscription.test.ts +465 -3
  490. package/src/tempo/server/Subscription.ts +174 -19
  491. package/src/tempo/server/index.ts +6 -5
  492. package/src/tempo/server/internal/html/package.json +2 -2
  493. package/src/tempo/server/internal/html.gen.ts +1 -1
  494. package/src/tempo/server/internal/request-body.test.ts +37 -4
  495. package/src/tempo/server/internal/request-body.ts +25 -6
  496. package/src/tempo/server/internal/transport.test.ts +4 -4
  497. package/src/tempo/server/internal/transport.ts +19 -10
  498. package/src/tempo/session/Snapshot.test.ts +41 -0
  499. package/src/tempo/session/Snapshot.ts +74 -0
  500. package/src/tempo/session/client/ChannelOps.test.ts +163 -0
  501. package/src/tempo/session/client/ChannelOps.ts +330 -0
  502. package/src/tempo/session/client/ChannelStore.ts +111 -0
  503. package/src/tempo/session/client/CredentialState.test.ts +789 -0
  504. package/src/tempo/session/client/CredentialState.ts +799 -0
  505. package/src/tempo/session/client/ReceiptCoordinator.ts +95 -0
  506. package/src/tempo/session/client/Runtime.test.ts +1092 -0
  507. package/src/tempo/session/client/Runtime.ts +986 -0
  508. package/src/tempo/session/client/Session.test.ts +774 -0
  509. package/src/tempo/session/client/Session.ts +123 -0
  510. package/src/tempo/session/client/SessionManager.test.ts +1397 -0
  511. package/src/tempo/session/client/SessionManager.ts +751 -0
  512. package/src/tempo/session/client/Transports.test.ts +837 -0
  513. package/src/tempo/session/client/Transports.ts +1292 -0
  514. package/src/tempo/session/client/index.ts +40 -0
  515. package/src/tempo/session/index.ts +7 -8
  516. package/src/tempo/session/precompile/Chain.integration.test.ts +321 -0
  517. package/src/tempo/session/precompile/Chain.test.ts +1258 -0
  518. package/src/tempo/session/precompile/Chain.ts +979 -0
  519. package/src/tempo/session/precompile/Channel.test.ts +138 -0
  520. package/src/tempo/session/precompile/Channel.ts +103 -0
  521. package/src/tempo/session/precompile/Protocol.test.ts +358 -0
  522. package/src/tempo/session/precompile/Protocol.ts +520 -0
  523. package/src/tempo/session/precompile/Voucher.test.ts +354 -0
  524. package/src/tempo/session/precompile/Voucher.ts +162 -0
  525. package/src/tempo/session/precompile/escrow.abi.ts +226 -0
  526. package/src/tempo/session/precompile/index.ts +33 -0
  527. package/src/tempo/session/server/ChannelOps.test.ts +129 -0
  528. package/src/tempo/session/server/ChannelOps.ts +157 -0
  529. package/src/tempo/session/{ChannelStore.test.ts → server/ChannelStore.test.ts} +536 -29
  530. package/src/tempo/session/server/ChannelStore.ts +835 -0
  531. package/src/tempo/session/server/CredentialVerification.test.ts +146 -0
  532. package/src/tempo/session/server/CredentialVerification.ts +710 -0
  533. package/src/tempo/session/server/MeteredStream.ts +88 -0
  534. package/src/tempo/session/server/RequestState.test.ts +531 -0
  535. package/src/tempo/session/server/RequestState.ts +499 -0
  536. package/src/tempo/session/server/Session.integration.test.ts +444 -0
  537. package/src/tempo/session/server/Session.test.ts +3253 -0
  538. package/src/tempo/session/server/Session.ts +543 -0
  539. package/src/tempo/session/server/Settlement.test.ts +329 -0
  540. package/src/tempo/session/server/Settlement.ts +471 -0
  541. package/src/tempo/session/{Sse.test.ts → server/Sse.test.ts} +37 -3
  542. package/src/tempo/session/server/Sse.ts +254 -0
  543. package/src/tempo/session/server/Transports.test.ts +346 -0
  544. package/src/tempo/session/server/Transports.ts +255 -0
  545. package/src/tempo/session/{Ws.test.ts → server/Ws.test.ts} +4 -4
  546. package/src/tempo/session/server/Ws.ts +380 -0
  547. package/src/tempo/session/server/index.ts +8 -0
  548. package/src/tempo/subscription/Store.ts +27 -9
  549. package/src/x402/Exact.e2e.test.ts +1 -1
  550. package/src/x402/PublicInterface.test-d.ts +1 -1
  551. package/src/x402/index.ts +1 -0
  552. package/dist/mcp-sdk/client/McpClient.d.ts +0 -78
  553. package/dist/mcp-sdk/client/McpClient.d.ts.map +0 -1
  554. package/dist/mcp-sdk/client/McpClient.js +0 -105
  555. package/dist/mcp-sdk/client/McpClient.js.map +0 -1
  556. package/dist/mcp-sdk/client/index.d.ts.map +0 -1
  557. package/dist/mcp-sdk/client/index.js.map +0 -1
  558. package/dist/mcp-sdk/server/Transport.d.ts.map +0 -1
  559. package/dist/mcp-sdk/server/Transport.js.map +0 -1
  560. package/dist/mcp-sdk/server/index.d.ts.map +0 -1
  561. package/dist/mcp-sdk/server/index.js.map +0 -1
  562. package/dist/tempo/client/ChannelOps.d.ts.map +0 -1
  563. package/dist/tempo/client/ChannelOps.js.map +0 -1
  564. package/dist/tempo/client/Session.d.ts.map +0 -1
  565. package/dist/tempo/client/Session.js.map +0 -1
  566. package/dist/tempo/client/SessionManager.d.ts.map +0 -1
  567. package/dist/tempo/client/SessionManager.js.map +0 -1
  568. package/dist/tempo/server/Session.d.ts.map +0 -1
  569. package/dist/tempo/server/Session.js.map +0 -1
  570. package/dist/tempo/session/Chain.d.ts.map +0 -1
  571. package/dist/tempo/session/Chain.js.map +0 -1
  572. package/dist/tempo/session/Channel.d.ts.map +0 -1
  573. package/dist/tempo/session/Channel.js.map +0 -1
  574. package/dist/tempo/session/ChannelStore.d.ts +0 -117
  575. package/dist/tempo/session/ChannelStore.d.ts.map +0 -1
  576. package/dist/tempo/session/ChannelStore.js +0 -172
  577. package/dist/tempo/session/ChannelStore.js.map +0 -1
  578. package/dist/tempo/session/Receipt.d.ts +0 -22
  579. package/dist/tempo/session/Receipt.d.ts.map +0 -1
  580. package/dist/tempo/session/Receipt.js +0 -34
  581. package/dist/tempo/session/Receipt.js.map +0 -1
  582. package/dist/tempo/session/Sse.d.ts.map +0 -1
  583. package/dist/tempo/session/Sse.js +0 -363
  584. package/dist/tempo/session/Sse.js.map +0 -1
  585. package/dist/tempo/session/Types.d.ts +0 -78
  586. package/dist/tempo/session/Types.d.ts.map +0 -1
  587. package/dist/tempo/session/Types.js.map +0 -1
  588. package/dist/tempo/session/Voucher.d.ts.map +0 -1
  589. package/dist/tempo/session/Voucher.js.map +0 -1
  590. package/dist/tempo/session/Ws.d.ts +0 -87
  591. package/dist/tempo/session/Ws.d.ts.map +0 -1
  592. package/dist/tempo/session/Ws.js +0 -443
  593. package/dist/tempo/session/Ws.js.map +0 -1
  594. package/dist/tempo/session/escrow.abi.js.map +0 -1
  595. package/src/mcp-sdk/client/McpClient.ts +0 -196
  596. package/src/tempo/session/ChannelStore.ts +0 -308
  597. package/src/tempo/session/Receipt.test.ts +0 -89
  598. package/src/tempo/session/Receipt.ts +0 -46
  599. package/src/tempo/session/Sse.ts +0 -462
  600. package/src/tempo/session/Types.ts +0 -86
  601. package/src/tempo/session/Ws.ts +0 -576
  602. /package/dist/{mcp-sdk → mcp}/client/index.d.ts +0 -0
  603. /package/dist/{mcp-sdk → mcp}/client/index.js +0 -0
  604. /package/dist/{mcp-sdk → mcp}/server/Transport.d.ts +0 -0
  605. /package/dist/{mcp-sdk → mcp}/server/Transport.js +0 -0
  606. /package/dist/{mcp-sdk → mcp}/server/index.d.ts +0 -0
  607. /package/dist/{mcp-sdk → mcp}/server/index.js +0 -0
  608. /package/dist/tempo/{session → legacy/session}/Channel.js +0 -0
  609. /package/dist/tempo/{session → legacy/session}/Types.js +0 -0
  610. /package/src/{mcp-sdk → mcp}/client/index.ts +0 -0
  611. /package/src/{mcp-sdk → mcp}/server/Transport.test.ts +0 -0
  612. /package/src/{mcp-sdk → mcp}/server/Transport.ts +0 -0
  613. /package/src/{mcp-sdk → mcp}/server/index.ts +0 -0
  614. /package/src/tempo/{session → legacy/session}/Channel.test.ts +0 -0
  615. /package/src/tempo/{session → legacy/session}/Voucher.test.ts +0 -0
  616. /package/src/tempo/session/{Sse.fuzz.test.ts → server/Sse.fuzz.test.ts} +0 -0
@@ -0,0 +1,835 @@
1
+ import type { Address, Hex } from 'viem'
2
+
3
+ import type * as Challenge from '../../../Challenge.js'
4
+ import {
5
+ AmountExceedsDepositError,
6
+ ChannelClosedError,
7
+ ChannelNotFoundError,
8
+ DeltaTooSmallError,
9
+ InvalidSignatureError,
10
+ VerificationFailedError,
11
+ } from '../../../Errors.js'
12
+ import type * as Store from '../../../Store.js'
13
+ import type * as Chain from '../precompile/Chain.js'
14
+ import type * as PrecompileChannel from '../precompile/Channel.js'
15
+ import { createSessionReceipt } from '../precompile/Protocol.js'
16
+ import type { SessionReceipt, SessionSignedVoucher } from '../precompile/Protocol.js'
17
+ import { uint96, type SignedVoucher } from '../precompile/Protocol.js'
18
+ import * as Voucher from '../precompile/Voucher.js'
19
+ import {
20
+ assertSameDescriptor,
21
+ validateChannelDescriptor,
22
+ validateChannelState,
23
+ } from './CredentialVerification.js'
24
+ import type { SessionMethodDetails } from './RequestState.js'
25
+
26
+ /**
27
+ * State for an on-chain payment channel, including per-session accounting.
28
+ *
29
+ * Tracks the channel's identity, on-chain balance, the highest voucher
30
+ * the server has accepted, and the current session's spend counters.
31
+ * A channel is created when a payer opens an escrow on-chain and persists
32
+ * until the channel is finalized (closed/settled).
33
+ *
34
+ * One channel = one session. The client owns the key and can't race with
35
+ * itself, so concurrent session support is unnecessary.
36
+ *
37
+ * Monotonicity invariants (enforced by update callbacks):
38
+ * - `highestVoucherAmount` only increases
39
+ * - `settledOnChain` only increases
40
+ * - `deposit` reflects the latest on-chain value
41
+ */
42
+ export type State = BaseState & BackendState
43
+
44
+ /** Result of an atomic channel deduction attempt. */
45
+ export type DeductResult = { ok: true; channel: State } | { ok: false; channel: State }
46
+
47
+ /** Persisted channel state after narrowing to the TIP-1034 precompile backend. */
48
+ export type StoredPrecompileChannel = BaseState & PrecompileBackendState
49
+
50
+ /** On-chain state fields read from the TIP-1034 precompile. */
51
+ export type OnChainChannelState = {
52
+ /** Current on-chain channel deposit. */
53
+ deposit: bigint
54
+ /** Cumulative amount settled on-chain. */
55
+ settled: bigint
56
+ /** Close-request timestamp, or zero when open. */
57
+ closeRequestedAt: number | bigint
58
+ }
59
+
60
+ /** Persisted fields that mirror authoritative on-chain channel state. */
61
+ export type ActiveOnChainStateFields = Pick<
62
+ State,
63
+ 'closeRequestedAt' | 'deposit' | 'settledOnChain'
64
+ >
65
+
66
+ /** Parameters for selecting the persisted highest accepted voucher. */
67
+ export type HighestVoucherParameters = {
68
+ /** Channel ID used when constructing a new voucher record. */
69
+ channelId: Hex
70
+ /** Existing persisted voucher amount and signature, when present. */
71
+ current?: Pick<State, 'highestVoucher' | 'highestVoucherAmount'> | null | undefined
72
+ /** Candidate cumulative voucher amount. */
73
+ cumulativeAmount: bigint
74
+ /** Candidate voucher signature. */
75
+ signature: Hex
76
+ }
77
+
78
+ /** Highest accepted voucher amount plus signed voucher payload. */
79
+ export type HighestVoucher = {
80
+ /** Highest cumulative voucher amount to persist. */
81
+ highestVoucherAmount: bigint
82
+ /** Signed voucher corresponding to `highestVoucherAmount`. */
83
+ highestVoucher: SessionSignedVoucher | null
84
+ }
85
+
86
+ /** Inputs for resolving the amount a close transaction should capture. */
87
+ export type ResolveCloseCaptureAmountParameters = {
88
+ /** Close voucher cumulative amount. */
89
+ cumulativeAmount: bigint
90
+ /** Current on-chain deposit. */
91
+ onChainDeposit: bigint
92
+ /** Current on-chain settled amount. */
93
+ onChainSettled: bigint
94
+ /** Locally recorded paid spend. */
95
+ spent: bigint
96
+ }
97
+
98
+ /** Inputs used when persisting or reconciling a successful open transaction. */
99
+ export type OpenChannelStateParameters = {
100
+ /** Address stored as the effective voucher signer for this channel. */
101
+ authorizedSigner: Address
102
+ /** Chain ID used by the opened channel. */
103
+ chainId: number
104
+ /** Normalized channel ID. */
105
+ channelId: Hex
106
+ /** Existing channel state, when one was already persisted. */
107
+ current: State | null
108
+ /** Descriptor verified from the open transaction. */
109
+ descriptor: PrecompileChannel.ChannelDescriptor
110
+ /** Escrow precompile address used by the channel. */
111
+ escrow: Address
112
+ /** Transaction-bound expiring nonce hash from the open call. */
113
+ expiringNonceHash: Hex
114
+ /** Initial or highest accepted cumulative voucher amount. */
115
+ cumulativeAmount: bigint
116
+ /** Voucher signature for `cumulativeAmount`. */
117
+ signature: Hex
118
+ /** Latest on-chain channel state read after open. */
119
+ state: Chain.ChannelState
120
+ }
121
+
122
+ /** Inputs for merging a successful top-up transaction into persisted channel state. */
123
+ export type TopUpStateParameters = {
124
+ /** Existing channel state, when one is currently persisted. */
125
+ current: State | null
126
+ /** Latest verified on-chain channel state read after top-up. */
127
+ state: Chain.ChannelState
128
+ }
129
+
130
+ /** Inputs for merging a newly accepted voucher with persisted channel state. */
131
+ export type AcceptVoucherStateUpdateParameters = {
132
+ /** Latest on-chain channel state used to validate the voucher. */
133
+ channelState: Chain.ChannelState
134
+ /** Existing channel state being updated. */
135
+ current: State | null
136
+ /** Verified signed voucher. */
137
+ voucher: SessionSignedVoucher
138
+ }
139
+
140
+ /** Inputs for marking a channel as pending cooperative close. */
141
+ export type MarkPendingCloseParameters = {
142
+ /** Timestamp used to mark the local pending-close state. */
143
+ closeRequestedAt: bigint
144
+ /** Close voucher cumulative amount. */
145
+ cumulativeAmount: bigint
146
+ /** Existing channel state being updated. */
147
+ current: State | null
148
+ /** Current on-chain deposit. */
149
+ onChainDeposit: bigint
150
+ /** Current on-chain settled amount. */
151
+ onChainSettled: bigint
152
+ }
153
+
154
+ /** Result of preparing local state for a cooperative close. */
155
+ export type PendingCloseUpdate = {
156
+ /** Amount that should be captured on-chain at close. */
157
+ captureAmount: bigint
158
+ /** Next local channel state, or null if no channel exists. */
159
+ state: State | null
160
+ }
161
+
162
+ /** Inputs for finalizing local state after a successful close transaction. */
163
+ export type FinalizeClosedChannelParameters = {
164
+ /** Amount captured to payee during close. */
165
+ captureAmount: bigint
166
+ /** Normalized channel ID. */
167
+ channelId: Hex
168
+ /** Close voucher cumulative amount. */
169
+ cumulativeAmount: bigint
170
+ /** Existing channel state being updated. */
171
+ current: State | null
172
+ /** Close voucher signature. */
173
+ signature: Hex
174
+ }
175
+
176
+ /** Immutable channel identity fields derived from a verified TIP-1034 descriptor. */
177
+ export type PrecompileChannelIdentity = Pick<
178
+ BaseState & PrecompileBackendState,
179
+ | 'authorizedSigner'
180
+ | 'backend'
181
+ | 'chainId'
182
+ | 'channelId'
183
+ | 'descriptor'
184
+ | 'escrowContract'
185
+ | 'expiringNonceHash'
186
+ | 'operator'
187
+ | 'payee'
188
+ | 'payer'
189
+ | 'salt'
190
+ | 'token'
191
+ >
192
+
193
+ /** Inputs used to derive immutable persisted channel identity fields. */
194
+ export type ResolvePrecompileChannelIdentityParameters = {
195
+ /** Address stored as the effective voucher signer for this channel. */
196
+ authorizedSigner: Address
197
+ /** Chain ID used by the opened channel. */
198
+ chainId: number
199
+ /** Normalized channel ID. */
200
+ channelId: Hex
201
+ /** Descriptor verified from the open transaction. */
202
+ descriptor: PrecompileChannel.ChannelDescriptor
203
+ /** Escrow precompile address used by the channel. */
204
+ escrow: Address
205
+ /** Transaction-bound expiring nonce hash from the open call. */
206
+ expiringNonceHash: Hex
207
+ }
208
+
209
+ /** Inputs for reading a persisted precompile channel and validating its descriptor. */
210
+ export type LoadPrecompileChannelParameters = {
211
+ /** Channel ID to read from the server store. */
212
+ channelId: Hex
213
+ /** Chain ID used to rederive the channel descriptor. */
214
+ chainId: number
215
+ /** Descriptor supplied by the credential payload. */
216
+ descriptor: StoredPrecompileChannel['descriptor']
217
+ /** Escrow precompile address used to derive the channel ID. */
218
+ escrow: Address
219
+ /** Server channel store. */
220
+ store: ChannelStore
221
+ /** Whether to also validate descriptor identity against chain/payee/token fields. */
222
+ validateDescriptor?: boolean | undefined
223
+ }
224
+
225
+ /** Inputs for validating a signed voucher and merging it into channel state. */
226
+ export type VerifyAndAcceptVoucherParameters = {
227
+ /** Credential challenge used to bind the returned receipt. */
228
+ challenge: Challenge.Challenge
229
+ /** Persisted channel state before voucher acceptance. */
230
+ channel: State
231
+ /** Latest on-chain state used as the deposit/settled authority. */
232
+ channelState: Chain.ChannelState
233
+ /** Session method details used for voucher signature domain separation. */
234
+ methodDetails: SessionMethodDetails
235
+ /** Minimum allowed voucher delta in raw units. */
236
+ minVoucherDelta: bigint
237
+ /** Server channel store. */
238
+ store: ChannelStore
239
+ /** Signed cumulative voucher to verify and accept. */
240
+ voucher: SignedVoucher
241
+ }
242
+
243
+ /** Channel backend-specific fields. */
244
+ export type BackendState = CompatibilityBackendState | PrecompileBackendState
245
+
246
+ /** State for records owned by a backend outside the TIP-1034 precompile path. */
247
+ export interface CompatibilityBackendState {
248
+ /** Optional backend marker for older stored records. */
249
+ backend?: 'contract' | 'external' | undefined
250
+ }
251
+
252
+ /** State for a TIP20EscrowChannel precompile-backed payment channel. */
253
+ export interface PrecompileBackendState {
254
+ /** Channel backend. */
255
+ backend: 'precompile'
256
+ /** Descriptor used to derive the channel's identity. */
257
+ descriptor: PrecompileChannel.ChannelDescriptor
258
+ /** Transaction-bound nonce hash used to derive the channel's identity. */
259
+ expiringNonceHash: Hex
260
+ /** Address authorized to operate the channel. */
261
+ operator: Address
262
+ /** Salt used to derive the channel's identity. */
263
+ salt: Hex
264
+ }
265
+
266
+ /** Common persisted state for every session channel backend. */
267
+ export interface BaseState {
268
+ /** Address authorized to sign vouchers on behalf of the payer. */
269
+ authorizedSigner: Address
270
+ /** Chain ID the channel was opened on. */
271
+ chainId: number
272
+ /** Escrow contract address the channel was opened on. */
273
+ escrowContract: Address
274
+ /** Unique identifier for this payment channel. */
275
+ channelId: Hex
276
+ /** On-chain timestamp when a force-close was requested (0n if not requested). */
277
+ closeRequestedAt: bigint
278
+ /** ISO 8601 timestamp when the channel was created. */
279
+ createdAt: string
280
+ /** Current on-chain deposit in the escrow contract. */
281
+ deposit: bigint
282
+ /** Whether the channel has been finalized (closed) on-chain. */
283
+ finalized: boolean
284
+ /** The signed voucher corresponding to `highestVoucherAmount`. */
285
+ highestVoucher: SessionSignedVoucher | null
286
+ /** Highest cumulative voucher amount accepted by the server. */
287
+ highestVoucherAmount: bigint
288
+ /** Address of the payment recipient. */
289
+ payee: Address
290
+ /** Address of the payment sender. */
291
+ payer: Address
292
+ /** Cumulative amount settled on-chain so far. */
293
+ settledOnChain: bigint
294
+ /** Cumulative amount spent (charged) against this channel's current session. */
295
+ spent: bigint
296
+ /** Token contract address used for payments. */
297
+ token: Address
298
+ /** Number of charge operations (API requests) fulfilled in the current session. */
299
+ units: number
300
+ /** ISO 8601 timestamp of the last server-scheduled settlement. */
301
+ lastSettlementAt?: string | undefined
302
+ /** Cumulative spent value when the last server-scheduled settlement ran. */
303
+ lastSettlementSpent?: bigint | undefined
304
+ /** Charge operation count when the last server-scheduled settlement ran. */
305
+ lastSettlementUnits?: number | undefined
306
+ }
307
+
308
+ /** Returns whether a channel is backed by the TIP20EscrowChannel precompile. */
309
+ export function isPrecompileState(state: State): state is BaseState & PrecompileBackendState {
310
+ return state.backend === 'precompile'
311
+ }
312
+
313
+ /** Returns the greater bigint value without decreasing persisted monotonic state. */
314
+ export function keepGreater(current: bigint, next: bigint): bigint {
315
+ return current > next ? current : next
316
+ }
317
+
318
+ /** Returns the greater close-request timestamp as a bigint. */
319
+ export function keepGreaterTimestamp(current: bigint, next: number | bigint): bigint {
320
+ return keepGreater(current, BigInt(next))
321
+ }
322
+
323
+ /** Keeps local active-channel state in sync with authoritative on-chain reads. */
324
+ export function mergeActiveOnChainState(
325
+ current: Partial<ActiveOnChainStateFields> | null | undefined,
326
+ state: OnChainChannelState,
327
+ ): ActiveOnChainStateFields {
328
+ return {
329
+ closeRequestedAt: keepGreaterTimestamp(current?.closeRequestedAt ?? 0n, state.closeRequestedAt),
330
+ deposit: keepGreater(current?.deposit ?? 0n, state.deposit),
331
+ settledOnChain: keepGreater(current?.settledOnChain ?? 0n, state.settled),
332
+ }
333
+ }
334
+
335
+ /** Keeps the existing higher voucher, otherwise stores the supplied candidate voucher. */
336
+ export function resolveHighestVoucher(parameters: HighestVoucherParameters): HighestVoucher {
337
+ const { channelId, current, cumulativeAmount, signature } = parameters
338
+ if (current?.highestVoucherAmount && current.highestVoucherAmount > cumulativeAmount) {
339
+ return {
340
+ highestVoucherAmount: current.highestVoucherAmount,
341
+ highestVoucher: current.highestVoucher,
342
+ }
343
+ }
344
+
345
+ return {
346
+ highestVoucherAmount: cumulativeAmount,
347
+ highestVoucher: { channelId, cumulativeAmount, signature },
348
+ }
349
+ }
350
+
351
+ /** Derives persisted identity fields from a verified precompile channel descriptor. */
352
+ export function resolvePrecompileChannelIdentity(
353
+ parameters: ResolvePrecompileChannelIdentityParameters,
354
+ ): PrecompileChannelIdentity {
355
+ const { authorizedSigner, chainId, channelId, descriptor, escrow, expiringNonceHash } = parameters
356
+ return {
357
+ authorizedSigner,
358
+ backend: 'precompile',
359
+ chainId,
360
+ channelId,
361
+ descriptor,
362
+ escrowContract: escrow,
363
+ expiringNonceHash,
364
+ operator: descriptor.operator,
365
+ payee: descriptor.payee,
366
+ payer: descriptor.payer,
367
+ salt: descriptor.salt,
368
+ token: descriptor.token,
369
+ }
370
+ }
371
+
372
+ /** Builds the persisted state for a verified precompile channel open. */
373
+ export function openChannelState(parameters: OpenChannelStateParameters): State {
374
+ const { authorizedSigner, chainId, channelId, current, descriptor, escrow, expiringNonceHash } =
375
+ parameters
376
+ const { state } = parameters
377
+ const { cumulativeAmount, signature } = parameters
378
+ const highestVoucher = resolveHighestVoucher({
379
+ channelId,
380
+ current,
381
+ cumulativeAmount,
382
+ signature,
383
+ })
384
+ const onChain = mergeActiveOnChainState(current, state)
385
+ return {
386
+ ...(current ?? {}),
387
+ ...resolvePrecompileChannelIdentity({
388
+ authorizedSigner,
389
+ chainId,
390
+ channelId,
391
+ descriptor,
392
+ escrow,
393
+ expiringNonceHash,
394
+ }),
395
+ closeRequestedAt: onChain.closeRequestedAt,
396
+ deposit: onChain.deposit,
397
+ settledOnChain: onChain.settledOnChain,
398
+ highestVoucherAmount: highestVoucher.highestVoucherAmount,
399
+ highestVoucher: highestVoucher.highestVoucher,
400
+ spent: keepGreater(current?.spent ?? 0n, state.settled),
401
+ units: current?.units ?? 0,
402
+ finalized: current?.finalized ?? false,
403
+ createdAt: current?.createdAt ?? new Date().toISOString(),
404
+ }
405
+ }
406
+
407
+ /** Merges top-up on-chain state into persisted channel state without decreasing monotonic fields. */
408
+ export function topUpChannelState(parameters: TopUpStateParameters): State | null {
409
+ const { current, state } = parameters
410
+ if (!current) return current
411
+ return {
412
+ ...current,
413
+ ...mergeActiveOnChainState(current, state),
414
+ }
415
+ }
416
+
417
+ /** Merges an accepted voucher into persisted channel state after signature and on-chain checks pass. */
418
+ export function acceptVoucherStateUpdate(parameters: AcceptVoucherStateUpdateParameters): State {
419
+ const { channelState, current, voucher } = parameters
420
+ if (!current) throw new ChannelNotFoundError({ reason: 'channel not found' })
421
+ if (current.finalized) throw new ChannelClosedError({ reason: 'channel is finalized' })
422
+ if (current.closeRequestedAt !== 0n)
423
+ throw new ChannelClosedError({ reason: 'channel has a pending close request' })
424
+
425
+ const onChain = mergeActiveOnChainState(current, channelState)
426
+
427
+ if (voucher.cumulativeAmount <= current.highestVoucherAmount) {
428
+ return { ...current, ...onChain }
429
+ }
430
+
431
+ return {
432
+ ...current,
433
+ ...onChain,
434
+ highestVoucherAmount: voucher.cumulativeAmount,
435
+ highestVoucher: voucher,
436
+ }
437
+ }
438
+
439
+ /**
440
+ * Resolves the close capture amount and validates it is covered by both the
441
+ * close voucher and current on-chain deposit.
442
+ */
443
+ export function resolveCloseCaptureAmount(parameters: ResolveCloseCaptureAmountParameters): bigint {
444
+ const { cumulativeAmount, onChainDeposit, onChainSettled, spent } = parameters
445
+ if (cumulativeAmount < spent) {
446
+ throw new VerificationFailedError({
447
+ reason: `close voucher amount must be >= ${spent} (spent)`,
448
+ })
449
+ }
450
+
451
+ const captureAmount = uint96(spent > onChainSettled ? spent : onChainSettled)
452
+ if (captureAmount > cumulativeAmount) {
453
+ throw new VerificationFailedError({
454
+ reason: `close voucher amount must be >= ${captureAmount} (capture amount)`,
455
+ })
456
+ }
457
+ if (captureAmount > onChainDeposit) {
458
+ throw new AmountExceedsDepositError({
459
+ reason: 'close capture amount exceeds on-chain deposit',
460
+ })
461
+ }
462
+ return captureAmount
463
+ }
464
+
465
+ /** Marks local channel state as pending close and returns the bounded capture amount. */
466
+ export function markPendingClose(parameters: MarkPendingCloseParameters): PendingCloseUpdate {
467
+ const { closeRequestedAt, cumulativeAmount, current, onChainSettled, onChainDeposit } = parameters
468
+ if (!current) return { captureAmount: 0n, state: null }
469
+ if (current.finalized) throw new ChannelClosedError({ reason: 'channel is already finalized' })
470
+ if (current.closeRequestedAt !== 0n)
471
+ throw new ChannelClosedError({ reason: 'channel has a pending close request' })
472
+ const captureAmount = resolveCloseCaptureAmount({
473
+ cumulativeAmount,
474
+ onChainDeposit,
475
+ onChainSettled,
476
+ spent: current.spent,
477
+ })
478
+
479
+ return {
480
+ captureAmount,
481
+ state: { ...current, closeRequestedAt },
482
+ }
483
+ }
484
+
485
+ /** Finalizes local channel state after a successful close transaction. */
486
+ export function finalizeClosedChannelState(
487
+ parameters: FinalizeClosedChannelParameters,
488
+ ): State | null {
489
+ const { captureAmount, channelId, cumulativeAmount, current, signature } = parameters
490
+ if (!current) return current
491
+ const highestVoucher = resolveHighestVoucher({
492
+ channelId,
493
+ current,
494
+ cumulativeAmount,
495
+ signature,
496
+ })
497
+ return {
498
+ ...current,
499
+ finalized: true,
500
+ closeRequestedAt: 0n,
501
+ deposit: 0n,
502
+ settledOnChain: keepGreater(current.settledOnChain, captureAmount),
503
+ highestVoucherAmount: highestVoucher.highestVoucherAmount,
504
+ highestVoucher: highestVoucher.highestVoucher,
505
+ }
506
+ }
507
+
508
+ /** Loads a precompile-backed channel or throws a verification error. */
509
+ export async function loadPrecompileChannel(
510
+ parameters: LoadPrecompileChannelParameters,
511
+ ): Promise<StoredPrecompileChannel> {
512
+ const { channelId, chainId, descriptor, escrow, store } = parameters
513
+ const channel = await store.getChannel(channelId)
514
+ if (!channel) throw new ChannelNotFoundError({ reason: 'channel not found' })
515
+ if (!isPrecompileState(channel))
516
+ throw new VerificationFailedError({ reason: 'channel is not precompile-backed' })
517
+ assertSameDescriptor(descriptor, channel.descriptor)
518
+ if (parameters.validateDescriptor)
519
+ validateChannelDescriptor(descriptor, channelId, chainId, escrow, channel.payee, channel.token)
520
+ return channel
521
+ }
522
+
523
+ /** Verifies a cumulative voucher and returns a session receipt after store reconciliation. */
524
+ export async function verifyAndAcceptVoucher(
525
+ parameters: VerifyAndAcceptVoucherParameters,
526
+ ): Promise<SessionReceipt> {
527
+ const { store, minVoucherDelta, challenge, channel, voucher, channelState, methodDetails } =
528
+ parameters
529
+
530
+ validateChannelState(channelState)
531
+ if (voucher.cumulativeAmount > channelState.deposit)
532
+ throw new AmountExceedsDepositError({ reason: 'voucher amount exceeds on-chain deposit' })
533
+ if (voucher.cumulativeAmount < channel.highestVoucherAmount)
534
+ throw new VerificationFailedError({
535
+ reason: 'voucher cumulativeAmount must be strictly greater than highest accepted voucher',
536
+ })
537
+ const valid = await Voucher.verifyVoucher(
538
+ methodDetails.escrowContract,
539
+ methodDetails.chainId,
540
+ voucher,
541
+ channel.authorizedSigner,
542
+ )
543
+ if (!valid) throw new InvalidSignatureError({ reason: 'invalid voucher signature' })
544
+
545
+ if (voucher.cumulativeAmount === channel.highestVoucherAmount)
546
+ return createSessionReceipt({
547
+ challengeId: challenge.id,
548
+ channelId: voucher.channelId,
549
+ acceptedCumulative: channel.highestVoucherAmount,
550
+ spent: channel.spent,
551
+ units: channel.units,
552
+ })
553
+ if (voucher.cumulativeAmount <= channelState.settled)
554
+ throw new VerificationFailedError({
555
+ reason: 'voucher cumulativeAmount is below on-chain settled amount',
556
+ })
557
+ const delta = voucher.cumulativeAmount - channel.highestVoucherAmount
558
+ if (delta < minVoucherDelta)
559
+ throw new DeltaTooSmallError({
560
+ reason: `voucher delta ${delta} below minimum ${minVoucherDelta}`,
561
+ })
562
+ const updated = await store.updateChannel(voucher.channelId, (current) =>
563
+ acceptVoucherStateUpdate({ channelState, current, voucher }),
564
+ )
565
+ if (!updated) throw new ChannelNotFoundError({ reason: 'channel not found' })
566
+ return createSessionReceipt({
567
+ challengeId: challenge.id,
568
+ channelId: voucher.channelId,
569
+ acceptedCumulative: updated.highestVoucherAmount,
570
+ spent: updated.spent,
571
+ units: updated.units,
572
+ })
573
+ }
574
+
575
+ /**
576
+ * Internal store interface for channel state persistence.
577
+ *
578
+ * ## Atomicity contract
579
+ *
580
+ * The `updateChannel` method uses an atomic read-modify-write callback.
581
+ * The callback receives the current state (or `null` if none exists), and
582
+ * returns the next state (or `null` to delete). Implementations must
583
+ * guarantee that no concurrent mutation occurs between reading `current`
584
+ * and writing the return value.
585
+ *
586
+ * Callbacks should be synchronous and deterministic. When a `ChannelStore`
587
+ * is backed by `Store.update()`, adapters may retry them internally.
588
+ *
589
+ * Backends implement this via their native mechanisms:
590
+ * - **In-memory / JS single-thread**: Synchronous callback execution
591
+ * - **Durable Objects**: Single-threaded execution model
592
+ * - **D1 / SQL**: Database transactions
593
+ */
594
+ export type ChannelStore = {
595
+ getChannel(channelId: Hex): Promise<State | null>
596
+
597
+ /**
598
+ * Atomic read-modify-write for channel state.
599
+ * Return `null` from `fn` to delete the channel.
600
+ */
601
+ updateChannel(channelId: Hex, fn: (current: State | null) => State | null): Promise<State | null>
602
+
603
+ /**
604
+ * Wait for the next update to a channel.
605
+ *
606
+ * Returns a `Promise` that resolves once `updateChannel` is called for
607
+ * `channelId`. Implementations should resolve immediately if the channel
608
+ * was updated between the call to `waitForUpdate` and the `Promise`
609
+ * being awaited.
610
+ *
611
+ * When not implemented, callers fall back to polling.
612
+ */
613
+ waitForUpdate?(channelId: Hex): Promise<void>
614
+
615
+ /**
616
+ * Atomic read-modify-write that returns the callback's `result` directly.
617
+ *
618
+ * Used by {@link deductFromChannel} to atomically compute the deduction
619
+ * outcome. When backed by `Store.update()`, this delegates to the store's
620
+ * native atomic primitive.
621
+ */
622
+ updateChannelResult?<result>(
623
+ channelId: Hex,
624
+ fn: (current: State | null) => Store.Change<State, result>,
625
+ ): Promise<result>
626
+ }
627
+
628
+ /** Normalizes and validates 32-byte channel IDs before store lookup or persistence. */
629
+ export function normalizeChannelId(channelId: string): Hex {
630
+ if (!/^0x[0-9a-fA-F]{64}$/.test(channelId)) throw new Error('Invalid session channel ID.')
631
+ return channelId.toLowerCase() as Hex
632
+ }
633
+
634
+ type StateStore = Store.Store<Record<string, State>> &
635
+ Partial<Store.AtomicActions<Record<string, State>>>
636
+
637
+ /** Atomic store change carrying normalized channel state. */
638
+ type ChannelStateChange<result> = Store.Change<State, result>
639
+
640
+ /** Store change carrying the result of an attempted spend deduction. */
641
+ type DeductionChange = Store.Change<State, DeductResult | null>
642
+
643
+ /** Mutable runtime state for one generic-store adapter instance. */
644
+ type StoreAdapterRuntime = {
645
+ /** Per-channel in-process locks used when the backend has no atomic update primitive. */
646
+ locks: Map<string, Promise<void>>
647
+ /** Waiters notified after the next mutation for a normalized channel ID. */
648
+ waiters: Map<string, Set<() => void>>
649
+ }
650
+
651
+ function normalizeState(channelId: Hex, state: State): State {
652
+ return state.channelId === channelId ? state : { ...state, channelId }
653
+ }
654
+
655
+ function normalizeMaybeState(channelId: Hex, state: State | null): State | null {
656
+ return state ? normalizeState(channelId, state) : null
657
+ }
658
+
659
+ /** Normalizes any stored channel value inside a store change. */
660
+ function normalizeChange<result>(
661
+ channelId: Hex,
662
+ change: ChannelStateChange<result>,
663
+ ): ChannelStateChange<result> {
664
+ if (change.op !== 'set') return change
665
+ return {
666
+ ...change,
667
+ value: normalizeState(channelId, change.value),
668
+ }
669
+ }
670
+
671
+ /**
672
+ * Wraps a generic {@link Store} into the internal {@link Store}
673
+ * interface used by server handlers and the SSE metering loop.
674
+ *
675
+ * Provides `waitForUpdate` notifications so the SSE `chargeOrWait` loop
676
+ * can wake up without polling.
677
+ *
678
+ * ## Atomicity
679
+ *
680
+ * Mutations use `get` → `fn` → `set` guarded by a per-key in-process
681
+ * mutex. This serializes concurrent `updateChannel` calls within a
682
+ * single JS runtime but does **not** protect against races across
683
+ * multiple processes or instances.
684
+ *
685
+ * Backends that need true atomicity (e.g., Durable Objects, D1)
686
+ * should implement {@link Store} directly.
687
+ */
688
+ const storeCache = new WeakMap<Store.Store, ChannelStore>()
689
+
690
+ /** Wraps a generic mppx store in the shared session channel-store interface. */
691
+ export function fromStore(store: Store.Store | Store.AtomicStore): ChannelStore {
692
+ const cached = storeCache.get(store)
693
+ if (cached) return cached
694
+
695
+ const stateStore = store as StateStore
696
+ const atomicUpdate = stateStore.update
697
+
698
+ const runtime: StoreAdapterRuntime = {
699
+ locks: new Map(),
700
+ waiters: new Map(),
701
+ }
702
+
703
+ function notify(channelId: string) {
704
+ const set = runtime.waiters.get(channelId)
705
+ if (!set) return
706
+ for (const resolve of set) resolve()
707
+ runtime.waiters.delete(channelId)
708
+ }
709
+
710
+ async function update(
711
+ channelId: Hex,
712
+ fn: (current: State | null) => State | null,
713
+ ): Promise<State | null> {
714
+ return updateResult(channelId, (current) => {
715
+ const next = fn(current)
716
+ if (next) return { op: 'set', value: next, result: next }
717
+ return { op: 'delete', result: null }
718
+ })
719
+ }
720
+
721
+ async function updateResult<result>(
722
+ channelId: Hex,
723
+ fn: (current: State | null) => Store.Change<State, result>,
724
+ ): Promise<result> {
725
+ const normalizedChannelId = normalizeChannelId(channelId)
726
+ let change: Store.Change<State, result> | undefined
727
+
728
+ if (atomicUpdate) {
729
+ const result = await atomicUpdate(normalizedChannelId, (current) => {
730
+ const normalizedCurrent = normalizeMaybeState(normalizedChannelId, current)
731
+ change = normalizeChange(normalizedChannelId, fn(normalizedCurrent))
732
+ return change
733
+ })
734
+ if (change?.op !== 'noop') notify(normalizedChannelId)
735
+ return result
736
+ }
737
+
738
+ while (runtime.locks.has(normalizedChannelId)) await runtime.locks.get(normalizedChannelId)
739
+
740
+ let release!: () => void
741
+ runtime.locks.set(
742
+ normalizedChannelId,
743
+ new Promise<void>((r) => {
744
+ release = r
745
+ }),
746
+ )
747
+
748
+ try {
749
+ const current = normalizeMaybeState(
750
+ normalizedChannelId,
751
+ await stateStore.get(normalizedChannelId),
752
+ )
753
+ change = normalizeChange(normalizedChannelId, fn(current))
754
+ if (change.op === 'set') {
755
+ await stateStore.put(normalizedChannelId, change.value)
756
+ }
757
+ if (change.op === 'delete') await stateStore.delete(normalizedChannelId)
758
+ if (change.op !== 'noop') notify(normalizedChannelId)
759
+ return change.result
760
+ } finally {
761
+ runtime.locks.delete(normalizedChannelId)
762
+ release()
763
+ }
764
+ }
765
+
766
+ const cs: ChannelStore = {
767
+ async getChannel(channelId) {
768
+ const normalizedChannelId = normalizeChannelId(channelId)
769
+ return normalizeMaybeState(normalizedChannelId, await stateStore.get(normalizedChannelId))
770
+ },
771
+ async updateChannel(channelId, fn) {
772
+ return update(channelId, fn)
773
+ },
774
+ waitForUpdate(channelId) {
775
+ return new Promise<void>((resolve) => {
776
+ const normalizedChannelId = normalizeChannelId(channelId)
777
+ let set = runtime.waiters.get(normalizedChannelId)
778
+ if (!set) {
779
+ set = new Set()
780
+ runtime.waiters.set(normalizedChannelId, set)
781
+ }
782
+ set.add(resolve)
783
+ })
784
+ },
785
+ }
786
+
787
+ cs.updateChannelResult = updateResult
788
+
789
+ storeCache.set(store, cs)
790
+ return cs
791
+ }
792
+
793
+ /**
794
+ * Atomically deducts `amount` from a channel's available voucher balance.
795
+ *
796
+ * Returns `{ ok: true, channel }` with updated spend/unit counters when the
797
+ * deduction succeeds. Returns `{ ok: false, channel }` without mutating state
798
+ * when the channel exists but cannot currently be charged.
799
+ */
800
+ export async function deductFromChannel(
801
+ store: ChannelStore,
802
+ channelId: State['channelId'],
803
+ amount: bigint,
804
+ ): Promise<DeductResult> {
805
+ if (store.updateChannelResult) {
806
+ const result = await store.updateChannelResult<DeductResult | null>(
807
+ channelId,
808
+ (current): DeductionChange => planDeduction(current, amount),
809
+ )
810
+ if (!result) throw new Error('channel not found')
811
+ return result
812
+ }
813
+
814
+ let result: DeductResult | null = null
815
+ const channel = await store.updateChannel(channelId, (current) => {
816
+ const change = planDeduction(current, amount)
817
+ result = change.result
818
+ if (change.op === 'set') return change.value
819
+ return current
820
+ })
821
+ if (!channel) throw new Error('channel not found')
822
+ return result ?? { ok: false, channel }
823
+ }
824
+
825
+ function planDeduction(current: State | null, amount: bigint): DeductionChange {
826
+ if (!current) return { op: 'noop', result: null }
827
+ if (current.finalized) return { op: 'noop', result: { ok: false, channel: current } }
828
+ if (current.closeRequestedAt !== 0n)
829
+ return { op: 'noop', result: { ok: false, channel: current } }
830
+ if (current.highestVoucherAmount - current.spent < amount)
831
+ return { op: 'noop', result: { ok: false, channel: current } }
832
+
833
+ const next = { ...current, spent: current.spent + amount, units: current.units + 1 }
834
+ return { op: 'set', value: next, result: { ok: true, channel: next } }
835
+ }