mppx 0.8.15 → 0.8.17
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 +36 -0
- package/dist/Challenge.d.ts.map +1 -1
- package/dist/Challenge.js +40 -35
- package/dist/Challenge.js.map +1 -1
- package/dist/Constants.d.ts +17 -17
- package/dist/Constants.d.ts.map +1 -1
- package/dist/Credential.d.ts.map +1 -1
- package/dist/Errors.d.ts +3 -3
- package/dist/Errors.d.ts.map +1 -1
- package/dist/Errors.js.map +1 -1
- package/dist/Method.d.ts +35 -5
- package/dist/Method.d.ts.map +1 -1
- package/dist/Method.js +7 -22
- package/dist/Method.js.map +1 -1
- package/dist/Store.d.ts +19 -0
- package/dist/Store.d.ts.map +1 -1
- package/dist/Store.js +43 -0
- package/dist/Store.js.map +1 -1
- package/dist/attestation/Client.d.ts +17 -0
- package/dist/attestation/Client.d.ts.map +1 -0
- package/dist/attestation/Client.js +28 -0
- package/dist/attestation/Client.js.map +1 -0
- package/dist/attestation/Constants.d.ts +15 -0
- package/dist/attestation/Constants.d.ts.map +1 -0
- package/dist/attestation/Constants.js +15 -0
- package/dist/attestation/Constants.js.map +1 -0
- package/dist/attestation/Server.d.ts +4 -0
- package/dist/attestation/Server.d.ts.map +1 -0
- package/dist/attestation/Server.js +8 -0
- package/dist/attestation/Server.js.map +1 -0
- package/dist/attestation/Types.d.ts +76 -0
- package/dist/attestation/Types.d.ts.map +1 -0
- package/dist/attestation/Types.js +2 -0
- package/dist/attestation/Types.js.map +1 -0
- package/dist/attestation/index.d.ts +6 -0
- package/dist/attestation/index.d.ts.map +1 -0
- package/dist/attestation/index.js +6 -0
- package/dist/attestation/index.js.map +1 -0
- package/dist/attestation/internal/HttpMessageSignature.d.ts +73 -0
- package/dist/attestation/internal/HttpMessageSignature.d.ts.map +1 -0
- package/dist/attestation/internal/HttpMessageSignature.js +320 -0
- package/dist/attestation/internal/HttpMessageSignature.js.map +1 -0
- package/dist/attestation/internal/SigningContext.d.ts +4 -0
- package/dist/attestation/internal/SigningContext.d.ts.map +1 -0
- package/dist/attestation/internal/SigningContext.js +11 -0
- package/dist/attestation/internal/SigningContext.js.map +1 -0
- package/dist/cli/account.d.ts +14 -14
- package/dist/cli/account.d.ts.map +1 -1
- package/dist/cli/cli.d.ts +6 -6
- package/dist/cli/cli.d.ts.map +1 -1
- package/dist/cli/cli.js +1 -0
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/plugins/tempo.js.map +1 -1
- package/dist/cli/sessions/commands.d.ts +4 -4
- package/dist/cli/sessions/commands.d.ts.map +1 -1
- package/dist/cli/sessions/commands.js.map +1 -1
- package/dist/cli/sessions/store.d.ts.map +1 -1
- package/dist/cli/sessions/store.js.map +1 -1
- package/dist/cli/utils.d.ts +1 -1
- package/dist/cli/utils.d.ts.map +1 -1
- package/dist/cli/utils.js.map +1 -1
- package/dist/cli/validate/discovery.js.map +1 -1
- package/dist/cli/validate/index.d.ts +3 -3
- package/dist/cli/validate/index.d.ts.map +1 -1
- package/dist/client/Mppx.d.ts +3 -0
- package/dist/client/Mppx.d.ts.map +1 -1
- package/dist/client/Mppx.js +13 -5
- package/dist/client/Mppx.js.map +1 -1
- package/dist/client/Transport.d.ts +3 -5
- package/dist/client/Transport.d.ts.map +1 -1
- package/dist/client/Transport.js +1 -17
- package/dist/client/Transport.js.map +1 -1
- package/dist/client/internal/Fetch.d.ts.map +1 -1
- package/dist/client/internal/Fetch.js +2 -6
- package/dist/client/internal/Fetch.js.map +1 -1
- package/dist/client/node.js.map +1 -1
- package/dist/discovery/OpenApi.d.ts +3 -5
- package/dist/discovery/OpenApi.d.ts.map +1 -1
- package/dist/discovery/OpenApi.js +13 -34
- package/dist/discovery/OpenApi.js.map +1 -1
- package/dist/discovery/internal/Metadata.d.ts +20 -0
- package/dist/discovery/internal/Metadata.d.ts.map +1 -0
- package/dist/discovery/internal/Metadata.js +36 -0
- package/dist/discovery/internal/Metadata.js.map +1 -0
- package/dist/evm/Methods.d.ts +11 -11
- package/dist/evm/Methods.d.ts.map +1 -1
- package/dist/evm/Types.d.ts +17 -17
- package/dist/evm/Types.d.ts.map +1 -1
- package/dist/evm/client/Charge.d.ts +11 -11
- package/dist/evm/client/Methods.d.ts +11 -11
- package/dist/evm/server/Charge.d.ts +1 -1
- package/dist/evm/server/Charge.d.ts.map +1 -1
- package/dist/evm/server/Charge.js +2 -0
- package/dist/evm/server/Charge.js.map +1 -1
- package/dist/evm/server/Methods.d.ts +11 -11
- package/dist/internal/HeaderCodec.d.ts +2 -2
- package/dist/internal/HeaderCodec.d.ts.map +1 -1
- package/dist/internal/types.d.ts +6 -0
- package/dist/internal/types.d.ts.map +1 -1
- package/dist/middlewares/elysia.js.map +1 -1
- package/dist/middlewares/express.js.map +1 -1
- package/dist/middlewares/hono.js.map +1 -1
- package/dist/middlewares/nextjs.js.map +1 -1
- package/dist/proxy/Proxy.d.ts +2 -0
- package/dist/proxy/Proxy.d.ts.map +1 -1
- package/dist/proxy/Proxy.js +117 -9
- package/dist/proxy/Proxy.js.map +1 -1
- package/dist/proxy/Service.d.ts +36 -1
- package/dist/proxy/Service.d.ts.map +1 -1
- package/dist/proxy/Service.js +9 -8
- package/dist/proxy/Service.js.map +1 -1
- package/dist/proxy/services/anthropic.d.ts.map +1 -1
- package/dist/proxy/services/anthropic.js +1 -0
- package/dist/proxy/services/anthropic.js.map +1 -1
- package/dist/proxy/services/openai.d.ts.map +1 -1
- package/dist/proxy/services/openai.js +1 -0
- package/dist/proxy/services/openai.js.map +1 -1
- package/dist/proxy/services/stripe.d.ts.map +1 -1
- package/dist/proxy/services/stripe.js +1 -0
- package/dist/proxy/services/stripe.js.map +1 -1
- package/dist/server/Mppx.d.ts +75 -13
- package/dist/server/Mppx.d.ts.map +1 -1
- package/dist/server/Mppx.js +201 -23
- package/dist/server/Mppx.js.map +1 -1
- package/dist/server/internal/html/config.d.ts +9 -9
- package/dist/server/internal/html/config.d.ts.map +1 -1
- package/dist/server/internal/html/constants.d.ts +17 -17
- package/dist/server/internal/html/constants.d.ts.map +1 -1
- package/dist/stripe/Methods.d.ts +10 -10
- package/dist/stripe/Methods.d.ts.map +1 -1
- package/dist/stripe/client/Charge.d.ts +10 -10
- package/dist/stripe/client/Methods.d.ts +10 -10
- package/dist/stripe/internal/constants.d.ts +1 -1
- package/dist/stripe/internal/constants.js +1 -1
- package/dist/stripe/internal/types.d.ts +1 -0
- package/dist/stripe/internal/types.d.ts.map +1 -1
- package/dist/stripe/server/Charge.d.ts +11 -11
- package/dist/stripe/server/Charge.d.ts.map +1 -1
- package/dist/stripe/server/Charge.js +49 -1
- package/dist/stripe/server/Charge.js.map +1 -1
- package/dist/stripe/server/Methods.d.ts +137 -48
- package/dist/stripe/server/Methods.d.ts.map +1 -1
- package/dist/stripe/server/Methods.js +259 -4
- package/dist/stripe/server/Methods.js.map +1 -1
- package/dist/stripe/server/internal/deposit-address.d.ts +13 -0
- package/dist/stripe/server/internal/deposit-address.d.ts.map +1 -0
- package/dist/stripe/server/internal/deposit-address.js +28 -0
- package/dist/stripe/server/internal/deposit-address.js.map +1 -0
- 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/stripe/server/internal/record-payment.d.ts +15 -0
- package/dist/stripe/server/internal/record-payment.d.ts.map +1 -0
- package/dist/stripe/server/internal/record-payment.js +42 -0
- package/dist/stripe/server/internal/record-payment.js.map +1 -0
- package/dist/stripe/server/internal/request.d.ts +25 -0
- package/dist/stripe/server/internal/request.d.ts.map +1 -0
- package/dist/stripe/server/internal/request.js +29 -0
- package/dist/stripe/server/internal/request.js.map +1 -0
- package/dist/tap/Constants.d.ts +28 -0
- package/dist/tap/Constants.d.ts.map +1 -0
- package/dist/tap/Constants.js +32 -0
- package/dist/tap/Constants.js.map +1 -0
- package/dist/tap/Types.d.ts +11 -0
- package/dist/tap/Types.d.ts.map +1 -0
- package/dist/tap/Types.js +2 -0
- package/dist/tap/Types.js.map +1 -0
- package/dist/tap/client/index.d.ts +26 -0
- package/dist/tap/client/index.d.ts.map +1 -0
- package/dist/tap/client/index.js +33 -0
- package/dist/tap/client/index.js.map +1 -0
- package/dist/tap/index.d.ts +5 -0
- package/dist/tap/index.d.ts.map +1 -0
- package/dist/tap/index.js +5 -0
- package/dist/tap/index.js.map +1 -0
- package/dist/tap/server/index.d.ts +20 -0
- package/dist/tap/server/index.d.ts.map +1 -0
- package/dist/tap/server/index.js +36 -0
- package/dist/tap/server/index.js.map +1 -0
- package/dist/tempo/Attribution.d.ts +1 -1
- package/dist/tempo/Methods.d.ts +60 -60
- package/dist/tempo/Methods.d.ts.map +1 -1
- package/dist/tempo/Proof.d.ts +16 -16
- package/dist/tempo/client/Charge.d.ts +19 -19
- package/dist/tempo/client/Charge.d.ts.map +1 -1
- package/dist/tempo/client/Charge.js +1 -7
- package/dist/tempo/client/Charge.js.map +1 -1
- package/dist/tempo/client/Methods.d.ts +38 -38
- package/dist/tempo/client/Methods.js.map +1 -1
- package/dist/tempo/client/Subscription.d.ts +23 -23
- package/dist/tempo/client/Subscription.js.map +1 -1
- package/dist/tempo/internal/address.d.ts +2 -1
- package/dist/tempo/internal/address.d.ts.map +1 -1
- package/dist/tempo/internal/address.js +3 -1
- package/dist/tempo/internal/address.js.map +1 -1
- package/dist/tempo/internal/auto-swap.d.ts.map +1 -1
- package/dist/tempo/internal/auto-swap.js +4 -19
- package/dist/tempo/internal/auto-swap.js.map +1 -1
- package/dist/tempo/internal/defaults.d.ts +6 -6
- package/dist/tempo/internal/defaults.d.ts.map +1 -1
- package/dist/tempo/internal/fee-payer.d.ts +12 -12
- package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
- package/dist/tempo/internal/fee-payer.js.map +1 -1
- package/dist/tempo/internal/proof.d.ts +17 -17
- package/dist/tempo/internal/proof.d.ts.map +1 -1
- package/dist/tempo/legacy/client/Session.d.ts +20 -20
- package/dist/tempo/legacy/client/Session.js.map +1 -1
- package/dist/tempo/legacy/client/SessionManager.js.map +1 -1
- package/dist/tempo/legacy/index.d.ts +1 -3
- package/dist/tempo/legacy/index.d.ts.map +1 -1
- package/dist/tempo/legacy/index.js +1 -3
- package/dist/tempo/legacy/index.js.map +1 -1
- package/dist/tempo/legacy/session/escrow.abi.d.ts +374 -374
- package/dist/tempo/legacy/session/escrow.abi.d.ts.map +1 -1
- package/dist/tempo/server/Charge.d.ts +25 -11
- package/dist/tempo/server/Charge.d.ts.map +1 -1
- package/dist/tempo/server/Charge.js +44 -39
- package/dist/tempo/server/Charge.js.map +1 -1
- package/dist/tempo/server/Methods.d.ts +37 -52
- package/dist/tempo/server/Methods.d.ts.map +1 -1
- package/dist/tempo/server/Methods.js +0 -14
- package/dist/tempo/server/Methods.js.map +1 -1
- package/dist/tempo/server/Relay.d.ts +1 -1
- package/dist/tempo/server/Relay.d.ts.map +1 -1
- package/dist/tempo/server/Relay.js +2 -2
- package/dist/tempo/server/Relay.js.map +1 -1
- package/dist/tempo/server/Subscription.d.ts +25 -25
- package/dist/tempo/server/Subscription.d.ts.map +1 -1
- package/dist/tempo/server/Subscription.js +2 -0
- package/dist/tempo/server/Subscription.js.map +1 -1
- package/dist/tempo/server/index.d.ts +1 -1
- package/dist/tempo/server/index.d.ts.map +1 -1
- package/dist/tempo/server/index.js +1 -1
- 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/transport.d.ts +2 -0
- package/dist/tempo/server/internal/transport.d.ts.map +1 -1
- package/dist/tempo/server/internal/transport.js +9 -2
- package/dist/tempo/server/internal/transport.js.map +1 -1
- package/dist/tempo/session/client/ChannelOps.js.map +1 -1
- package/dist/tempo/session/client/CredentialState.d.ts +1 -1
- package/dist/tempo/session/client/CredentialState.js.map +1 -1
- package/dist/tempo/session/client/ReceiptCoordinator.js.map +1 -1
- package/dist/tempo/session/client/Runtime.js.map +1 -1
- package/dist/tempo/session/client/Session.d.ts +19 -19
- package/dist/tempo/session/client/Session.js.map +1 -1
- package/dist/tempo/session/client/SessionManager.js.map +1 -1
- package/dist/tempo/session/client/Transports.d.ts.map +1 -1
- package/dist/tempo/session/precompile/Chain.d.ts +27 -0
- package/dist/tempo/session/precompile/Chain.d.ts.map +1 -1
- package/dist/tempo/session/precompile/Chain.js +68 -7
- package/dist/tempo/session/precompile/Chain.js.map +1 -1
- package/dist/tempo/session/precompile/Protocol.js.map +1 -1
- package/dist/tempo/session/precompile/Voucher.d.ts +4 -4
- package/dist/tempo/session/precompile/Voucher.d.ts.map +1 -1
- package/dist/tempo/session/precompile/escrow.abi.d.ts +306 -306
- package/dist/tempo/session/precompile/escrow.abi.d.ts.map +1 -1
- package/dist/tempo/session/server/ChannelStore.d.ts +9 -0
- package/dist/tempo/session/server/ChannelStore.d.ts.map +1 -1
- package/dist/tempo/session/server/ChannelStore.js +16 -8
- package/dist/tempo/session/server/ChannelStore.js.map +1 -1
- package/dist/tempo/session/server/CredentialVerification.d.ts +30 -13
- package/dist/tempo/session/server/CredentialVerification.d.ts.map +1 -1
- package/dist/tempo/session/server/CredentialVerification.js +207 -13
- package/dist/tempo/session/server/CredentialVerification.js.map +1 -1
- package/dist/tempo/session/server/MeteredStream.d.ts +3 -0
- package/dist/tempo/session/server/MeteredStream.d.ts.map +1 -1
- package/dist/tempo/session/server/MeteredStream.js +3 -1
- package/dist/tempo/session/server/MeteredStream.js.map +1 -1
- package/dist/tempo/session/server/Session.d.ts +32 -21
- package/dist/tempo/session/server/Session.d.ts.map +1 -1
- package/dist/tempo/session/server/Session.js +116 -53
- package/dist/tempo/session/server/Session.js.map +1 -1
- package/dist/tempo/session/server/Sse.d.ts +3 -1
- package/dist/tempo/session/server/Sse.d.ts.map +1 -1
- package/dist/tempo/session/server/Sse.js +2 -1
- package/dist/tempo/session/server/Sse.js.map +1 -1
- package/dist/tempo/session/server/Transports.d.ts +1 -1
- package/dist/tempo/session/server/Transports.d.ts.map +1 -1
- package/dist/tempo/session/server/Transports.js +1 -0
- package/dist/tempo/session/server/Transports.js.map +1 -1
- package/dist/tempo/session/server/Ws.d.ts +6 -1
- package/dist/tempo/session/server/Ws.d.ts.map +1 -1
- package/dist/tempo/session/server/Ws.js +1 -0
- package/dist/tempo/session/server/Ws.js.map +1 -1
- package/dist/tempo/subscription/KeyAuthorization.d.ts +39 -39
- package/dist/tempo/subscription/KeyAuthorization.d.ts.map +1 -1
- package/dist/viem/Account.d.ts.map +1 -1
- package/dist/viem/Account.js.map +1 -1
- package/dist/web-bot-auth/Constants.d.ts +20 -0
- package/dist/web-bot-auth/Constants.d.ts.map +1 -0
- package/dist/web-bot-auth/Constants.js +24 -0
- package/dist/web-bot-auth/Constants.js.map +1 -0
- package/dist/web-bot-auth/Types.d.ts +10 -0
- package/dist/web-bot-auth/Types.d.ts.map +1 -0
- package/dist/web-bot-auth/Types.js +2 -0
- package/dist/web-bot-auth/Types.js.map +1 -0
- package/dist/web-bot-auth/client/index.d.ts +29 -0
- package/dist/web-bot-auth/client/index.d.ts.map +1 -0
- package/dist/web-bot-auth/client/index.js +64 -0
- package/dist/web-bot-auth/client/index.js.map +1 -0
- package/dist/web-bot-auth/index.d.ts +7 -0
- package/dist/web-bot-auth/index.d.ts.map +1 -0
- package/dist/web-bot-auth/index.js +7 -0
- package/dist/web-bot-auth/index.js.map +1 -0
- package/dist/web-bot-auth/internal/JwkThumbprint.d.ts +5 -0
- package/dist/web-bot-auth/internal/JwkThumbprint.d.ts.map +1 -0
- package/dist/web-bot-auth/internal/JwkThumbprint.js +20 -0
- package/dist/web-bot-auth/internal/JwkThumbprint.js.map +1 -0
- package/dist/web-bot-auth/internal/SignatureAgent.d.ts +3 -0
- package/dist/web-bot-auth/internal/SignatureAgent.d.ts.map +1 -0
- package/dist/web-bot-auth/internal/SignatureAgent.js +18 -0
- package/dist/web-bot-auth/internal/SignatureAgent.js.map +1 -0
- package/dist/web-bot-auth/server/index.d.ts +35 -0
- package/dist/web-bot-auth/server/index.d.ts.map +1 -0
- package/dist/web-bot-auth/server/index.js +88 -0
- package/dist/web-bot-auth/server/index.js.map +1 -0
- package/dist/x402/Assets.d.ts.map +1 -1
- package/dist/x402/Types.d.ts +6 -6
- package/dist/x402/Types.d.ts.map +1 -1
- package/dist/x402/server/EvmCharge.d.ts.map +1 -1
- package/dist/x402/server/EvmCharge.js +32 -20
- package/dist/x402/server/EvmCharge.js.map +1 -1
- package/package.json +19 -3
- package/src/Challenge.fuzz.test.ts +80 -47
- package/src/Challenge.test.ts +65 -0
- package/src/Challenge.ts +39 -35
- package/src/Method.ts +82 -68
- package/src/Store.test-d.ts +16 -0
- package/src/Store.test.ts +50 -0
- package/src/Store.ts +68 -0
- package/src/attestation/Attestation.integration.test.ts +208 -0
- package/src/attestation/Client.test.ts +83 -0
- package/src/attestation/Client.ts +34 -0
- package/src/attestation/Constants.ts +15 -0
- package/src/attestation/Server.test.ts +60 -0
- package/src/attestation/Server.ts +12 -0
- package/src/attestation/Types.test-d.ts +54 -0
- package/src/attestation/Types.ts +77 -0
- package/src/attestation/index.ts +5 -0
- package/src/attestation/internal/HttpMessageSignature.test.ts +101 -0
- package/src/attestation/internal/HttpMessageSignature.ts +429 -0
- package/src/attestation/internal/SigningContext.ts +13 -0
- package/src/bin.js +2 -0
- package/src/cli/cli.ts +1 -0
- package/src/client/Mppx.test-d.ts +17 -0
- package/src/client/Mppx.test.ts +14 -14
- package/src/client/Mppx.ts +25 -4
- package/src/client/Transport.test.ts +12 -45
- package/src/client/Transport.ts +3 -24
- package/src/client/internal/Fetch.ts +2 -6
- package/src/discovery/OpenApi.test.ts +170 -0
- package/src/discovery/OpenApi.ts +16 -48
- package/src/discovery/internal/Metadata.ts +51 -0
- package/src/evm/server/Charge.ts +6 -1
- package/src/internal/AcceptPayment.test.ts +12 -8
- package/src/internal/types.ts +9 -0
- package/src/mcp/client/McpClient.integration.test.ts +19 -32
- package/src/middlewares/elysia.test.ts +2 -12
- package/src/middlewares/express.test.ts +2 -12
- package/src/middlewares/hono.test.ts +6 -9
- package/src/middlewares/nextjs.test.ts +2 -12
- package/src/proxy/Proxy.test.ts +26 -19
- package/src/proxy/Proxy.ts +147 -9
- package/src/proxy/Proxy.upstreamError.test.ts +364 -0
- package/src/proxy/Service.test.ts +73 -3
- package/src/proxy/Service.ts +50 -23
- package/src/proxy/services/anthropic.ts +1 -0
- package/src/proxy/services/hooks.test-d.ts +14 -0
- package/src/proxy/services/hooks.test.ts +44 -0
- package/src/proxy/services/openai.ts +1 -0
- package/src/proxy/services/stripe.ts +1 -0
- package/src/server/Methods.test-d.ts +88 -0
- package/src/server/Methods.test.ts +69 -0
- package/src/server/Mppx.test-d.ts +141 -7
- package/src/server/Mppx.test.ts +1017 -119
- package/src/server/Mppx.ts +350 -54
- package/src/stripe/internal/constants.ts +1 -1
- package/src/stripe/internal/types.ts +1 -0
- package/src/stripe/server/Charge.test-d.ts +16 -1
- package/src/stripe/server/Charge.test.ts +79 -0
- package/src/stripe/server/Charge.ts +54 -1
- package/src/stripe/server/Methods.test-d.ts +157 -0
- package/src/stripe/server/Methods.test.ts +403 -0
- package/src/stripe/server/Methods.ts +423 -6
- package/src/stripe/server/internal/deposit-address.ts +57 -0
- package/src/stripe/server/internal/html/node_modules/.bin/mppx +3 -3
- package/src/stripe/server/internal/html/package.json +1 -1
- package/src/stripe/server/internal/html.gen.ts +1 -1
- package/src/stripe/server/internal/record-payment.ts +66 -0
- package/src/stripe/server/internal/request.ts +49 -0
- package/src/tap/Constants.ts +32 -0
- package/src/tap/Tap.test.ts +125 -0
- package/src/tap/Types.ts +11 -0
- package/src/tap/client/index.ts +54 -0
- package/src/tap/index.ts +4 -0
- package/src/tap/server/index.ts +48 -0
- package/src/tempo/PublicExports.test-d.ts +3 -3
- package/src/tempo/client/Charge.ts +1 -19
- package/src/tempo/internal/address.test.ts +42 -0
- package/src/tempo/internal/address.ts +3 -3
- package/src/tempo/internal/auto-swap.test.ts +4 -4
- package/src/tempo/internal/auto-swap.ts +7 -50
- package/src/tempo/legacy/README.md +5 -5
- package/src/tempo/legacy/index.ts +1 -3
- package/src/tempo/server/AtomicStore.test-d.ts +13 -0
- package/src/tempo/server/Charge.test.ts +19 -84
- package/src/tempo/server/Charge.ts +83 -55
- package/src/tempo/server/Methods.ts +0 -20
- package/src/tempo/server/Relay.test.ts +5 -5
- package/src/tempo/server/Relay.ts +2 -2
- package/src/tempo/server/Subscription.ts +4 -1
- package/src/tempo/server/index.ts +1 -1
- package/src/tempo/server/internal/html/node_modules/.bin/mppx +3 -3
- package/src/tempo/server/internal/html/package.json +1 -1
- package/src/tempo/server/internal/html.gen.ts +1 -1
- package/src/tempo/server/internal/transport.test.ts +22 -3
- package/src/tempo/server/internal/transport.ts +15 -3
- package/src/tempo/session/README.md +112 -0
- package/src/tempo/session/precompile/Chain.ts +131 -11
- package/src/tempo/session/server/ChannelStore.ts +33 -12
- package/src/tempo/session/server/CredentialVerification.test.ts +4 -4
- package/src/tempo/session/server/CredentialVerification.ts +340 -28
- package/src/tempo/session/server/MeteredStream.ts +5 -1
- package/src/tempo/session/server/Session.test.ts +428 -43
- package/src/tempo/session/server/Session.ts +159 -60
- package/src/tempo/session/server/Sse.test.ts +77 -0
- package/src/tempo/session/server/Sse.ts +8 -1
- package/src/tempo/session/server/Transports.ts +2 -1
- package/src/tempo/session/server/Ws.test.ts +171 -0
- package/src/tempo/session/server/Ws.ts +7 -1
- package/src/web-bot-auth/Constants.ts +24 -0
- package/src/web-bot-auth/Types.ts +9 -0
- package/src/web-bot-auth/WebBotAuth.test.ts +182 -0
- package/src/web-bot-auth/client/index.ts +84 -0
- package/src/web-bot-auth/index.ts +6 -0
- package/src/web-bot-auth/internal/JwkThumbprint.ts +21 -0
- package/src/web-bot-auth/internal/SignatureAgent.ts +18 -0
- package/src/web-bot-auth/server/index.ts +113 -0
- package/src/x402/Exact.e2e.test.ts +121 -81
- package/src/x402/Exact.localnet.test.ts +1 -1
- package/src/x402/server/EvmCharge.ts +35 -19
- package/dist/tempo/legacy/server/Session.d.ts +0 -208
- package/dist/tempo/legacy/server/Session.d.ts.map +0 -1
- package/dist/tempo/legacy/server/Session.js +0 -698
- package/dist/tempo/legacy/server/Session.js.map +0 -1
- package/dist/tempo/legacy/server/index.d.ts +0 -5
- package/dist/tempo/legacy/server/index.d.ts.map +0 -1
- package/dist/tempo/legacy/server/index.js +0 -5
- package/dist/tempo/legacy/server/index.js.map +0 -1
- package/dist/tempo/legacy/session/ChannelStore.d.ts +0 -22
- package/dist/tempo/legacy/session/ChannelStore.d.ts.map +0 -1
- package/dist/tempo/legacy/session/ChannelStore.js +0 -6
- package/dist/tempo/legacy/session/ChannelStore.js.map +0 -1
- package/src/tempo/legacy/server/Defaults.test-d.ts +0 -9
- package/src/tempo/legacy/server/Session.test.ts +0 -6370
- package/src/tempo/legacy/server/Session.ts +0 -1024
- package/src/tempo/legacy/server/index.ts +0 -4
- package/src/tempo/legacy/session/ChannelStore.test.ts +0 -58
- package/src/tempo/legacy/session/ChannelStore.ts +0 -39
|
@@ -4,6 +4,8 @@ import { serve } from '@hono/node-server'
|
|
|
4
4
|
import { Hono } from 'hono'
|
|
5
5
|
import { Challenge, Constants, Credential } from 'mppx'
|
|
6
6
|
import { Mppx as Mppx_server, tempo as tempo_server } from 'mppx/server'
|
|
7
|
+
import { Secp256k1 } from 'ox'
|
|
8
|
+
import { TxEnvelopeTempo } from 'ox/tempo'
|
|
7
9
|
import {
|
|
8
10
|
type Address,
|
|
9
11
|
createClient,
|
|
@@ -14,6 +16,7 @@ import {
|
|
|
14
16
|
encodeFunctionData,
|
|
15
17
|
encodeFunctionResult,
|
|
16
18
|
type Hex,
|
|
19
|
+
maxUint256,
|
|
17
20
|
zeroAddress,
|
|
18
21
|
} from 'viem'
|
|
19
22
|
import { privateKeyToAccount } from 'viem/accounts'
|
|
@@ -40,9 +43,8 @@ import * as ChannelStore from './ChannelStore.js'
|
|
|
40
43
|
import { charge, session, type ResolveSessionChannelId } from './Session.js'
|
|
41
44
|
import * as TempoWs from './Ws.js'
|
|
42
45
|
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
)
|
|
46
|
+
const payerPrivateKey = '0xac0974bec39a17e36ba6a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'
|
|
47
|
+
const payer = privateKeyToAccount(payerPrivateKey)
|
|
46
48
|
const wrongPayer = privateKeyToAccount(
|
|
47
49
|
'0x59c6995e998f97a5a0044966f094538a009d74290f5811cfba6a6b4d238ff944',
|
|
48
50
|
)
|
|
@@ -88,10 +90,16 @@ function createServerClient(
|
|
|
88
90
|
_eventChannelId: Hex = `0x${'00'.repeat(32)}` as Hex,
|
|
89
91
|
options: {
|
|
90
92
|
descriptor?: Channel.ChannelDescriptor
|
|
91
|
-
receipt?:
|
|
92
|
-
|
|
93
|
+
receipt?:
|
|
94
|
+
| Record<string, unknown>
|
|
95
|
+
| (() => Record<string, unknown> | Promise<Record<string, unknown>>)
|
|
96
|
+
sentReceipt?:
|
|
97
|
+
| Record<string, unknown>
|
|
98
|
+
| (() => Record<string, unknown> | Promise<Record<string, unknown>>)
|
|
99
|
+
state?: ChainState | (() => ChainState | Promise<ChainState>)
|
|
93
100
|
} = {},
|
|
94
101
|
) {
|
|
102
|
+
let sentTransaction = false
|
|
95
103
|
return createClient({
|
|
96
104
|
...(account ? { account } : {}),
|
|
97
105
|
chain: testChain,
|
|
@@ -103,11 +111,24 @@ function createServerClient(
|
|
|
103
111
|
if (args.method === 'eth_estimateGas') return '0x5208'
|
|
104
112
|
if (args.method === 'eth_maxPriorityFeePerGas') return '0x1'
|
|
105
113
|
if (args.method === 'eth_getBlockByNumber') return { baseFeePerGas: '0x1' }
|
|
106
|
-
if (args.method === 'eth_sendRawTransaction')
|
|
107
|
-
|
|
108
|
-
|
|
114
|
+
if (args.method === 'eth_sendRawTransaction') {
|
|
115
|
+
sentTransaction = true
|
|
116
|
+
return `0x${'aa'.repeat(32)}`
|
|
117
|
+
}
|
|
118
|
+
if (args.method === 'eth_getTransactionReceipt') {
|
|
119
|
+
const receipt = sentTransaction
|
|
120
|
+
? (options.sentReceipt ?? options.receipt)
|
|
121
|
+
: options.receipt
|
|
122
|
+
return typeof receipt === 'function' ? receipt() : (receipt ?? null)
|
|
123
|
+
}
|
|
124
|
+
if (args.method === 'eth_sendTransaction') {
|
|
125
|
+
sentTransaction = true
|
|
126
|
+
return `0x${'bb'.repeat(32)}`
|
|
127
|
+
}
|
|
109
128
|
if (args.method === 'eth_call') {
|
|
110
|
-
const
|
|
129
|
+
const configuredState =
|
|
130
|
+
typeof options.state === 'function' ? await options.state() : options.state
|
|
131
|
+
const state = configuredState ?? { settled: 100n, deposit: 1_000n, closeRequestedAt: 0 }
|
|
111
132
|
const data = (args.params as [{ data?: Hex }])[0].data
|
|
112
133
|
const getChannelSelector = options.descriptor
|
|
113
134
|
? encodeFunctionData({
|
|
@@ -315,6 +336,52 @@ async function createOpenPayload(
|
|
|
315
336
|
}
|
|
316
337
|
}
|
|
317
338
|
|
|
339
|
+
function sponsorTransaction(
|
|
340
|
+
serializedTransaction: Hex,
|
|
341
|
+
options: { gas?: bigint | undefined } = {},
|
|
342
|
+
): Hex {
|
|
343
|
+
const transaction = Transaction.deserialize(
|
|
344
|
+
serializedTransaction as Transaction.TransactionSerializedTempo,
|
|
345
|
+
)
|
|
346
|
+
const envelope = TxEnvelopeTempo.from({
|
|
347
|
+
...transaction,
|
|
348
|
+
feePayerSignature: null,
|
|
349
|
+
gas: options.gas ?? 100_000n,
|
|
350
|
+
maxFeePerGas: 1n,
|
|
351
|
+
maxPriorityFeePerGas: 1n,
|
|
352
|
+
nonceKey: maxUint256,
|
|
353
|
+
validBefore: Math.floor(Date.now() / 1_000) + 600,
|
|
354
|
+
} as never)
|
|
355
|
+
return TxEnvelopeTempo.serialize(envelope, {
|
|
356
|
+
signature: Secp256k1.sign({
|
|
357
|
+
payload: TxEnvelopeTempo.getSignPayload(envelope),
|
|
358
|
+
privateKey: payerPrivateKey,
|
|
359
|
+
}),
|
|
360
|
+
}) as Hex
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
async function createSponsoredOpenPayload(): Promise<
|
|
364
|
+
Extract<SessionCredentialPayload, { action: 'open' }>
|
|
365
|
+
> {
|
|
366
|
+
const payload = await createOpenPayload()
|
|
367
|
+
const transaction = sponsorTransaction(payload.transaction)
|
|
368
|
+
const signed = Transaction.deserialize(transaction as Transaction.TransactionSerializedTempo)
|
|
369
|
+
const expiringNonceHash = Channel.computeExpiringNonceHash(
|
|
370
|
+
Channel.transactionForExpiringNonceHash({ feePayer: true, transaction: signed }),
|
|
371
|
+
{ sender: payer.address },
|
|
372
|
+
)
|
|
373
|
+
const descriptor = { ...payload.descriptor, expiringNonceHash }
|
|
374
|
+
const channelId = Channel.computeId({ ...descriptor, chainId, escrow: tip20ChannelEscrow })
|
|
375
|
+
const signature = await Voucher.signVoucher(
|
|
376
|
+
createSigningClient(),
|
|
377
|
+
payer,
|
|
378
|
+
{ channelId, cumulativeAmount: BigInt(payload.cumulativeAmount) },
|
|
379
|
+
tip20ChannelEscrow,
|
|
380
|
+
chainId,
|
|
381
|
+
)
|
|
382
|
+
return { ...payload, channelId, transaction, signature, descriptor }
|
|
383
|
+
}
|
|
384
|
+
|
|
318
385
|
function transactionReceipt(logs: readonly Record<string, unknown>[]) {
|
|
319
386
|
return {
|
|
320
387
|
blockHash: `0x${'01'.repeat(32)}`,
|
|
@@ -757,6 +824,133 @@ describe('precompile server session unit guardrails', () => {
|
|
|
757
824
|
).rejects.toThrow('Client not configured with chainId 1.')
|
|
758
825
|
})
|
|
759
826
|
|
|
827
|
+
test('fully validates a session credential without broadcasting or changing channel state', async () => {
|
|
828
|
+
const { method, rpcCalls, store } = createServer()
|
|
829
|
+
const openPayload = await createOpenPayload()
|
|
830
|
+
await persistPrecompileChannel(store, openPayload)
|
|
831
|
+
const payload = await ClientOps.createVoucherPayload(
|
|
832
|
+
createSigningClient(),
|
|
833
|
+
payer,
|
|
834
|
+
openPayload.descriptor,
|
|
835
|
+
Types.uint96(200n),
|
|
836
|
+
chainId,
|
|
837
|
+
)
|
|
838
|
+
|
|
839
|
+
const validation = await method.validate!({
|
|
840
|
+
credential: {
|
|
841
|
+
challenge: makeChallenge(openPayload.channelId),
|
|
842
|
+
payload,
|
|
843
|
+
source: sourceFor(),
|
|
844
|
+
},
|
|
845
|
+
request: verifyRequest(openPayload.channelId),
|
|
846
|
+
})
|
|
847
|
+
|
|
848
|
+
await method.validate!({
|
|
849
|
+
credential: {
|
|
850
|
+
challenge: makeChallenge(openPayload.channelId),
|
|
851
|
+
payload,
|
|
852
|
+
source: sourceFor(),
|
|
853
|
+
},
|
|
854
|
+
request: verifyRequest(openPayload.channelId),
|
|
855
|
+
})
|
|
856
|
+
|
|
857
|
+
expect(validation.details).toEqual({ action: 'voucher', channelId: openPayload.channelId })
|
|
858
|
+
expect(await store.getChannel(openPayload.channelId)).toMatchObject({
|
|
859
|
+
highestVoucherAmount: 100n,
|
|
860
|
+
spent: 0n,
|
|
861
|
+
units: 0,
|
|
862
|
+
})
|
|
863
|
+
expect(rpcCalls.map(({ method }) => method)).toEqual(['eth_call'])
|
|
864
|
+
expect(rpcCalls.map(({ method }) => method)).not.toContain('eth_sendRawTransaction')
|
|
865
|
+
expect(rpcCalls.map(({ method }) => method)).not.toContain('eth_sendRawTransactionSync')
|
|
866
|
+
})
|
|
867
|
+
|
|
868
|
+
test('simulates unsponsored open and top-up credentials during validation', async () => {
|
|
869
|
+
const { method, rpcCalls, store } = createServer()
|
|
870
|
+
const openPayload = await createOpenPayload()
|
|
871
|
+
|
|
872
|
+
await method.validate!({
|
|
873
|
+
credential: { challenge: makeChallenge(openPayload.channelId), payload: openPayload },
|
|
874
|
+
request: verifyRequest(openPayload.channelId),
|
|
875
|
+
})
|
|
876
|
+
await persistPrecompileChannel(store, openPayload)
|
|
877
|
+
const topUpPayload = await createTopUpPayload(openPayload.descriptor, 100n)
|
|
878
|
+
|
|
879
|
+
await method.validate!({
|
|
880
|
+
credential: { challenge: makeChallenge(topUpPayload.channelId), payload: topUpPayload },
|
|
881
|
+
request: verifyRequest(topUpPayload.channelId),
|
|
882
|
+
})
|
|
883
|
+
|
|
884
|
+
expect(rpcCalls.map(({ method }) => method)).toEqual(['eth_call', 'eth_call', 'eth_call'])
|
|
885
|
+
expect(await store.getChannel(openPayload.channelId)).toMatchObject({
|
|
886
|
+
deposit: 1_000n,
|
|
887
|
+
highestVoucherAmount: 100n,
|
|
888
|
+
})
|
|
889
|
+
})
|
|
890
|
+
|
|
891
|
+
test('does not simulate sponsored credentials during validation but checks top-up state', async () => {
|
|
892
|
+
const { method, rpcCalls, store } = createServer({ feePayer: payer })
|
|
893
|
+
const openPayload = await createSponsoredOpenPayload()
|
|
894
|
+
|
|
895
|
+
await method.validate!({
|
|
896
|
+
credential: { challenge: makeChallenge(openPayload.channelId), payload: openPayload },
|
|
897
|
+
request: verifyRequestWithFeePayer(openPayload.channelId, payer),
|
|
898
|
+
})
|
|
899
|
+
await persistPrecompileChannel(store, openPayload)
|
|
900
|
+
const topUpPayload = await createTopUpPayload(openPayload.descriptor, 100n)
|
|
901
|
+
topUpPayload.transaction = sponsorTransaction(topUpPayload.transaction)
|
|
902
|
+
|
|
903
|
+
await method.validate!({
|
|
904
|
+
credential: { challenge: makeChallenge(topUpPayload.channelId), payload: topUpPayload },
|
|
905
|
+
request: verifyRequestWithFeePayer(topUpPayload.channelId, payer),
|
|
906
|
+
})
|
|
907
|
+
|
|
908
|
+
expect(rpcCalls.map(({ method }) => method)).toEqual(['eth_call'])
|
|
909
|
+
expect(await store.getChannel(openPayload.channelId)).toMatchObject({
|
|
910
|
+
deposit: 1_000n,
|
|
911
|
+
highestVoucherAmount: 100n,
|
|
912
|
+
})
|
|
913
|
+
})
|
|
914
|
+
|
|
915
|
+
test('rejects sponsored credentials that exceed the fee-payer policy during validation', async () => {
|
|
916
|
+
const { method, rpcCalls } = createServer({
|
|
917
|
+
feePayer: payer,
|
|
918
|
+
feePayerPolicy: { maxGas: 1n },
|
|
919
|
+
})
|
|
920
|
+
const payload = await createSponsoredOpenPayload()
|
|
921
|
+
|
|
922
|
+
payload.transaction = sponsorTransaction(payload.transaction, { gas: 2n })
|
|
923
|
+
|
|
924
|
+
await expect(
|
|
925
|
+
method.validate!({
|
|
926
|
+
credential: { challenge: makeChallenge(payload.channelId), payload },
|
|
927
|
+
request: verifyRequestWithFeePayer(payload.channelId, payer),
|
|
928
|
+
}),
|
|
929
|
+
).rejects.toThrow(/fee-sponsored transaction gas exceeds sponsor policy/)
|
|
930
|
+
expect(rpcCalls).toEqual([])
|
|
931
|
+
})
|
|
932
|
+
|
|
933
|
+
test('validates close credentials without marking the channel pending', async () => {
|
|
934
|
+
const { method, rpcCalls, store } = createServer()
|
|
935
|
+
const openPayload = await createOpenPayload()
|
|
936
|
+
await persistPrecompileChannel(store, openPayload, { payee: payer.address })
|
|
937
|
+
const payload = await ClientOps.createClosePayload(
|
|
938
|
+
createSigningClient(),
|
|
939
|
+
payer,
|
|
940
|
+
openPayload.descriptor,
|
|
941
|
+
Types.uint96(100n),
|
|
942
|
+
chainId,
|
|
943
|
+
)
|
|
944
|
+
|
|
945
|
+
await method.validate!({
|
|
946
|
+
credential: { challenge: makeChallenge(openPayload.channelId), payload },
|
|
947
|
+
request: verifyRequest(openPayload.channelId),
|
|
948
|
+
})
|
|
949
|
+
|
|
950
|
+
expect((await store.getChannel(openPayload.channelId))?.closeRequestedAt).toBe(0n)
|
|
951
|
+
expect(rpcCalls.map(({ method }) => method)).toEqual(['eth_call'])
|
|
952
|
+
})
|
|
953
|
+
|
|
760
954
|
test('rejects open transactions targeting the wrong address', async () => {
|
|
761
955
|
const { method } = createServer()
|
|
762
956
|
const payload = await createOpenPayload({ escrow: wrongTarget })
|
|
@@ -1409,7 +1603,7 @@ describe('precompile server session unit guardrails', () => {
|
|
|
1409
1603
|
expect(stored?.units).toBe(4)
|
|
1410
1604
|
})
|
|
1411
1605
|
|
|
1412
|
-
test('rejects
|
|
1606
|
+
test('rejects top-up validation when on-chain state has pending close', async () => {
|
|
1413
1607
|
const rawStore = Store.memory()
|
|
1414
1608
|
const store = channelStore(rawStore)
|
|
1415
1609
|
const openPayload = await createOpenPayload({ initialAmount: 100n })
|
|
@@ -1431,7 +1625,7 @@ describe('precompile server session unit guardrails', () => {
|
|
|
1431
1625
|
})
|
|
1432
1626
|
|
|
1433
1627
|
await expect(
|
|
1434
|
-
method.
|
|
1628
|
+
method.validate!({
|
|
1435
1629
|
credential: {
|
|
1436
1630
|
challenge: makeChallenge(openPayload.channelId),
|
|
1437
1631
|
payload: topUpPayload,
|
|
@@ -2172,14 +2366,23 @@ describe('precompile server session unit guardrails', () => {
|
|
|
2172
2366
|
|
|
2173
2367
|
describe('SSE parity', () => {
|
|
2174
2368
|
function createManagedSseFetch(
|
|
2175
|
-
options: {
|
|
2369
|
+
options: {
|
|
2370
|
+
amount?: string
|
|
2371
|
+
chunkDelayMs?: number
|
|
2372
|
+
maxDeposit?: bigint
|
|
2373
|
+
onSessionSettlement?: session.Parameters['onSessionSettlement']
|
|
2374
|
+
settlementSchedule?: session.Parameters['settlementSchedule']
|
|
2375
|
+
unitType?: 'request' | 'token'
|
|
2376
|
+
} = {},
|
|
2176
2377
|
) {
|
|
2177
2378
|
const rawStore = Store.memory()
|
|
2379
|
+
let activeChannelId: Hex | undefined
|
|
2178
2380
|
let currentPayload: SessionCredentialPayload | undefined
|
|
2179
2381
|
let voucherPosts = 0
|
|
2180
2382
|
const amount = options.amount ?? '1'
|
|
2181
2383
|
const maxDeposit = options.maxDeposit ?? 3n
|
|
2182
2384
|
let deposit = maxDeposit
|
|
2385
|
+
let settled = 0n
|
|
2183
2386
|
const unitType = options.unitType ?? 'token'
|
|
2184
2387
|
const route = Mppx_server.create({
|
|
2185
2388
|
methods: [
|
|
@@ -2189,6 +2392,8 @@ describe('precompile server session unit guardrails', () => {
|
|
|
2189
2392
|
currency: token,
|
|
2190
2393
|
decimals: 0,
|
|
2191
2394
|
recipient: payer.address,
|
|
2395
|
+
onSessionSettlement: options.onSessionSettlement,
|
|
2396
|
+
settlementSchedule: options.settlementSchedule,
|
|
2192
2397
|
sse: true,
|
|
2193
2398
|
store: rawStore,
|
|
2194
2399
|
unitType,
|
|
@@ -2206,20 +2411,24 @@ describe('precompile server session unit guardrails', () => {
|
|
|
2206
2411
|
receipt: transactionReceipt([
|
|
2207
2412
|
closedLog(payload.channelId, BigInt(payload.cumulativeAmount), 0n),
|
|
2208
2413
|
]),
|
|
2209
|
-
state: { settled
|
|
2414
|
+
state: { settled, deposit, closeRequestedAt: 0 },
|
|
2210
2415
|
})
|
|
2211
2416
|
}
|
|
2212
2417
|
if (payload?.action === 'topUp') {
|
|
2213
2418
|
deposit += BigInt(payload.additionalDeposit)
|
|
2214
2419
|
return createServerClient([], payer, payload.channelId, {
|
|
2215
2420
|
receipt: transactionReceipt([topUpLog(payload, deposit)]),
|
|
2216
|
-
state: { settled
|
|
2421
|
+
state: { settled, deposit, closeRequestedAt: 0 },
|
|
2217
2422
|
})
|
|
2218
2423
|
}
|
|
2219
|
-
return
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2424
|
+
return createServerClient([], payer, undefined, {
|
|
2425
|
+
sentReceipt: async () => {
|
|
2426
|
+
if (!activeChannelId) throw new Error('missing channel context')
|
|
2427
|
+
const channel = await channelStore(rawStore).getChannel(activeChannelId)
|
|
2428
|
+
settled = channel?.highestVoucherAmount ?? settled
|
|
2429
|
+
return transactionReceipt([settledLog(activeChannelId, settled)])
|
|
2430
|
+
},
|
|
2431
|
+
state: () => ({ settled, deposit, closeRequestedAt: 0 }),
|
|
2223
2432
|
})
|
|
2224
2433
|
},
|
|
2225
2434
|
}),
|
|
@@ -2233,6 +2442,7 @@ describe('precompile server session unit guardrails', () => {
|
|
|
2233
2442
|
if (request.headers.has('Authorization')) {
|
|
2234
2443
|
try {
|
|
2235
2444
|
currentPayload = Credential.fromRequest<SessionCredentialPayload>(request).payload
|
|
2445
|
+
activeChannelId = currentPayload.channelId
|
|
2236
2446
|
if (currentPayload.action === 'voucher') voucherPosts++
|
|
2237
2447
|
} catch {}
|
|
2238
2448
|
}
|
|
@@ -2259,9 +2469,12 @@ describe('precompile server session unit guardrails', () => {
|
|
|
2259
2469
|
)
|
|
2260
2470
|
}
|
|
2261
2471
|
|
|
2472
|
+
currentPayload = undefined
|
|
2262
2473
|
return result.withReceipt(async function* (stream) {
|
|
2263
2474
|
await stream.charge()
|
|
2264
2475
|
yield 'chunk-1'
|
|
2476
|
+
if (options.chunkDelayMs)
|
|
2477
|
+
await new Promise((resolve) => setTimeout(resolve, options.chunkDelayMs))
|
|
2265
2478
|
await stream.charge()
|
|
2266
2479
|
yield 'chunk-2'
|
|
2267
2480
|
await stream.charge()
|
|
@@ -2312,6 +2525,49 @@ describe('precompile server session unit guardrails', () => {
|
|
|
2312
2525
|
expect(persisted?.finalized).toBe(true)
|
|
2313
2526
|
})
|
|
2314
2527
|
|
|
2528
|
+
test.each([
|
|
2529
|
+
['unit', { units: 2 }, 0],
|
|
2530
|
+
['amount', { amount: '2' }, 0],
|
|
2531
|
+
['interval', { intervalMs: 500 }, 750],
|
|
2532
|
+
] as const)(
|
|
2533
|
+
'applies the %s settlement schedule after SSE charges',
|
|
2534
|
+
async (_label, settlementSchedule, chunkDelayMs) => {
|
|
2535
|
+
const settlements: Array<{ delta: bigint; trigger: string }> = []
|
|
2536
|
+
const harness = createManagedSseFetch({
|
|
2537
|
+
chunkDelayMs,
|
|
2538
|
+
maxDeposit: 3n,
|
|
2539
|
+
settlementSchedule,
|
|
2540
|
+
onSessionSettlement(context) {
|
|
2541
|
+
settlements.push({ delta: context.delta, trigger: context.trigger })
|
|
2542
|
+
},
|
|
2543
|
+
})
|
|
2544
|
+
const manager = precompileSessionManager({
|
|
2545
|
+
account: payer,
|
|
2546
|
+
client: createSigningClient(),
|
|
2547
|
+
decimals: 0,
|
|
2548
|
+
fetch: harness.fetch,
|
|
2549
|
+
maxDeposit: '3',
|
|
2550
|
+
})
|
|
2551
|
+
|
|
2552
|
+
const chunks: string[] = []
|
|
2553
|
+
for await (const chunk of await manager.sse('https://api.example.com/stream')) {
|
|
2554
|
+
chunks.push(chunk)
|
|
2555
|
+
}
|
|
2556
|
+
|
|
2557
|
+
expect(chunks).toEqual(['chunk-1', 'chunk-2', 'chunk-3'])
|
|
2558
|
+
expect(harness.voucherPosts).toBeGreaterThan(0)
|
|
2559
|
+
expect(settlements).toEqual([{ delta: 2n, trigger: 'scheduled' }])
|
|
2560
|
+
const persisted = await channelStore(harness.rawStore).getChannel(manager.channelId!)
|
|
2561
|
+
expect(persisted?.lastSettlementUnits).toBe(2)
|
|
2562
|
+
|
|
2563
|
+
await manager.close()
|
|
2564
|
+
expect(settlements).toEqual([
|
|
2565
|
+
{ delta: 2n, trigger: 'scheduled' },
|
|
2566
|
+
{ delta: 1n, trigger: 'close' },
|
|
2567
|
+
])
|
|
2568
|
+
},
|
|
2569
|
+
)
|
|
2570
|
+
|
|
2315
2571
|
test('handles empty management POST streams through a Node adapter', async () => {
|
|
2316
2572
|
const harness = createManagedSseFetch({ maxDeposit: 1n })
|
|
2317
2573
|
const managementPosts: Array<{
|
|
@@ -2422,11 +2678,18 @@ describe('precompile server session unit guardrails', () => {
|
|
|
2422
2678
|
|
|
2423
2679
|
describe('WebSocket parity', () => {
|
|
2424
2680
|
async function createManagedWsHarness(
|
|
2425
|
-
options: {
|
|
2681
|
+
options: {
|
|
2682
|
+
challengeTtlMs?: number
|
|
2683
|
+
maxDeposit?: bigint
|
|
2684
|
+
onSessionSettlement?: session.Parameters['onSessionSettlement']
|
|
2685
|
+
settlementSchedule?: session.Parameters['settlementSchedule']
|
|
2686
|
+
} = {},
|
|
2426
2687
|
) {
|
|
2427
2688
|
const rawStore = Store.memory()
|
|
2689
|
+
let activeChannelId: Hex | undefined
|
|
2428
2690
|
let challengeRequests = 0
|
|
2429
2691
|
let currentPayload: SessionCredentialPayload | undefined
|
|
2692
|
+
let settled = 0n
|
|
2430
2693
|
let voucherPosts = 0
|
|
2431
2694
|
const maxDeposit = options.maxDeposit ?? 3n
|
|
2432
2695
|
const payment = Mppx_server.create({
|
|
@@ -2436,7 +2699,9 @@ describe('precompile server session unit guardrails', () => {
|
|
|
2436
2699
|
chainId,
|
|
2437
2700
|
currency: token,
|
|
2438
2701
|
decimals: 0,
|
|
2702
|
+
onSessionSettlement: options.onSessionSettlement,
|
|
2439
2703
|
recipient: payer.address,
|
|
2704
|
+
settlementSchedule: options.settlementSchedule,
|
|
2440
2705
|
store: rawStore,
|
|
2441
2706
|
unitType: 'token',
|
|
2442
2707
|
getClient: () => {
|
|
@@ -2453,13 +2718,17 @@ describe('precompile server session unit guardrails', () => {
|
|
|
2453
2718
|
receipt: transactionReceipt([
|
|
2454
2719
|
closedLog(payload.channelId, BigInt(payload.cumulativeAmount), 0n),
|
|
2455
2720
|
]),
|
|
2456
|
-
state: { settled
|
|
2721
|
+
state: { settled, deposit: maxDeposit, closeRequestedAt: 0 },
|
|
2457
2722
|
})
|
|
2458
2723
|
}
|
|
2459
|
-
return
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2724
|
+
return createServerClient([], payer, undefined, {
|
|
2725
|
+
sentReceipt: async () => {
|
|
2726
|
+
if (!activeChannelId) throw new Error('missing channel context')
|
|
2727
|
+
const channel = await channelStore(rawStore).getChannel(activeChannelId)
|
|
2728
|
+
settled = channel?.highestVoucherAmount ?? settled
|
|
2729
|
+
return transactionReceipt([settledLog(activeChannelId, settled)])
|
|
2730
|
+
},
|
|
2731
|
+
state: () => ({ settled, deposit: maxDeposit, closeRequestedAt: 0 }),
|
|
2463
2732
|
})
|
|
2464
2733
|
},
|
|
2465
2734
|
}),
|
|
@@ -2468,23 +2737,26 @@ describe('precompile server session unit guardrails', () => {
|
|
|
2468
2737
|
secretKey: 'test-secret-key-test-secret-key-32',
|
|
2469
2738
|
})
|
|
2470
2739
|
|
|
2740
|
+
const routeOptions = () => ({
|
|
2741
|
+
amount: '1',
|
|
2742
|
+
decimals: 0,
|
|
2743
|
+
suggestedDeposit: maxDeposit.toString(),
|
|
2744
|
+
...(options.challengeTtlMs === undefined
|
|
2745
|
+
? {}
|
|
2746
|
+
: { expires: new Date(Date.now() + options.challengeTtlMs) }),
|
|
2747
|
+
})
|
|
2471
2748
|
const route = async (request: Request) => {
|
|
2472
2749
|
currentPayload = undefined
|
|
2473
2750
|
if (request.headers.has('Authorization')) {
|
|
2474
2751
|
try {
|
|
2475
2752
|
currentPayload = Credential.fromRequest<SessionCredentialPayload>(request).payload
|
|
2753
|
+
activeChannelId = currentPayload.channelId
|
|
2476
2754
|
if (currentPayload.action === 'voucher') voucherPosts++
|
|
2477
2755
|
} catch {}
|
|
2478
2756
|
} else challengeRequests++
|
|
2479
|
-
const
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
suggestedDeposit: maxDeposit.toString(),
|
|
2483
|
-
...(options.challengeTtlMs === undefined
|
|
2484
|
-
? {}
|
|
2485
|
-
: { expires: new Date(Date.now() + options.challengeTtlMs) }),
|
|
2486
|
-
})
|
|
2487
|
-
return routeHandler(request)
|
|
2757
|
+
const result = await payment.session(routeOptions())(request)
|
|
2758
|
+
currentPayload = undefined
|
|
2759
|
+
return result
|
|
2488
2760
|
}
|
|
2489
2761
|
|
|
2490
2762
|
const httpHandler = NodeRequest.toNodeListener(async (request) => {
|
|
@@ -2516,6 +2788,7 @@ describe('precompile server session unit guardrails', () => {
|
|
|
2516
2788
|
return {
|
|
2517
2789
|
rawStore,
|
|
2518
2790
|
route,
|
|
2791
|
+
serveWebSocket: payment.session.serveWebSocket,
|
|
2519
2792
|
server,
|
|
2520
2793
|
wsServer,
|
|
2521
2794
|
get port() {
|
|
@@ -2537,9 +2810,8 @@ describe('precompile server session unit guardrails', () => {
|
|
|
2537
2810
|
test('refreshes an expired challenge before sending a later websocket voucher', async () => {
|
|
2538
2811
|
const harness = await createManagedWsHarness({ challengeTtlMs: 2_000, maxDeposit: 2n })
|
|
2539
2812
|
harness.wsServer.on('connection', (socket: import('ws').WebSocket) => {
|
|
2540
|
-
void
|
|
2813
|
+
void harness.serveWebSocket({
|
|
2541
2814
|
socket,
|
|
2542
|
-
store: harness.rawStore,
|
|
2543
2815
|
url: `${harness.server.url}/ws`,
|
|
2544
2816
|
route: harness.route,
|
|
2545
2817
|
generate: async function* (stream: TempoWs.SessionController) {
|
|
@@ -2585,9 +2857,8 @@ describe('precompile server session unit guardrails', () => {
|
|
|
2585
2857
|
test('open -> stream -> need-voucher -> resume -> close', async () => {
|
|
2586
2858
|
const harness = await createManagedWsHarness({ maxDeposit: 3n })
|
|
2587
2859
|
harness.wsServer.on('connection', (socket: import('ws').WebSocket) => {
|
|
2588
|
-
void
|
|
2860
|
+
void harness.serveWebSocket({
|
|
2589
2861
|
socket,
|
|
2590
|
-
store: harness.rawStore,
|
|
2591
2862
|
url: `${harness.server.url}/ws`,
|
|
2592
2863
|
route: harness.route,
|
|
2593
2864
|
generate: async function* (stream: TempoWs.SessionController) {
|
|
@@ -2641,6 +2912,75 @@ describe('precompile server session unit guardrails', () => {
|
|
|
2641
2912
|
}
|
|
2642
2913
|
})
|
|
2643
2914
|
|
|
2915
|
+
test.each([
|
|
2916
|
+
['unit', { units: 2 }, 0],
|
|
2917
|
+
['amount', { amount: '2' }, 0],
|
|
2918
|
+
['interval', { intervalMs: 500 }, 750],
|
|
2919
|
+
] as const)(
|
|
2920
|
+
'applies the %s settlement schedule after websocket charges',
|
|
2921
|
+
async (_label, settlementSchedule, chunkDelayMs) => {
|
|
2922
|
+
const settlements: Array<{ delta: bigint; trigger: string }> = []
|
|
2923
|
+
const harness = await createManagedWsHarness({
|
|
2924
|
+
maxDeposit: 3n,
|
|
2925
|
+
settlementSchedule,
|
|
2926
|
+
onSessionSettlement(context) {
|
|
2927
|
+
settlements.push({ delta: context.delta, trigger: context.trigger })
|
|
2928
|
+
},
|
|
2929
|
+
})
|
|
2930
|
+
harness.wsServer.on('connection', (socket: import('ws').WebSocket) => {
|
|
2931
|
+
void harness.serveWebSocket({
|
|
2932
|
+
socket,
|
|
2933
|
+
url: `${harness.server.url}/ws`,
|
|
2934
|
+
route: harness.route,
|
|
2935
|
+
generate: async function* (stream: TempoWs.SessionController) {
|
|
2936
|
+
for (const chunk of ['chunk-1', 'chunk-2', 'chunk-3']) {
|
|
2937
|
+
if (chunk === 'chunk-2' && chunkDelayMs)
|
|
2938
|
+
await new Promise((resolve) => setTimeout(resolve, chunkDelayMs))
|
|
2939
|
+
await stream.charge()
|
|
2940
|
+
yield chunk
|
|
2941
|
+
}
|
|
2942
|
+
},
|
|
2943
|
+
})
|
|
2944
|
+
})
|
|
2945
|
+
|
|
2946
|
+
try {
|
|
2947
|
+
const manager = precompileSessionManager({
|
|
2948
|
+
account: payer,
|
|
2949
|
+
client: createSigningClient(),
|
|
2950
|
+
decimals: 0,
|
|
2951
|
+
fetch: globalThis.fetch,
|
|
2952
|
+
maxDeposit: '3',
|
|
2953
|
+
webSocket: WebSocket as never,
|
|
2954
|
+
})
|
|
2955
|
+
const ws = await manager.ws(`ws://localhost:${harness.port}/ws`)
|
|
2956
|
+
const chunks: string[] = []
|
|
2957
|
+
|
|
2958
|
+
await new Promise<void>((resolve, reject) => {
|
|
2959
|
+
ws.addEventListener('message', (event) => {
|
|
2960
|
+
if (typeof event.data === 'string') chunks.push(event.data)
|
|
2961
|
+
})
|
|
2962
|
+
ws.addEventListener('close', () => resolve(), { once: true })
|
|
2963
|
+
ws.addEventListener('error', () => reject(new Error('websocket stream failed')), {
|
|
2964
|
+
once: true,
|
|
2965
|
+
})
|
|
2966
|
+
})
|
|
2967
|
+
|
|
2968
|
+
expect(chunks).toEqual(['chunk-1', 'chunk-2', 'chunk-3'])
|
|
2969
|
+
expect(harness.voucherPosts).toBeGreaterThan(0)
|
|
2970
|
+
expect(settlements).toEqual([{ delta: 2n, trigger: 'scheduled' }])
|
|
2971
|
+
await manager.close()
|
|
2972
|
+
expect(settlements).toEqual([
|
|
2973
|
+
{ delta: 2n, trigger: 'scheduled' },
|
|
2974
|
+
{ delta: 1n, trigger: 'close' },
|
|
2975
|
+
])
|
|
2976
|
+
const persisted = await channelStore(harness.rawStore).getChannel(manager.channelId!)
|
|
2977
|
+
expect(persisted?.lastSettlementUnits).toBe(2)
|
|
2978
|
+
} finally {
|
|
2979
|
+
harness.close()
|
|
2980
|
+
}
|
|
2981
|
+
},
|
|
2982
|
+
)
|
|
2983
|
+
|
|
2644
2984
|
test('treats control-shaped application payloads as content', async () => {
|
|
2645
2985
|
const harness = await createManagedWsHarness({ maxDeposit: 1n })
|
|
2646
2986
|
const controlLookingChunk = JSON.stringify({
|
|
@@ -2653,9 +2993,8 @@ describe('precompile server session unit guardrails', () => {
|
|
|
2653
2993
|
},
|
|
2654
2994
|
})
|
|
2655
2995
|
harness.wsServer.on('connection', (socket: import('ws').WebSocket) => {
|
|
2656
|
-
void
|
|
2996
|
+
void harness.serveWebSocket({
|
|
2657
2997
|
socket,
|
|
2658
|
-
store: harness.rawStore,
|
|
2659
2998
|
url: `${harness.server.url}/ws`,
|
|
2660
2999
|
route: harness.route,
|
|
2661
3000
|
generate: async function* (stream: TempoWs.SessionController) {
|
|
@@ -2703,9 +3042,8 @@ describe('precompile server session unit guardrails', () => {
|
|
|
2703
3042
|
test('refuses websocket voucher requests beyond local maxDeposit', async () => {
|
|
2704
3043
|
const harness = await createManagedWsHarness({ maxDeposit: 1n })
|
|
2705
3044
|
harness.wsServer.on('connection', (socket: import('ws').WebSocket) => {
|
|
2706
|
-
void
|
|
3045
|
+
void harness.serveWebSocket({
|
|
2707
3046
|
socket,
|
|
2708
|
-
store: harness.rawStore,
|
|
2709
3047
|
url: `${harness.server.url}/ws`,
|
|
2710
3048
|
route: harness.route,
|
|
2711
3049
|
generate: async function* (stream: TempoWs.SessionController) {
|
|
@@ -2865,9 +3203,8 @@ describe('precompile server session unit guardrails', () => {
|
|
|
2865
3203
|
let serverSocket: import('ws').WebSocket | null = null
|
|
2866
3204
|
harness.wsServer.on('connection', (socket: import('ws').WebSocket) => {
|
|
2867
3205
|
serverSocket = socket
|
|
2868
|
-
void
|
|
3206
|
+
void harness.serveWebSocket({
|
|
2869
3207
|
socket,
|
|
2870
|
-
store: harness.rawStore,
|
|
2871
3208
|
url: `${harness.server.url}/ws`,
|
|
2872
3209
|
route: harness.route,
|
|
2873
3210
|
generate: async function* (stream: TempoWs.SessionController) {
|
|
@@ -3461,6 +3798,54 @@ describe('precompile server session unit guardrails', () => {
|
|
|
3461
3798
|
})
|
|
3462
3799
|
})
|
|
3463
3800
|
|
|
3801
|
+
describe('session settlement extensions', () => {
|
|
3802
|
+
test.each([
|
|
3803
|
+
['no schedule is configured', undefined],
|
|
3804
|
+
['the configured threshold is not due', { units: 11 }],
|
|
3805
|
+
] as const)('does not resolve a client when %s', async (_label, settlementSchedule) => {
|
|
3806
|
+
const rawStore = Store.memory()
|
|
3807
|
+
const store = channelStore(rawStore)
|
|
3808
|
+
const openPayload = await createOpenPayload()
|
|
3809
|
+
let clientResolutions = 0
|
|
3810
|
+
await persistPrecompileChannel(store, openPayload, {
|
|
3811
|
+
highestVoucherAmount: 500n,
|
|
3812
|
+
highestVoucher: {
|
|
3813
|
+
channelId: openPayload.channelId,
|
|
3814
|
+
cumulativeAmount: 500n,
|
|
3815
|
+
signature: '0x1234',
|
|
3816
|
+
},
|
|
3817
|
+
spent: 500n,
|
|
3818
|
+
units: 10,
|
|
3819
|
+
})
|
|
3820
|
+
|
|
3821
|
+
const payment = Mppx_server.create({
|
|
3822
|
+
methods: [
|
|
3823
|
+
tempo_server.session({
|
|
3824
|
+
account: payer,
|
|
3825
|
+
amount: '1',
|
|
3826
|
+
chainId,
|
|
3827
|
+
currency: token,
|
|
3828
|
+
decimals: 0,
|
|
3829
|
+
getClient() {
|
|
3830
|
+
clientResolutions++
|
|
3831
|
+
throw new Error('client should not be resolved')
|
|
3832
|
+
},
|
|
3833
|
+
recipient: payee,
|
|
3834
|
+
settlementSchedule,
|
|
3835
|
+
store: rawStore,
|
|
3836
|
+
unitType: 'token',
|
|
3837
|
+
}),
|
|
3838
|
+
],
|
|
3839
|
+
realm: 'api.example.com',
|
|
3840
|
+
secretKey: 'test-secret-key-test-secret-key-32',
|
|
3841
|
+
})
|
|
3842
|
+
const channel = await store.getChannel(openPayload.channelId)
|
|
3843
|
+
|
|
3844
|
+
await expect(payment.session.settleScheduled(channel!)).resolves.toBeUndefined()
|
|
3845
|
+
expect(clientResolutions).toBe(0)
|
|
3846
|
+
})
|
|
3847
|
+
})
|
|
3848
|
+
|
|
3464
3849
|
describe('onSessionSettlement', () => {
|
|
3465
3850
|
function createSettleClient(channelId: Hex, settledAmount: bigint) {
|
|
3466
3851
|
return createClient({
|