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.
- package/CHANGELOG.md +17 -0
- package/dist/Challenge.d.ts.map +1 -1
- package/dist/Challenge.js +9 -7
- package/dist/Challenge.js.map +1 -1
- package/dist/Constants.d.ts +46 -0
- package/dist/Constants.d.ts.map +1 -0
- package/dist/Constants.js +46 -0
- package/dist/Constants.js.map +1 -0
- package/dist/Credential.d.ts.map +1 -1
- package/dist/Credential.js +5 -4
- package/dist/Credential.js.map +1 -1
- package/dist/Method.d.ts +32 -4
- package/dist/Method.d.ts.map +1 -1
- package/dist/Method.js +5 -2
- package/dist/Method.js.map +1 -1
- package/dist/Receipt.d.ts.map +1 -1
- package/dist/Receipt.js +3 -2
- package/dist/Receipt.js.map +1 -1
- package/dist/cli/cli.d.ts.map +1 -1
- package/dist/cli/cli.js +19 -11
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/plugins/tempo.d.ts.map +1 -1
- package/dist/cli/plugins/tempo.js +17 -6
- package/dist/cli/plugins/tempo.js.map +1 -1
- package/dist/cli/utils.d.ts +5 -0
- package/dist/cli/utils.d.ts.map +1 -1
- package/dist/cli/utils.js +10 -0
- package/dist/cli/utils.js.map +1 -1
- package/dist/client/Methods.d.ts +5 -2
- package/dist/client/Methods.d.ts.map +1 -1
- package/dist/client/Methods.js +5 -2
- package/dist/client/Methods.js.map +1 -1
- package/dist/client/Transport.d.ts.map +1 -1
- package/dist/client/Transport.js +4 -5
- package/dist/client/Transport.js.map +1 -1
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +2 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal/Fetch.d.ts.map +1 -1
- package/dist/client/internal/Fetch.js +14 -6
- package/dist/client/internal/Fetch.js.map +1 -1
- package/dist/evm/server/Methods.d.ts +1 -1
- package/dist/evm/server/Methods.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/AcceptPayment.d.ts +3 -0
- package/dist/internal/AcceptPayment.d.ts.map +1 -1
- package/dist/internal/AcceptPayment.js +15 -11
- package/dist/internal/AcceptPayment.js.map +1 -1
- package/dist/mcp-sdk/client/McpClient.d.ts +12 -5
- package/dist/mcp-sdk/client/McpClient.d.ts.map +1 -1
- package/dist/mcp-sdk/client/McpClient.js +55 -42
- package/dist/mcp-sdk/client/McpClient.js.map +1 -1
- package/dist/server/Mppx.d.ts +11 -3
- package/dist/server/Mppx.d.ts.map +1 -1
- package/dist/server/Mppx.js +76 -27
- package/dist/server/Mppx.js.map +1 -1
- package/dist/server/Response.d.ts.map +1 -1
- package/dist/server/Response.js +2 -1
- package/dist/server/Response.js.map +1 -1
- package/dist/server/Transport.d.ts.map +1 -1
- package/dist/server/Transport.js +4 -3
- package/dist/server/Transport.js.map +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/stripe/client/Charge.d.ts +1 -1
- package/dist/stripe/client/Charge.d.ts.map +1 -1
- package/dist/stripe/client/Charge.js +3 -1
- package/dist/stripe/client/Charge.js.map +1 -1
- package/dist/stripe/server/Charge.d.ts +1 -1
- package/dist/stripe/server/Charge.d.ts.map +1 -1
- package/dist/stripe/server/Charge.js +9 -2
- package/dist/stripe/server/Charge.js.map +1 -1
- package/dist/stripe/server/Methods.d.ts +1 -1
- package/dist/stripe/server/Methods.d.ts.map +1 -1
- package/dist/stripe/server/internal/html.gen.d.ts +1 -1
- package/dist/stripe/server/internal/html.gen.d.ts.map +1 -1
- package/dist/stripe/server/internal/html.gen.js +1 -1
- package/dist/stripe/server/internal/html.gen.js.map +1 -1
- package/dist/tempo/Methods.d.ts +18 -0
- package/dist/tempo/Methods.d.ts.map +1 -1
- package/dist/tempo/Methods.js +16 -1
- package/dist/tempo/Methods.js.map +1 -1
- package/dist/tempo/client/Charge.d.ts +6 -0
- package/dist/tempo/client/Charge.d.ts.map +1 -1
- package/dist/tempo/client/Charge.js +9 -2
- package/dist/tempo/client/Charge.js.map +1 -1
- package/dist/tempo/client/Methods.d.ts +36 -7
- package/dist/tempo/client/Methods.d.ts.map +1 -1
- package/dist/tempo/client/Methods.js +12 -5
- package/dist/tempo/client/Methods.js.map +1 -1
- package/dist/tempo/client/index.d.ts +7 -4
- package/dist/tempo/client/index.d.ts.map +1 -1
- package/dist/tempo/client/index.js +5 -3
- package/dist/tempo/client/index.js.map +1 -1
- package/dist/tempo/index.d.ts +1 -0
- package/dist/tempo/index.d.ts.map +1 -1
- package/dist/tempo/index.js +1 -0
- package/dist/tempo/index.js.map +1 -1
- package/dist/tempo/internal/fee-payer.d.ts +21 -1
- package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
- package/dist/tempo/internal/fee-payer.js +109 -4
- package/dist/tempo/internal/fee-payer.js.map +1 -1
- package/dist/tempo/{client → legacy/client}/ChannelOps.d.ts +19 -6
- package/dist/tempo/legacy/client/ChannelOps.d.ts.map +1 -0
- package/dist/tempo/{client → legacy/client}/ChannelOps.js +9 -3
- package/dist/tempo/legacy/client/ChannelOps.js.map +1 -0
- package/dist/tempo/{client → legacy/client}/Session.d.ts +23 -4
- package/dist/tempo/legacy/client/Session.d.ts.map +1 -0
- package/dist/tempo/{client → legacy/client}/Session.js +14 -7
- package/dist/tempo/legacy/client/Session.js.map +1 -0
- package/dist/tempo/{client → legacy/client}/SessionManager.d.ts +20 -5
- package/dist/tempo/legacy/client/SessionManager.d.ts.map +1 -0
- package/dist/tempo/{client → legacy/client}/SessionManager.js +20 -16
- package/dist/tempo/legacy/client/SessionManager.js.map +1 -0
- package/dist/tempo/legacy/client/index.d.ts +7 -0
- package/dist/tempo/legacy/client/index.d.ts.map +1 -0
- package/dist/tempo/legacy/client/index.js +5 -0
- package/dist/tempo/legacy/client/index.js.map +1 -0
- package/dist/tempo/legacy/index.d.ts +7 -0
- package/dist/tempo/legacy/index.d.ts.map +1 -0
- package/dist/tempo/legacy/index.js +7 -0
- package/dist/tempo/legacy/index.js.map +1 -0
- package/dist/tempo/{server → legacy/server}/Session.d.ts +28 -11
- package/dist/tempo/legacy/server/Session.d.ts.map +1 -0
- package/dist/tempo/{server → legacy/server}/Session.js +12 -10
- package/dist/tempo/legacy/server/Session.js.map +1 -0
- package/dist/tempo/legacy/server/index.d.ts +5 -0
- package/dist/tempo/legacy/server/index.d.ts.map +1 -0
- package/dist/tempo/legacy/server/index.js +5 -0
- package/dist/tempo/legacy/server/index.js.map +1 -0
- package/dist/tempo/{session → legacy/session}/Chain.d.ts +30 -23
- package/dist/tempo/legacy/session/Chain.d.ts.map +1 -0
- package/dist/tempo/{session → legacy/session}/Chain.js +12 -11
- package/dist/tempo/legacy/session/Chain.js.map +1 -0
- package/dist/tempo/{session → legacy/session}/Channel.d.ts +1 -0
- package/dist/tempo/legacy/session/Channel.d.ts.map +1 -0
- package/dist/tempo/legacy/session/Channel.js.map +1 -0
- package/dist/tempo/legacy/session/ChannelStore.d.ts +22 -0
- package/dist/tempo/legacy/session/ChannelStore.d.ts.map +1 -0
- package/dist/tempo/legacy/session/ChannelStore.js +6 -0
- package/dist/tempo/legacy/session/ChannelStore.js.map +1 -0
- package/dist/tempo/legacy/session/Types.d.ts +73 -0
- package/dist/tempo/legacy/session/Types.d.ts.map +1 -0
- package/dist/tempo/legacy/session/Types.js.map +1 -0
- package/dist/tempo/{session → legacy/session}/Voucher.d.ts +4 -4
- package/dist/tempo/legacy/session/Voucher.d.ts.map +1 -0
- package/dist/tempo/{session → legacy/session}/Voucher.js +1 -1
- package/dist/tempo/legacy/session/Voucher.js.map +1 -0
- package/dist/tempo/{session → legacy/session}/escrow.abi.d.ts +1 -0
- package/dist/tempo/{session → legacy/session}/escrow.abi.d.ts.map +1 -1
- package/dist/tempo/{session → legacy/session}/escrow.abi.js +1 -0
- package/dist/tempo/legacy/session/escrow.abi.js.map +1 -0
- package/dist/tempo/legacy/session/index.d.ts +9 -0
- package/dist/tempo/legacy/session/index.d.ts.map +1 -0
- package/dist/tempo/legacy/session/index.js +9 -0
- package/dist/tempo/legacy/session/index.js.map +1 -0
- package/dist/tempo/server/Charge.d.ts +1 -1
- package/dist/tempo/server/Charge.d.ts.map +1 -1
- package/dist/tempo/server/Charge.js +13 -16
- package/dist/tempo/server/Charge.js.map +1 -1
- package/dist/tempo/server/Methods.d.ts +63 -6
- package/dist/tempo/server/Methods.d.ts.map +1 -1
- package/dist/tempo/server/Methods.js +36 -8
- package/dist/tempo/server/Methods.js.map +1 -1
- package/dist/tempo/server/Subscription.d.ts +1 -1
- package/dist/tempo/server/Subscription.d.ts.map +1 -1
- package/dist/tempo/server/index.d.ts +6 -5
- package/dist/tempo/server/index.d.ts.map +1 -1
- package/dist/tempo/server/index.js +5 -5
- package/dist/tempo/server/index.js.map +1 -1
- package/dist/tempo/server/internal/html.gen.d.ts +1 -1
- package/dist/tempo/server/internal/html.gen.d.ts.map +1 -1
- package/dist/tempo/server/internal/html.gen.js +1 -1
- package/dist/tempo/server/internal/html.gen.js.map +1 -1
- package/dist/tempo/server/internal/request-body.d.ts +7 -2
- package/dist/tempo/server/internal/request-body.d.ts.map +1 -1
- package/dist/tempo/server/internal/request-body.js +20 -3
- package/dist/tempo/server/internal/request-body.js.map +1 -1
- package/dist/tempo/server/internal/transport.d.ts +8 -4
- package/dist/tempo/server/internal/transport.d.ts.map +1 -1
- package/dist/tempo/server/internal/transport.js +8 -7
- package/dist/tempo/server/internal/transport.js.map +1 -1
- package/dist/tempo/session/Snapshot.d.ts +32 -0
- package/dist/tempo/session/Snapshot.d.ts.map +1 -0
- package/dist/tempo/session/Snapshot.js +37 -0
- package/dist/tempo/session/Snapshot.js.map +1 -0
- package/dist/tempo/session/client/ChannelOps.d.ts +82 -0
- package/dist/tempo/session/client/ChannelOps.d.ts.map +1 -0
- package/dist/tempo/session/client/ChannelOps.js +204 -0
- package/dist/tempo/session/client/ChannelOps.js.map +1 -0
- package/dist/tempo/session/client/CredentialState.d.ts +262 -0
- package/dist/tempo/session/client/CredentialState.d.ts.map +1 -0
- package/dist/tempo/session/client/CredentialState.js +417 -0
- package/dist/tempo/session/client/CredentialState.js.map +1 -0
- package/dist/tempo/session/client/ReceiptCoordinator.d.ts +26 -0
- package/dist/tempo/session/client/ReceiptCoordinator.d.ts.map +1 -0
- package/dist/tempo/session/client/ReceiptCoordinator.js +61 -0
- package/dist/tempo/session/client/ReceiptCoordinator.js.map +1 -0
- package/dist/tempo/session/client/Runtime.d.ts +464 -0
- package/dist/tempo/session/client/Runtime.d.ts.map +1 -0
- package/dist/tempo/session/client/Runtime.js +499 -0
- package/dist/tempo/session/client/Runtime.js.map +1 -0
- package/dist/tempo/session/client/Session.d.ts +132 -0
- package/dist/tempo/session/client/Session.d.ts.map +1 -0
- package/dist/tempo/session/client/Session.js +55 -0
- package/dist/tempo/session/client/Session.js.map +1 -0
- package/dist/tempo/session/client/SessionManager.d.ts +120 -0
- package/dist/tempo/session/client/SessionManager.d.ts.map +1 -0
- package/dist/tempo/session/client/SessionManager.js +627 -0
- package/dist/tempo/session/client/SessionManager.js.map +1 -0
- package/dist/tempo/session/client/Transports.d.ts +449 -0
- package/dist/tempo/session/client/Transports.d.ts.map +1 -0
- package/dist/tempo/session/client/Transports.js +721 -0
- package/dist/tempo/session/client/Transports.js.map +1 -0
- package/dist/tempo/session/client/index.d.ts +12 -0
- package/dist/tempo/session/client/index.d.ts.map +1 -0
- package/dist/tempo/session/client/index.js +5 -0
- package/dist/tempo/session/client/index.js.map +1 -0
- package/dist/tempo/session/index.d.ts +7 -8
- package/dist/tempo/session/index.d.ts.map +1 -1
- package/dist/tempo/session/index.js +7 -8
- package/dist/tempo/session/index.js.map +1 -1
- package/dist/tempo/session/precompile/Chain.d.ts +319 -0
- package/dist/tempo/session/precompile/Chain.d.ts.map +1 -0
- package/dist/tempo/session/precompile/Chain.js +492 -0
- package/dist/tempo/session/precompile/Chain.js.map +1 -0
- package/dist/tempo/session/precompile/Channel.d.ts +46 -0
- package/dist/tempo/session/precompile/Channel.d.ts.map +1 -0
- package/dist/tempo/session/precompile/Channel.js +56 -0
- package/dist/tempo/session/precompile/Channel.js.map +1 -0
- package/dist/tempo/session/precompile/Protocol.d.ts +308 -0
- package/dist/tempo/session/precompile/Protocol.d.ts.map +1 -0
- package/dist/tempo/session/precompile/Protocol.js +264 -0
- package/dist/tempo/session/precompile/Protocol.js.map +1 -0
- package/dist/tempo/session/precompile/Voucher.d.ts +40 -0
- package/dist/tempo/session/precompile/Voucher.d.ts.map +1 -0
- package/dist/tempo/session/precompile/Voucher.js +126 -0
- package/dist/tempo/session/precompile/Voucher.js.map +1 -0
- package/dist/tempo/session/precompile/escrow.abi.d.ts +522 -0
- package/dist/tempo/session/precompile/escrow.abi.d.ts.map +1 -0
- package/dist/tempo/session/precompile/escrow.abi.js +224 -0
- package/dist/tempo/session/precompile/escrow.abi.js.map +1 -0
- package/dist/tempo/session/precompile/index.d.ts +24 -0
- package/dist/tempo/session/precompile/index.d.ts.map +1 -0
- package/dist/tempo/session/precompile/index.js +22 -0
- package/dist/tempo/session/precompile/index.js.map +1 -0
- package/dist/tempo/session/server/ChannelOps.d.ts +56 -0
- package/dist/tempo/session/server/ChannelOps.d.ts.map +1 -0
- package/dist/tempo/session/server/ChannelOps.js +91 -0
- package/dist/tempo/session/server/ChannelOps.js.map +1 -0
- package/dist/tempo/session/server/ChannelStore.d.ts +347 -0
- package/dist/tempo/session/server/ChannelStore.d.ts.map +1 -0
- package/dist/tempo/session/server/ChannelStore.js +404 -0
- package/dist/tempo/session/server/ChannelStore.js.map +1 -0
- package/dist/tempo/session/server/CredentialVerification.d.ts +85 -0
- package/dist/tempo/session/server/CredentialVerification.d.ts.map +1 -0
- package/dist/tempo/session/server/CredentialVerification.js +494 -0
- package/dist/tempo/session/server/CredentialVerification.js.map +1 -0
- package/dist/tempo/session/server/MeteredStream.d.ts +40 -0
- package/dist/tempo/session/server/MeteredStream.d.ts.map +1 -0
- package/dist/tempo/session/server/MeteredStream.js +42 -0
- package/dist/tempo/session/server/MeteredStream.js.map +1 -0
- package/dist/tempo/session/server/RequestState.d.ts +208 -0
- package/dist/tempo/session/server/RequestState.d.ts.map +1 -0
- package/dist/tempo/session/server/RequestState.js +252 -0
- package/dist/tempo/session/server/RequestState.js.map +1 -0
- package/dist/tempo/session/server/Session.d.ts +169 -0
- package/dist/tempo/session/server/Session.d.ts.map +1 -0
- package/dist/tempo/session/server/Session.js +351 -0
- package/dist/tempo/session/server/Session.js.map +1 -0
- package/dist/tempo/session/server/Settlement.d.ts +185 -0
- package/dist/tempo/session/server/Settlement.d.ts.map +1 -0
- package/dist/tempo/session/server/Settlement.js +250 -0
- package/dist/tempo/session/server/Settlement.js.map +1 -0
- package/dist/tempo/session/{Sse.d.ts → server/Sse.d.ts} +9 -56
- package/dist/tempo/session/server/Sse.d.ts.map +1 -0
- package/dist/tempo/session/server/Sse.js +184 -0
- package/dist/tempo/session/server/Sse.js.map +1 -0
- package/dist/tempo/session/server/Transports.d.ts +89 -0
- package/dist/tempo/session/server/Transports.d.ts.map +1 -0
- package/dist/tempo/session/server/Transports.js +149 -0
- package/dist/tempo/session/server/Transports.js.map +1 -0
- package/dist/tempo/session/server/Ws.d.ts +48 -0
- package/dist/tempo/session/server/Ws.d.ts.map +1 -0
- package/dist/tempo/session/server/Ws.js +244 -0
- package/dist/tempo/session/server/Ws.js.map +1 -0
- package/dist/tempo/session/server/index.d.ts +4 -0
- package/dist/tempo/session/server/index.d.ts.map +1 -0
- package/dist/tempo/session/server/index.js +2 -0
- package/dist/tempo/session/server/index.js.map +1 -0
- package/package.json +6 -1
- package/src/Challenge.ts +9 -7
- package/src/Constants.ts +58 -0
- package/src/Credential.ts +5 -4
- package/src/Method.ts +46 -5
- package/src/Receipt.ts +3 -2
- package/src/cli/cli.test.ts +23 -28
- package/src/cli/cli.ts +23 -10
- package/src/cli/mcp.test.ts +21 -7
- package/src/cli/plugins/tempo.ts +21 -8
- package/src/cli/utils.test.ts +25 -1
- package/src/cli/utils.ts +10 -0
- package/src/client/Methods.ts +5 -2
- package/src/client/Mppx.test-d.ts +10 -0
- package/src/client/Mppx.test.ts +75 -0
- package/src/client/Transport.ts +4 -5
- package/src/client/index.ts +11 -1
- package/src/client/internal/Fetch.test.ts +29 -4
- package/src/client/internal/Fetch.ts +17 -5
- package/src/env.d.ts +1 -1
- package/src/index.ts +1 -0
- package/src/internal/AcceptPayment.test.ts +61 -0
- package/src/internal/AcceptPayment.ts +21 -14
- package/src/mcp-sdk/client/McpClient.integration.test.ts +8 -7
- package/src/mcp-sdk/client/McpClient.test-d.ts +7 -0
- package/src/mcp-sdk/client/McpClient.ts +99 -67
- package/src/mcp-sdk/client/McpClient.unit.test.ts +131 -0
- package/src/middlewares/elysia.test.ts +8 -4
- package/src/middlewares/express.test.ts +8 -4
- package/src/middlewares/hono.test.ts +4 -4
- package/src/middlewares/nextjs.test.ts +8 -4
- package/src/proxy/Proxy.test.ts +8 -8
- package/src/server/Mppx.test-d.ts +54 -0
- package/src/server/Mppx.test.ts +200 -7
- package/src/server/Mppx.ts +487 -406
- package/src/server/Response.ts +2 -1
- package/src/server/Transport.ts +4 -3
- package/src/server/index.ts +1 -0
- package/src/stripe/client/Charge.test.ts +20 -5
- package/src/stripe/client/Charge.ts +6 -2
- package/src/stripe/server/Charge.test.ts +114 -1
- package/src/stripe/server/Charge.ts +13 -2
- package/src/stripe/server/internal/html.gen.ts +1 -1
- package/src/tempo/AccessKeyAuthorization.test.ts +4 -94
- package/src/tempo/Methods.test.ts +45 -17
- package/src/tempo/Methods.ts +22 -0
- package/src/tempo/PublicExports.test-d.ts +105 -0
- package/src/tempo/client/Charge.test.ts +85 -0
- package/src/tempo/client/Charge.ts +19 -2
- package/src/tempo/client/Methods.ts +18 -6
- package/src/tempo/client/index.ts +15 -4
- package/src/tempo/index.ts +1 -0
- package/src/tempo/internal/fee-payer.test.ts +241 -17
- package/src/tempo/internal/fee-payer.ts +150 -4
- package/src/tempo/internal/fee-token.test.ts +14 -9
- package/src/tempo/legacy/AccessKeyAuthorization.test.ts +162 -0
- package/src/tempo/legacy/README.md +9 -0
- package/src/tempo/{client → legacy/client}/ChannelOps.test.ts +6 -7
- package/src/tempo/{client → legacy/client}/ChannelOps.ts +22 -9
- package/src/tempo/{client → legacy/client}/Session.test.ts +51 -9
- package/src/tempo/{client → legacy/client}/Session.ts +25 -11
- package/src/tempo/{client → legacy/client}/SessionManager.test.ts +81 -9
- package/src/tempo/{client → legacy/client}/SessionManager.ts +41 -20
- package/src/tempo/legacy/client/index.ts +6 -0
- package/src/tempo/legacy/index.ts +6 -0
- package/src/tempo/{server → legacy/server}/Session.test.ts +45 -45
- package/src/tempo/{server → legacy/server}/Session.ts +32 -23
- package/src/tempo/legacy/server/index.ts +4 -0
- package/src/tempo/{session → legacy/session}/Chain.test.ts +3 -4
- package/src/tempo/{session → legacy/session}/Chain.ts +94 -63
- package/src/tempo/{session → legacy/session}/Channel.ts +1 -0
- package/src/tempo/legacy/session/ChannelStore.test.ts +58 -0
- package/src/tempo/legacy/session/ChannelStore.ts +39 -0
- package/src/tempo/legacy/session/Types.ts +91 -0
- package/src/tempo/{session → legacy/session}/Voucher.ts +12 -8
- package/src/tempo/{session → legacy/session}/escrow.abi.ts +1 -0
- package/src/tempo/legacy/session/index.ts +8 -0
- package/src/tempo/server/AtomicStore.test-d.ts +16 -11
- package/src/tempo/server/Charge.test.ts +92 -14
- package/src/tempo/server/Charge.ts +18 -16
- package/src/tempo/server/Methods.ts +54 -8
- package/src/tempo/server/Sse.test.ts +2 -2
- package/src/tempo/server/index.ts +6 -5
- package/src/tempo/server/internal/html.gen.ts +1 -1
- package/src/tempo/server/internal/request-body.test.ts +37 -4
- package/src/tempo/server/internal/request-body.ts +25 -6
- package/src/tempo/server/internal/transport.test.ts +4 -4
- package/src/tempo/server/internal/transport.ts +19 -10
- package/src/tempo/session/Snapshot.test.ts +41 -0
- package/src/tempo/session/Snapshot.ts +74 -0
- package/src/tempo/session/client/ChannelOps.test.ts +163 -0
- package/src/tempo/session/client/ChannelOps.ts +344 -0
- package/src/tempo/session/client/CredentialState.test.ts +645 -0
- package/src/tempo/session/client/CredentialState.ts +814 -0
- package/src/tempo/session/client/ReceiptCoordinator.ts +95 -0
- package/src/tempo/session/client/Runtime.test.ts +1092 -0
- package/src/tempo/session/client/Runtime.ts +986 -0
- package/src/tempo/session/client/Session.test.ts +734 -0
- package/src/tempo/session/client/Session.ts +97 -0
- package/src/tempo/session/client/SessionManager.test.ts +1308 -0
- package/src/tempo/session/client/SessionManager.ts +845 -0
- package/src/tempo/session/client/Transports.test.ts +837 -0
- package/src/tempo/session/client/Transports.ts +1292 -0
- package/src/tempo/session/client/index.ts +37 -0
- package/src/tempo/session/index.ts +7 -8
- package/src/tempo/session/precompile/Chain.integration.test.ts +321 -0
- package/src/tempo/session/precompile/Chain.test.ts +1258 -0
- package/src/tempo/session/precompile/Chain.ts +979 -0
- package/src/tempo/session/precompile/Channel.test.ts +138 -0
- package/src/tempo/session/precompile/Channel.ts +103 -0
- package/src/tempo/session/precompile/Protocol.test.ts +358 -0
- package/src/tempo/session/precompile/Protocol.ts +520 -0
- package/src/tempo/session/precompile/Voucher.test.ts +316 -0
- package/src/tempo/session/precompile/Voucher.ts +160 -0
- package/src/tempo/session/precompile/escrow.abi.ts +226 -0
- package/src/tempo/session/precompile/index.ts +33 -0
- package/src/tempo/session/server/ChannelOps.test.ts +129 -0
- package/src/tempo/session/server/ChannelOps.ts +157 -0
- package/src/tempo/session/{ChannelStore.test.ts → server/ChannelStore.test.ts} +536 -29
- package/src/tempo/session/server/ChannelStore.ts +835 -0
- package/src/tempo/session/server/CredentialVerification.test.ts +146 -0
- package/src/tempo/session/server/CredentialVerification.ts +710 -0
- package/src/tempo/session/server/MeteredStream.ts +88 -0
- package/src/tempo/session/server/RequestState.test.ts +531 -0
- package/src/tempo/session/server/RequestState.ts +499 -0
- package/src/tempo/session/server/Session.integration.test.ts +444 -0
- package/src/tempo/session/server/Session.test.ts +3253 -0
- package/src/tempo/session/server/Session.ts +543 -0
- package/src/tempo/session/server/Settlement.test.ts +242 -0
- package/src/tempo/session/server/Settlement.ts +470 -0
- package/src/tempo/session/{Sse.test.ts → server/Sse.test.ts} +37 -3
- package/src/tempo/session/server/Sse.ts +256 -0
- package/src/tempo/session/server/Transports.test.ts +346 -0
- package/src/tempo/session/server/Transports.ts +255 -0
- package/src/tempo/session/{Ws.test.ts → server/Ws.test.ts} +4 -4
- package/src/tempo/session/server/Ws.ts +384 -0
- package/src/tempo/session/server/index.ts +8 -0
- package/dist/tempo/client/ChannelOps.d.ts.map +0 -1
- package/dist/tempo/client/ChannelOps.js.map +0 -1
- package/dist/tempo/client/Session.d.ts.map +0 -1
- package/dist/tempo/client/Session.js.map +0 -1
- package/dist/tempo/client/SessionManager.d.ts.map +0 -1
- package/dist/tempo/client/SessionManager.js.map +0 -1
- package/dist/tempo/server/Session.d.ts.map +0 -1
- package/dist/tempo/server/Session.js.map +0 -1
- package/dist/tempo/session/Chain.d.ts.map +0 -1
- package/dist/tempo/session/Chain.js.map +0 -1
- package/dist/tempo/session/Channel.d.ts.map +0 -1
- package/dist/tempo/session/Channel.js.map +0 -1
- package/dist/tempo/session/ChannelStore.d.ts +0 -117
- package/dist/tempo/session/ChannelStore.d.ts.map +0 -1
- package/dist/tempo/session/ChannelStore.js +0 -172
- package/dist/tempo/session/ChannelStore.js.map +0 -1
- package/dist/tempo/session/Receipt.d.ts +0 -22
- package/dist/tempo/session/Receipt.d.ts.map +0 -1
- package/dist/tempo/session/Receipt.js +0 -34
- package/dist/tempo/session/Receipt.js.map +0 -1
- package/dist/tempo/session/Sse.d.ts.map +0 -1
- package/dist/tempo/session/Sse.js +0 -363
- package/dist/tempo/session/Sse.js.map +0 -1
- package/dist/tempo/session/Types.d.ts +0 -78
- package/dist/tempo/session/Types.d.ts.map +0 -1
- package/dist/tempo/session/Types.js.map +0 -1
- package/dist/tempo/session/Voucher.d.ts.map +0 -1
- package/dist/tempo/session/Voucher.js.map +0 -1
- package/dist/tempo/session/Ws.d.ts +0 -87
- package/dist/tempo/session/Ws.d.ts.map +0 -1
- package/dist/tempo/session/Ws.js +0 -443
- package/dist/tempo/session/Ws.js.map +0 -1
- package/dist/tempo/session/escrow.abi.js.map +0 -1
- package/src/tempo/session/ChannelStore.ts +0 -308
- package/src/tempo/session/Receipt.test.ts +0 -89
- package/src/tempo/session/Receipt.ts +0 -46
- package/src/tempo/session/Sse.ts +0 -462
- package/src/tempo/session/Types.ts +0 -86
- package/src/tempo/session/Ws.ts +0 -576
- /package/dist/tempo/{session → legacy/session}/Channel.js +0 -0
- /package/dist/tempo/{session → legacy/session}/Types.js +0 -0
- /package/src/tempo/{session → legacy/session}/Channel.test.ts +0 -0
- /package/src/tempo/{session → legacy/session}/Voucher.test.ts +0 -0
- /package/src/tempo/session/{Sse.fuzz.test.ts → server/Sse.fuzz.test.ts} +0 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import type { Hex } from 'viem'
|
|
2
|
+
|
|
3
|
+
import * as Constants from '../../../Constants.js'
|
|
4
|
+
import * as Credential from '../../../Credential.js'
|
|
5
|
+
import {
|
|
6
|
+
createSessionReceipt,
|
|
7
|
+
extractData,
|
|
8
|
+
formatMessageEvent,
|
|
9
|
+
formatNeedVoucherEvent,
|
|
10
|
+
formatReceiptEvent,
|
|
11
|
+
parseEvent,
|
|
12
|
+
readSessionChallengeAmount,
|
|
13
|
+
requireSessionCredentialContext,
|
|
14
|
+
type SseEvent,
|
|
15
|
+
} from '../precompile/Protocol.js'
|
|
16
|
+
import * as ChannelStore from './ChannelStore.js'
|
|
17
|
+
import { meterIterable, type SessionController } from './MeteredStream.js'
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* SSE (Server-Sent Events) utilities for metered streaming payments.
|
|
21
|
+
*
|
|
22
|
+
* Provides event formatting/parsing, balance polling, the core
|
|
23
|
+
* `serve()` loop that meters an async iterable into a ReadableStream
|
|
24
|
+
* of SSE events, and helpers (`toResponse`, `fromRequest`) for
|
|
25
|
+
* building HTTP responses from the stream.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
extractData,
|
|
30
|
+
formatMessageEvent,
|
|
31
|
+
formatNeedVoucherEvent,
|
|
32
|
+
formatReceiptEvent,
|
|
33
|
+
parseEvent,
|
|
34
|
+
readSessionChallengeAmount,
|
|
35
|
+
requireSessionCredentialContext,
|
|
36
|
+
type SseEvent,
|
|
37
|
+
} from '../precompile/Protocol.js'
|
|
38
|
+
|
|
39
|
+
/** Controller passed to manual-charge SSE generators. */
|
|
40
|
+
export type { SessionController } from './MeteredStream.js'
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Wrap an async iterable with payment metering, producing an SSE stream.
|
|
44
|
+
*
|
|
45
|
+
* `generate` may be either:
|
|
46
|
+
* - An `AsyncIterable<string>` — each yielded value is automatically charged
|
|
47
|
+
* (one `tickCost` per value).
|
|
48
|
+
* - A callback `(stream: SessionController) => AsyncIterable<string>` — the
|
|
49
|
+
* generator controls when charges happen by calling `stream.charge()`.
|
|
50
|
+
*
|
|
51
|
+
* For each emitted value the stream:
|
|
52
|
+
* 1. Reserves `tickCost` from the channel's available voucher headroom
|
|
53
|
+
* (auto or manual).
|
|
54
|
+
* 2. If balance is sufficient, emits `event: message` with the value.
|
|
55
|
+
* 3. If balance is exhausted, emits `event: payment-need-voucher`
|
|
56
|
+
* and polls store until the client tops up the channel.
|
|
57
|
+
* 4. Commits the reserved charge immediately before the chunk is emitted.
|
|
58
|
+
* 5. On generator completion, emits a final `event: payment-receipt`.
|
|
59
|
+
*
|
|
60
|
+
* Returns a `ReadableStream<Uint8Array>` suitable for use as an HTTP response body.
|
|
61
|
+
*/
|
|
62
|
+
export function serve(options: serve.Options): ReadableStream<Uint8Array> {
|
|
63
|
+
const {
|
|
64
|
+
store,
|
|
65
|
+
channelId,
|
|
66
|
+
challengeId,
|
|
67
|
+
tickCost,
|
|
68
|
+
generate,
|
|
69
|
+
pollIntervalMs = 100,
|
|
70
|
+
signal,
|
|
71
|
+
} = options
|
|
72
|
+
|
|
73
|
+
const encoder = new TextEncoder()
|
|
74
|
+
|
|
75
|
+
return new ReadableStream<Uint8Array>({
|
|
76
|
+
async start(controller) {
|
|
77
|
+
const aborted = () => signal?.aborted ?? false
|
|
78
|
+
const emit = (event: string) => controller.enqueue(encoder.encode(event))
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
for await (const value of meterIterable({
|
|
82
|
+
store,
|
|
83
|
+
channelId,
|
|
84
|
+
tickCost,
|
|
85
|
+
generate,
|
|
86
|
+
pollIntervalMs,
|
|
87
|
+
prepaidUnits: options.prepaidUnits,
|
|
88
|
+
signal,
|
|
89
|
+
emitNeedVoucher: emit,
|
|
90
|
+
formatNeedVoucher: formatNeedVoucherEvent,
|
|
91
|
+
})) {
|
|
92
|
+
if (aborted()) break
|
|
93
|
+
controller.enqueue(encoder.encode(formatMessageEvent(value)))
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!aborted()) {
|
|
97
|
+
const channel = await store.getChannel(channelId)
|
|
98
|
+
if (channel) {
|
|
99
|
+
const receipt = createSessionReceipt({
|
|
100
|
+
challengeId,
|
|
101
|
+
channelId,
|
|
102
|
+
acceptedCumulative: channel.highestVoucherAmount,
|
|
103
|
+
spent: channel.spent,
|
|
104
|
+
units: channel.units,
|
|
105
|
+
})
|
|
106
|
+
controller.enqueue(encoder.encode(formatReceiptEvent(receipt)))
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
} catch (e) {
|
|
110
|
+
if (!aborted()) controller.error(e)
|
|
111
|
+
} finally {
|
|
112
|
+
controller.close()
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Type helpers for {@link serve}. */
|
|
119
|
+
export declare namespace serve {
|
|
120
|
+
type Options = {
|
|
121
|
+
store: ChannelStore.ChannelStore
|
|
122
|
+
channelId: Hex
|
|
123
|
+
challengeId: string
|
|
124
|
+
tickCost: bigint
|
|
125
|
+
generate: AsyncIterable<string> | ((stream: SessionController) => AsyncIterable<string>)
|
|
126
|
+
pollIntervalMs?: number | undefined
|
|
127
|
+
prepaidUnits?: number | undefined
|
|
128
|
+
signal?: AbortSignal | undefined
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Wrap a `ReadableStream<Uint8Array>` (from {@link serve}) in an HTTP
|
|
134
|
+
* `Response` with the correct SSE headers.
|
|
135
|
+
*/
|
|
136
|
+
export function toResponse(body: ReadableStream<Uint8Array>): Response {
|
|
137
|
+
return new Response(body, {
|
|
138
|
+
headers: {
|
|
139
|
+
'Cache-Control': 'no-cache, no-transform',
|
|
140
|
+
Connection: 'keep-alive',
|
|
141
|
+
'Content-Type': 'text/event-stream; charset=utf-8',
|
|
142
|
+
},
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Extract `channelId`, `challengeId`, and `tickCost` from a `Request`'s
|
|
148
|
+
* `Authorization: Payment …` header.
|
|
149
|
+
*
|
|
150
|
+
* This is a convenience for callers that receive a raw `Request` and need
|
|
151
|
+
* the parameters required by {@link serve}.
|
|
152
|
+
*/
|
|
153
|
+
export function fromRequest(request: Request): fromRequest.Context {
|
|
154
|
+
const header = request.headers.get(Constants.Headers.authorization)
|
|
155
|
+
if (!header) throw new Error('Missing Authorization header.')
|
|
156
|
+
|
|
157
|
+
const payment = Credential.extractPaymentScheme(header)
|
|
158
|
+
if (!payment) throw new Error('Missing Payment credential in Authorization header.')
|
|
159
|
+
|
|
160
|
+
const credential = Credential.deserialize(payment)
|
|
161
|
+
const payload = requireSessionCredentialContext(credential.payload)
|
|
162
|
+
return {
|
|
163
|
+
challengeId: credential.challenge.id,
|
|
164
|
+
channelId: payload.channelId,
|
|
165
|
+
tickCost: readSessionChallengeAmount(credential.challenge),
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Type helpers for {@link fromRequest}. */
|
|
170
|
+
export declare namespace fromRequest {
|
|
171
|
+
type Context = {
|
|
172
|
+
challengeId: string
|
|
173
|
+
channelId: Hex
|
|
174
|
+
tickCost: bigint
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Check whether a `Response` carries an SSE event stream.
|
|
180
|
+
*
|
|
181
|
+
* Returns `true` when the `Content-Type` header starts with
|
|
182
|
+
* `text/event-stream` (case-insensitive, ignoring charset params).
|
|
183
|
+
*/
|
|
184
|
+
export function isEventStream(response: Response): boolean {
|
|
185
|
+
const ct = response.headers.get('content-type')
|
|
186
|
+
return ct?.toLowerCase().startsWith('text/event-stream') ?? false
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Parse an SSE `Response` body into an async iterable of `data:` payloads.
|
|
191
|
+
*
|
|
192
|
+
* Yields the raw `data:` field content for each SSE event in the stream.
|
|
193
|
+
* Events whose data matches the `skip` predicate are silently dropped
|
|
194
|
+
* (e.g. `[DONE]` sentinels used by OpenAI-compatible APIs).
|
|
195
|
+
*
|
|
196
|
+
* Each yielded value typically becomes one charge tick when fed to
|
|
197
|
+
* {@link serve} via the SSE transport's auto-charge mode.
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```ts
|
|
201
|
+
* const upstream = await fetch('https://api.example.com/stream')
|
|
202
|
+
* for await (const data of Sse.iterateData(upstream)) {
|
|
203
|
+
* console.log(data)
|
|
204
|
+
* }
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
export async function* iterateData(
|
|
208
|
+
response: Response,
|
|
209
|
+
options?: iterateData.Options,
|
|
210
|
+
): AsyncGenerator<string> {
|
|
211
|
+
const skip = options?.skip
|
|
212
|
+
const body = response.body
|
|
213
|
+
if (!body) return
|
|
214
|
+
|
|
215
|
+
const reader = body.getReader()
|
|
216
|
+
const decoder = new TextDecoder()
|
|
217
|
+
let buffer = ''
|
|
218
|
+
|
|
219
|
+
try {
|
|
220
|
+
while (true) {
|
|
221
|
+
const { value, done } = await reader.read()
|
|
222
|
+
if (done) break
|
|
223
|
+
|
|
224
|
+
buffer += decoder.decode(value, { stream: true })
|
|
225
|
+
|
|
226
|
+
// Split on double-newline SSE event boundaries.
|
|
227
|
+
const events = buffer.split('\n\n')
|
|
228
|
+
// Last element may be incomplete — keep in buffer.
|
|
229
|
+
buffer = events.pop() ?? ''
|
|
230
|
+
|
|
231
|
+
for (const event of events) {
|
|
232
|
+
if (!event.trim()) continue
|
|
233
|
+
const data = extractData(event)
|
|
234
|
+
if (data === null) continue
|
|
235
|
+
if (skip?.(data)) continue
|
|
236
|
+
yield data
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Flush remaining buffer.
|
|
241
|
+
if (buffer.trim()) {
|
|
242
|
+
const data = extractData(buffer)
|
|
243
|
+
if (data !== null && !skip?.(data)) yield data
|
|
244
|
+
}
|
|
245
|
+
} finally {
|
|
246
|
+
reader.releaseLock()
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/** Type helpers for {@link iterateData}. */
|
|
251
|
+
export declare namespace iterateData {
|
|
252
|
+
type Options = {
|
|
253
|
+
/** Predicate to skip specific data payloads (e.g. `d => d === '[DONE]'`). */
|
|
254
|
+
skip?: ((data: string) => boolean) | undefined
|
|
255
|
+
}
|
|
256
|
+
}
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import type { Address, Hex } from 'viem'
|
|
2
|
+
import { describe, expect, test } from 'vp/test'
|
|
3
|
+
|
|
4
|
+
import { ChannelClosedError } from '../../../Errors.js'
|
|
5
|
+
import type { NeedVoucherEvent } from '../precompile/Protocol.js'
|
|
6
|
+
import * as ChannelStore from './ChannelStore.js'
|
|
7
|
+
import {
|
|
8
|
+
commitReservedCharges,
|
|
9
|
+
reserveChargeOrWait,
|
|
10
|
+
send,
|
|
11
|
+
subscribe,
|
|
12
|
+
toText,
|
|
13
|
+
type SocketEventListener,
|
|
14
|
+
type SocketEventMap,
|
|
15
|
+
} from './Transports.js'
|
|
16
|
+
|
|
17
|
+
describe('MeteredStream', () => {
|
|
18
|
+
const channelId = `0x${'01'.repeat(32)}` as Hex
|
|
19
|
+
|
|
20
|
+
const descriptor = {
|
|
21
|
+
authorizedSigner: '0x0000000000000000000000000000000000000001' as Address,
|
|
22
|
+
expiringNonceHash: `0x${'11'.repeat(32)}` as Hex,
|
|
23
|
+
operator: '0x0000000000000000000000000000000000000000' as Address,
|
|
24
|
+
payee: '0x0000000000000000000000000000000000000002' as Address,
|
|
25
|
+
payer: '0x0000000000000000000000000000000000000001' as Address,
|
|
26
|
+
salt: `0x${'22'.repeat(32)}` as Hex,
|
|
27
|
+
token: '0x20c0000000000000000000000000000000000001' as Address,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function channel(overrides: Partial<ChannelStore.State> = {}): ChannelStore.State {
|
|
31
|
+
const base: ChannelStore.State = {
|
|
32
|
+
authorizedSigner: descriptor.authorizedSigner,
|
|
33
|
+
backend: 'precompile',
|
|
34
|
+
chainId: 4217,
|
|
35
|
+
escrowContract: '0x4D50500000000000000000000000000000000000' as Address,
|
|
36
|
+
channelId,
|
|
37
|
+
closeRequestedAt: 0n,
|
|
38
|
+
createdAt: '2026-01-01T00:00:00.000Z',
|
|
39
|
+
deposit: 100n,
|
|
40
|
+
descriptor,
|
|
41
|
+
expiringNonceHash: descriptor.expiringNonceHash,
|
|
42
|
+
finalized: false,
|
|
43
|
+
highestVoucher: null,
|
|
44
|
+
highestVoucherAmount: 50n,
|
|
45
|
+
operator: descriptor.operator,
|
|
46
|
+
payee: descriptor.payee,
|
|
47
|
+
payer: descriptor.payer,
|
|
48
|
+
salt: descriptor.salt,
|
|
49
|
+
settledOnChain: 0n,
|
|
50
|
+
spent: 20n,
|
|
51
|
+
token: descriptor.token,
|
|
52
|
+
units: 2,
|
|
53
|
+
}
|
|
54
|
+
return { ...base, ...overrides }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function memoryStore(
|
|
58
|
+
initial: ChannelStore.State,
|
|
59
|
+
options: { waitForUpdate?: boolean } = {},
|
|
60
|
+
): ChannelStore.ChannelStore {
|
|
61
|
+
let state: ChannelStore.State | null = initial
|
|
62
|
+
const waiters = new Set<() => void>()
|
|
63
|
+
const store: ChannelStore.ChannelStore = {
|
|
64
|
+
async getChannel() {
|
|
65
|
+
return state
|
|
66
|
+
},
|
|
67
|
+
async updateChannel(_channelId, fn) {
|
|
68
|
+
state = fn(state)
|
|
69
|
+
for (const waiter of waiters) waiter()
|
|
70
|
+
waiters.clear()
|
|
71
|
+
return state
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
if (options.waitForUpdate) {
|
|
75
|
+
store.waitForUpdate = () => {
|
|
76
|
+
return new Promise<void>((resolve) => {
|
|
77
|
+
waiters.add(resolve)
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return store
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function formatNeedVoucher(event: NeedVoucherEvent) {
|
|
85
|
+
return JSON.stringify(event)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
describe('MeteredStream', () => {
|
|
89
|
+
test('reserveChargeOrWait returns immediately when voucher headroom is available', async () => {
|
|
90
|
+
const emitted: string[] = []
|
|
91
|
+
await reserveChargeOrWait({
|
|
92
|
+
amount: 10n,
|
|
93
|
+
channelId,
|
|
94
|
+
emit(message) {
|
|
95
|
+
emitted.push(message)
|
|
96
|
+
},
|
|
97
|
+
formatNeedVoucher,
|
|
98
|
+
pollIntervalMs: 1,
|
|
99
|
+
reservedAmount: 0n,
|
|
100
|
+
store: memoryStore(channel()),
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
expect(emitted).toEqual([])
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
test('reserveChargeOrWait emits need-voucher and waits for accepted headroom', async () => {
|
|
107
|
+
const emitted: string[] = []
|
|
108
|
+
const store = memoryStore(channel({ highestVoucherAmount: 25n, spent: 20n }))
|
|
109
|
+
const reserved = reserveChargeOrWait({
|
|
110
|
+
amount: 10n,
|
|
111
|
+
channelId,
|
|
112
|
+
emit(message) {
|
|
113
|
+
emitted.push(message)
|
|
114
|
+
},
|
|
115
|
+
formatNeedVoucher,
|
|
116
|
+
pollIntervalMs: 1,
|
|
117
|
+
reservedAmount: 0n,
|
|
118
|
+
store,
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
await Promise.resolve()
|
|
122
|
+
expect(emitted.map((item) => JSON.parse(item))).toEqual([
|
|
123
|
+
{
|
|
124
|
+
channelId,
|
|
125
|
+
requiredCumulative: '30',
|
|
126
|
+
acceptedCumulative: '25',
|
|
127
|
+
deposit: '100',
|
|
128
|
+
},
|
|
129
|
+
])
|
|
130
|
+
|
|
131
|
+
await store.updateChannel(channelId, (current) =>
|
|
132
|
+
current ? { ...current, highestVoucherAmount: 30n } : current,
|
|
133
|
+
)
|
|
134
|
+
await reserved
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
test('reserveChargeOrWait observes updates that happen before wait registration', async () => {
|
|
138
|
+
const emitted: string[] = []
|
|
139
|
+
const store = memoryStore(channel({ highestVoucherAmount: 25n, spent: 20n }), {
|
|
140
|
+
waitForUpdate: true,
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
await reserveChargeOrWait({
|
|
144
|
+
amount: 10n,
|
|
145
|
+
channelId,
|
|
146
|
+
async emit(message) {
|
|
147
|
+
emitted.push(message)
|
|
148
|
+
await store.updateChannel(channelId, (current) =>
|
|
149
|
+
current ? { ...current, highestVoucherAmount: 30n } : current,
|
|
150
|
+
)
|
|
151
|
+
},
|
|
152
|
+
formatNeedVoucher,
|
|
153
|
+
pollIntervalMs: 1,
|
|
154
|
+
reservedAmount: 0n,
|
|
155
|
+
store,
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
expect(emitted).toHaveLength(1)
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
test('commitReservedCharges increments spend and units', async () => {
|
|
162
|
+
const store = memoryStore(channel({ spent: 20n, units: 2, highestVoucherAmount: 50n }))
|
|
163
|
+
|
|
164
|
+
await commitReservedCharges({ amount: 10n, channelId, store, units: 1 })
|
|
165
|
+
|
|
166
|
+
expect(await store.getChannel(channelId)).toMatchObject({ spent: 30n, units: 3 })
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
test('commitReservedCharges rejects when reserved coverage is no longer available', async () => {
|
|
170
|
+
await expect(
|
|
171
|
+
commitReservedCharges({
|
|
172
|
+
amount: 40n,
|
|
173
|
+
channelId,
|
|
174
|
+
store: memoryStore(channel({ spent: 20n, highestVoucherAmount: 50n })),
|
|
175
|
+
units: 1,
|
|
176
|
+
}),
|
|
177
|
+
).rejects.toThrow('reserved voucher coverage is no longer available')
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
test('commitReservedCharges rejects closed channels', async () => {
|
|
181
|
+
await expect(
|
|
182
|
+
commitReservedCharges({
|
|
183
|
+
amount: 10n,
|
|
184
|
+
channelId,
|
|
185
|
+
store: memoryStore(channel({ finalized: true })),
|
|
186
|
+
units: 1,
|
|
187
|
+
}),
|
|
188
|
+
).rejects.toThrow(ChannelClosedError)
|
|
189
|
+
})
|
|
190
|
+
})
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
describe('SocketTransport', () => {
|
|
194
|
+
class BrowserSocket {
|
|
195
|
+
sent: string[] = []
|
|
196
|
+
listeners = {
|
|
197
|
+
close: new Set<SocketEventListener<'close'>>(),
|
|
198
|
+
error: new Set<SocketEventListener<'error'>>(),
|
|
199
|
+
message: new Set<SocketEventListener<'message'>>(),
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
addEventListener<type extends keyof SocketEventMap>(
|
|
203
|
+
type: type,
|
|
204
|
+
listener: SocketEventListener<type>,
|
|
205
|
+
) {
|
|
206
|
+
this.listeners[type].add(listener as never)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
close() {
|
|
210
|
+
this.emit('close', { type: 'close' })
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
emit<type extends keyof SocketEventMap>(type: type, event: SocketEventMap[type]) {
|
|
214
|
+
for (const listener of this.listeners[type]) {
|
|
215
|
+
if (typeof listener === 'function') listener(event as never)
|
|
216
|
+
else listener.handleEvent(event as never)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
removeEventListener<type extends keyof SocketEventMap>(
|
|
221
|
+
type: type,
|
|
222
|
+
listener: SocketEventListener<type>,
|
|
223
|
+
) {
|
|
224
|
+
this.listeners[type].delete(listener as never)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
send(data: string) {
|
|
228
|
+
this.sent.push(data)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
class NodeSocket {
|
|
233
|
+
sent: string[] = []
|
|
234
|
+
listeners = {
|
|
235
|
+
close: new Set<(event: SocketEventMap['close']) => void>(),
|
|
236
|
+
error: new Set<(event: SocketEventMap['error']) => void>(),
|
|
237
|
+
message: new Set<(event: SocketEventMap['message']) => void>(),
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
close() {
|
|
241
|
+
this.emit('close', { type: 'close' })
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
emit<type extends keyof SocketEventMap>(type: type, event: SocketEventMap[type]) {
|
|
245
|
+
for (const listener of this.listeners[type]) listener(event as never)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
off<type extends keyof SocketEventMap>(
|
|
249
|
+
type: type,
|
|
250
|
+
listener: (event: SocketEventMap[type]) => void,
|
|
251
|
+
) {
|
|
252
|
+
this.listeners[type].delete(listener as never)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
on<type extends keyof SocketEventMap>(
|
|
256
|
+
type: type,
|
|
257
|
+
listener: (event: SocketEventMap[type]) => void,
|
|
258
|
+
) {
|
|
259
|
+
this.listeners[type].add(listener as never)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
send(data: string) {
|
|
263
|
+
this.sent.push(data)
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
describe('SocketTransport', () => {
|
|
268
|
+
test('subscribe handles browser-style socket events', () => {
|
|
269
|
+
const socket = new BrowserSocket()
|
|
270
|
+
const messages: unknown[] = []
|
|
271
|
+
let closed = 0
|
|
272
|
+
let errors = 0
|
|
273
|
+
|
|
274
|
+
const unsubscribe = subscribe(socket, {
|
|
275
|
+
close() {
|
|
276
|
+
closed++
|
|
277
|
+
},
|
|
278
|
+
error() {
|
|
279
|
+
errors++
|
|
280
|
+
},
|
|
281
|
+
message(value) {
|
|
282
|
+
messages.push(value)
|
|
283
|
+
},
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
socket.emit('message', { data: 'hello', type: 'message' })
|
|
287
|
+
socket.emit('error', { type: 'error' })
|
|
288
|
+
socket.emit('close', { type: 'close' })
|
|
289
|
+
unsubscribe()
|
|
290
|
+
socket.emit('message', { data: 'ignored', type: 'message' })
|
|
291
|
+
|
|
292
|
+
expect(messages).toEqual(['hello'])
|
|
293
|
+
expect(errors).toBe(1)
|
|
294
|
+
expect(closed).toBe(1)
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
test('subscribe handles node-style socket events', () => {
|
|
298
|
+
const socket = new NodeSocket()
|
|
299
|
+
const messages: unknown[] = []
|
|
300
|
+
|
|
301
|
+
const unsubscribe = subscribe(socket, {
|
|
302
|
+
close() {},
|
|
303
|
+
error() {},
|
|
304
|
+
message(value) {
|
|
305
|
+
messages.push(value)
|
|
306
|
+
},
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
socket.emit('message', { data: 'hello', type: 'message' })
|
|
310
|
+
unsubscribe()
|
|
311
|
+
socket.emit('message', { data: 'ignored', type: 'message' })
|
|
312
|
+
|
|
313
|
+
expect(messages).toEqual([{ data: 'hello', type: 'message' }])
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
test('subscribe rejects unsupported socket implementations', () => {
|
|
317
|
+
expect(() =>
|
|
318
|
+
subscribe({ close() {}, send() {} }, { close() {}, error() {}, message() {} }),
|
|
319
|
+
).toThrow('unsupported websocket implementation')
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
test('send supports sync and async socket implementations', async () => {
|
|
323
|
+
const syncSocket = new BrowserSocket()
|
|
324
|
+
const asyncSocket = {
|
|
325
|
+
close() {},
|
|
326
|
+
sent: [] as string[],
|
|
327
|
+
async send(data: string) {
|
|
328
|
+
this.sent.push(data)
|
|
329
|
+
},
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
await send(syncSocket, 'sync')
|
|
333
|
+
await send(asyncSocket, 'async')
|
|
334
|
+
|
|
335
|
+
expect(syncSocket.sent).toEqual(['sync'])
|
|
336
|
+
expect(asyncSocket.sent).toEqual(['async'])
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
test('toText normalizes common message payloads', () => {
|
|
340
|
+
expect(toText('hello')).toBe('hello')
|
|
341
|
+
expect(toText(new TextEncoder().encode('bytes'))).toBe('bytes')
|
|
342
|
+
expect(toText(new TextEncoder().encode('buffer').buffer)).toBe('buffer')
|
|
343
|
+
expect(toText({ data: 'object' })).toBeNull()
|
|
344
|
+
})
|
|
345
|
+
})
|
|
346
|
+
})
|