mppx 0.8.14 → 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 +57 -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/cli/validate/payment.d.ts.map +1 -1
- package/dist/cli/validate/payment.js +18 -4
- package/dist/cli/validate/payment.js.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 +92 -13
- package/dist/client/internal/Fetch.js.map +1 -1
- package/dist/client/internal/MethodChallenge.d.ts +2 -0
- package/dist/client/internal/MethodChallenge.d.ts.map +1 -1
- package/dist/client/internal/MethodChallenge.js +4 -0
- package/dist/client/internal/MethodChallenge.js.map +1 -1
- package/dist/client/internal/MethodResponse.d.ts +15 -0
- package/dist/client/internal/MethodResponse.d.ts.map +1 -1
- package/dist/client/internal/MethodResponse.js +10 -0
- package/dist/client/internal/MethodResponse.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 +34 -12
- 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 +14 -5
- package/dist/tempo/server/Relay.d.ts.map +1 -1
- package/dist/tempo/server/Relay.js +6 -4
- package/dist/tempo/server/Relay.js.map +1 -1
- package/dist/tempo/server/SponsorBudget.d.ts.map +1 -1
- package/dist/tempo/server/SponsorBudget.js +7 -1
- package/dist/tempo/server/SponsorBudget.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.d.ts.map +1 -1
- package/dist/tempo/session/client/Session.js +128 -14
- package/dist/tempo/session/client/Session.js.map +1 -1
- package/dist/tempo/session/client/SessionManager.d.ts.map +1 -1
- package/dist/tempo/session/client/SessionManager.js +62 -20
- package/dist/tempo/session/client/SessionManager.js.map +1 -1
- package/dist/tempo/session/client/Transports.d.ts +9 -1
- package/dist/tempo/session/client/Transports.d.ts.map +1 -1
- package/dist/tempo/session/client/Transports.js +36 -13
- package/dist/tempo/session/client/Transports.js.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 +4 -0
- package/dist/tempo/session/server/Ws.js.map +1 -1
- package/dist/tempo/subscription/KeyAuthorization.d.ts +38 -866
- package/dist/tempo/subscription/KeyAuthorization.d.ts.map +1 -1
- package/dist/tempo/subscription/KeyAuthorization.js +14 -3
- package/dist/tempo/subscription/KeyAuthorization.js.map +1 -1
- package/dist/viem/Account.d.ts.map +1 -1
- package/dist/viem/Account.js.map +1 -1
- package/dist/viem/Client.d.ts.map +1 -1
- package/dist/viem/Client.js +6 -1
- package/dist/viem/Client.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 +20 -4
- 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/cli/validate/payment.ts +18 -4
- package/src/cli/validate.test.ts +16 -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.test.ts +77 -0
- package/src/client/internal/Fetch.ts +112 -14
- package/src/client/internal/MethodChallenge.ts +5 -0
- package/src/client/internal/MethodResponse.ts +28 -0
- 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 +92 -56
- package/src/tempo/server/Methods.ts +0 -20
- package/src/tempo/server/Relay.test.ts +161 -7
- package/src/tempo/server/Relay.ts +15 -6
- package/src/tempo/server/SponsorBudget.test.ts +29 -0
- package/src/tempo/server/SponsorBudget.ts +7 -1
- 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 +119 -0
- package/src/tempo/session/client/Session.test.ts +299 -33
- package/src/tempo/session/client/Session.ts +152 -16
- package/src/tempo/session/client/SessionManager.test.ts +216 -9
- package/src/tempo/session/client/SessionManager.ts +63 -17
- package/src/tempo/session/client/Transports.test.ts +22 -0
- package/src/tempo/session/client/Transports.ts +58 -22
- 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 +483 -36
- 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 +10 -1
- package/src/tempo/subscription/KeyAuthorization.test.ts +70 -1
- package/src/tempo/subscription/KeyAuthorization.ts +14 -3
- package/src/viem/Client.test.ts +18 -1
- package/src/viem/Client.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
package/src/server/Mppx.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from 'node:http'
|
|
2
2
|
import { isDeepStrictEqual } from 'node:util'
|
|
3
3
|
|
|
4
|
+
import * as AttestationServer from '../attestation/Server.js'
|
|
5
|
+
import type * as Attestation from '../attestation/Types.js'
|
|
4
6
|
import * as Challenge from '../Challenge.js'
|
|
5
7
|
import * as Constants from '../Constants.js'
|
|
6
8
|
import * as Credential from '../Credential.js'
|
|
@@ -8,7 +10,7 @@ import * as Errors from '../Errors.js'
|
|
|
8
10
|
import * as Expires from '../Expires.js'
|
|
9
11
|
import * as AcceptPayment from '../internal/AcceptPayment.js'
|
|
10
12
|
import * as Env from '../internal/env.js'
|
|
11
|
-
import type { MaybePromise } from '../internal/types.js'
|
|
13
|
+
import type { DeepReadonly, MaybePromise } from '../internal/types.js'
|
|
12
14
|
import * as Method from '../Method.js'
|
|
13
15
|
import * as PaymentRequest from '../PaymentRequest.js'
|
|
14
16
|
import type * as Receipt from '../Receipt.js'
|
|
@@ -85,6 +87,41 @@ export type ServerMethodDescriptor<
|
|
|
85
87
|
name: method['name']
|
|
86
88
|
}>
|
|
87
89
|
|
|
90
|
+
/** A configured payment offer exposed to the server's `selectOffers` hook. */
|
|
91
|
+
export type ServerOffer<method extends Method.Method = Method.Method> = method extends unknown
|
|
92
|
+
? ServerOfferFor<method>
|
|
93
|
+
: never
|
|
94
|
+
|
|
95
|
+
type ServerOfferFor<method extends Method.Method> = Readonly<{
|
|
96
|
+
/** Canonical wire key for the configured method. */
|
|
97
|
+
key: `${method['name']}/${method['intent']}`
|
|
98
|
+
/** Immutable method metadata for this offer. */
|
|
99
|
+
method: ServerOfferMethodDescriptor<method>
|
|
100
|
+
/** Schema-normalized request configured for this offer. */
|
|
101
|
+
request: DeepReadonly<z.output<method['schema']['request']>>
|
|
102
|
+
}>
|
|
103
|
+
|
|
104
|
+
/** Immutable method metadata exposed to offer-selection hooks. */
|
|
105
|
+
export type ServerOfferMethodDescriptor<method extends Method.Method = Method.Method> = Readonly<{
|
|
106
|
+
/** Optional public alias used to register this server method. */
|
|
107
|
+
alias?: method extends { alias?: infer alias } ? alias : string
|
|
108
|
+
intent: method['intent']
|
|
109
|
+
name: method['name']
|
|
110
|
+
}>
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Selects a subset of configured offers before payment challenges are issued.
|
|
114
|
+
*
|
|
115
|
+
* The hook must select at least one offer. Returned offers must come from the input,
|
|
116
|
+
* contain no duplicates, and preserve their original order. Offers and their
|
|
117
|
+
* normalized requests are deeply immutable. The incoming request is cloned so
|
|
118
|
+
* the hook may safely inspect its body when it has not already been consumed.
|
|
119
|
+
*/
|
|
120
|
+
export type SelectOffers<methods extends readonly Method.Method[]> = (
|
|
121
|
+
offers: readonly ServerOffer<methods[number]>[],
|
|
122
|
+
context: Readonly<{ request: globalThis.Request }>,
|
|
123
|
+
) => MaybePromise<readonly ServerOffer<methods[number]>[]>
|
|
124
|
+
|
|
88
125
|
/** Context passed to `onChallengeCreated`. */
|
|
89
126
|
export type ChallengeContext<
|
|
90
127
|
method extends Method.Method = Method.Method,
|
|
@@ -227,9 +264,7 @@ export type Mppx<
|
|
|
227
264
|
* })
|
|
228
265
|
* ```
|
|
229
266
|
*/
|
|
230
|
-
compose(
|
|
231
|
-
...entries: ComposeEntry<FlattenMethods<methods>>[]
|
|
232
|
-
): (input: Request) => Promise<MethodFn.Response<Transport.Http>>
|
|
267
|
+
compose(...entries: ComposeEntry<FlattenMethods<methods>>[]): ComposedHandler
|
|
233
268
|
}
|
|
234
269
|
: {}) &
|
|
235
270
|
Handlers<FlattenMethods<methods>, transport> & {
|
|
@@ -339,22 +374,37 @@ type IsUniqueIntent<methods extends readonly Method.AnyServer[], intent extends
|
|
|
339
374
|
: never
|
|
340
375
|
: never
|
|
341
376
|
|
|
342
|
-
/**
|
|
343
|
-
|
|
377
|
+
/** Shorthand intent handlers. Single-method intents get direct handlers;
|
|
378
|
+
* multi-method intents get an implicit compose wrapper. */
|
|
379
|
+
type IntentHandlers<
|
|
344
380
|
methods extends readonly Method.AnyServer[],
|
|
345
381
|
transport extends Transport.AnyTransport,
|
|
346
382
|
> = {
|
|
347
|
-
[
|
|
348
|
-
?
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
}
|
|
383
|
+
[intent in methods[number]['intent'] as intent extends ReservedKey
|
|
384
|
+
? never
|
|
385
|
+
: intent]: IsUniqueIntent<methods, intent> extends true
|
|
386
|
+
? MethodFn<
|
|
387
|
+
Extract<methods[number], { intent: intent }>,
|
|
388
|
+
EffectiveTransportOf<Extract<methods[number], { intent: intent }>, transport>,
|
|
389
|
+
NonNullable<Extract<methods[number], { intent: intent }>['defaults']>
|
|
390
|
+
> &
|
|
391
|
+
MethodExtensions<Extract<methods[number], { intent: intent }>>
|
|
392
|
+
: MultiMethodFn<Extract<methods[number], { intent: intent }>, transport>
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/** Handler for an intent with multiple methods - takes the intersection of all methods' options. */
|
|
396
|
+
type MultiMethodFn<methods extends Method.AnyServer, transport extends Transport.AnyTransport> = (
|
|
397
|
+
options: UnionToIntersection<MultiMethodFnDistribute<methods>>,
|
|
398
|
+
) => (input: Transport.InputOf<transport>) => Promise<MethodFn.Response<transport>>
|
|
399
|
+
|
|
400
|
+
type MultiMethodFnDistribute<M> =
|
|
401
|
+
M extends Method.Server<infer method, infer defaults, any, any, any>
|
|
402
|
+
? MethodFn.Options<method, NonNullable<defaults>>
|
|
403
|
+
: never
|
|
404
|
+
|
|
405
|
+
type UnionToIntersection<U> = (U extends any ? (x: U) => void : never) extends (x: infer I) => void
|
|
406
|
+
? I
|
|
407
|
+
: never
|
|
358
408
|
|
|
359
409
|
/** Nested handlers: `mppx.tempo.charge(...)`, grouped by method name then intent. */
|
|
360
410
|
type PublicAlias<method extends Method.AnyServer> = method extends {
|
|
@@ -399,7 +449,7 @@ type Handlers<
|
|
|
399
449
|
NonNullable<mi['defaults']>
|
|
400
450
|
> &
|
|
401
451
|
MethodExtensions<mi>
|
|
402
|
-
} &
|
|
452
|
+
} & IntentHandlers<methods, transport> &
|
|
403
453
|
NestedHandlers<methods, transport> & {
|
|
404
454
|
[mi in methods[number] as PublicAlias<mi> extends string
|
|
405
455
|
? `${mi['name']}/${PublicAlias<mi>}`
|
|
@@ -451,7 +501,9 @@ export function create<
|
|
|
451
501
|
const transport extends Transport.AnyTransport = Transport.Http,
|
|
452
502
|
>(config: create.Config<methods, transport>): Mppx<methods, transport> {
|
|
453
503
|
const {
|
|
504
|
+
attestation,
|
|
454
505
|
realm = Env.get('realm'),
|
|
506
|
+
selectOffers,
|
|
455
507
|
secretKey = Env.get('secretKey'),
|
|
456
508
|
transport = Transport.http() as transport,
|
|
457
509
|
} = config
|
|
@@ -465,17 +517,32 @@ export function create<
|
|
|
465
517
|
|
|
466
518
|
const methods = config.methods.flat() as unknown as FlattenMethods<methods>
|
|
467
519
|
const serverEvents = createServerEventDispatcher<FlattenMethods<methods>, transport>()
|
|
520
|
+
const verifyAttestation = attestation
|
|
521
|
+
? createAttestationGuard(attestation as Attestation.VerifierMap)
|
|
522
|
+
: undefined
|
|
468
523
|
|
|
469
524
|
const handlers: Record<string, unknown> = {}
|
|
470
525
|
const intentCount: Record<string, number> = {}
|
|
471
526
|
|
|
472
527
|
for (const mi of methods) {
|
|
473
528
|
intentCount[mi.intent] = (intentCount[mi.intent] ?? 0) + 1
|
|
529
|
+
if (mi.onPaymentSuccess) {
|
|
530
|
+
serverEvents.on('payment.success', (async (ctx: PaymentSuccessContext) => {
|
|
531
|
+
if (ctx.method.name === mi.name && ctx.method.intent === mi.intent) {
|
|
532
|
+
await mi.onPaymentSuccess({
|
|
533
|
+
input: ctx.input,
|
|
534
|
+
receipt: ctx.receipt,
|
|
535
|
+
request: ctx.request,
|
|
536
|
+
})
|
|
537
|
+
}
|
|
538
|
+
}) as never)
|
|
539
|
+
}
|
|
474
540
|
}
|
|
475
541
|
assertNoReservedMppxKeys(methods as readonly Method.AnyServer[])
|
|
476
542
|
|
|
477
543
|
for (const mi of methods) {
|
|
478
544
|
const fn = createMethodFn({
|
|
545
|
+
...(verifyAttestation && { attest: verifyAttestation }),
|
|
479
546
|
authorize: mi.authorize as never,
|
|
480
547
|
defaults: mi.defaults,
|
|
481
548
|
method: mi,
|
|
@@ -498,9 +565,32 @@ export function create<
|
|
|
498
565
|
if (aliasKey) handlers[aliasKey] = fn
|
|
499
566
|
}
|
|
500
567
|
|
|
501
|
-
//
|
|
568
|
+
// Set shorthand intent key: single method gets direct handler,
|
|
569
|
+
// multiple methods get an implicit compose wrapper.
|
|
570
|
+
const processedIntents = new Set<string>()
|
|
502
571
|
for (const mi of methods) {
|
|
503
|
-
if (
|
|
572
|
+
if (processedIntents.has(mi.intent)) continue
|
|
573
|
+
processedIntents.add(mi.intent)
|
|
574
|
+
|
|
575
|
+
if (intentCount[mi.intent] === 1) {
|
|
576
|
+
handlers[mi.intent] = handlers[`${mi.name}/${mi.intent}`]
|
|
577
|
+
} else {
|
|
578
|
+
const intentMethods = (methods as readonly Method.AnyServer[]).filter(
|
|
579
|
+
(m) => m.intent === mi.intent,
|
|
580
|
+
)
|
|
581
|
+
handlers[mi.intent] = (options: Record<string, unknown>) => {
|
|
582
|
+
const configured = intentMethods.map((m) => {
|
|
583
|
+
const key = `${m.name}/${m.intent}`
|
|
584
|
+
const handlerFn = handlers[key] as AnyMethodFn
|
|
585
|
+
return handlerFn(options)
|
|
586
|
+
})
|
|
587
|
+
return composeHandlers(
|
|
588
|
+
configured as ConfiguredHandler[],
|
|
589
|
+
undefined,
|
|
590
|
+
selectOffers as SelectOffers<readonly Method.AnyServer[]> | undefined,
|
|
591
|
+
)
|
|
592
|
+
}
|
|
593
|
+
}
|
|
504
594
|
}
|
|
505
595
|
|
|
506
596
|
// Build nested handlers: mppx.tempo.charge(...)
|
|
@@ -539,7 +629,7 @@ export function create<
|
|
|
539
629
|
const methodCandidates = (methods as readonly Method.AnyServer[]).filter(
|
|
540
630
|
(m) => m.name === credMethod && m.intent === credIntent,
|
|
541
631
|
)
|
|
542
|
-
const mi =
|
|
632
|
+
const mi = methodCandidates[0]
|
|
543
633
|
const eventMethod =
|
|
544
634
|
mi ?? ({ intent: credIntent, name: credMethod } satisfies ServerMethodDescriptor)
|
|
545
635
|
|
|
@@ -806,7 +896,11 @@ export function create<
|
|
|
806
896
|
throw new Error(`No handler for "${key}". Is this method in your methods array?`)
|
|
807
897
|
return handlerFn(options)
|
|
808
898
|
})
|
|
809
|
-
return
|
|
899
|
+
return composeHandlers(
|
|
900
|
+
configured as ConfiguredHandler[],
|
|
901
|
+
undefined,
|
|
902
|
+
selectOffers as SelectOffers<readonly Method.AnyServer[]> | undefined,
|
|
903
|
+
)
|
|
810
904
|
}
|
|
811
905
|
|
|
812
906
|
function onChallengeCreated(
|
|
@@ -858,12 +952,18 @@ export declare namespace create {
|
|
|
858
952
|
methods extends Methods = Methods,
|
|
859
953
|
transport extends Transport.AnyTransport = Transport.Http,
|
|
860
954
|
> = {
|
|
955
|
+
/** Request-attestation verifiers required before handling an HTTP payment request. */
|
|
956
|
+
attestation?: transport extends Transport.Http ? Attestation.VerifierMap | undefined : never
|
|
861
957
|
/** Array of configured methods. @example [tempo()] */
|
|
862
958
|
methods: methods
|
|
863
959
|
/** Server realm (e.g., hostname). Resolution order: explicit value > env vars (`MPP_REALM`, `FLY_APP_NAME`, `VERCEL_URL`, etc.) > request URL hostname > `"MPP Payment"`. */
|
|
864
960
|
realm?: string | undefined
|
|
865
961
|
/** Secret key for HMAC-bound challenge IDs for stateless verification. Must be at least 32 bytes. Auto-detected from `MPP_SECRET_KEY` environment variable. */
|
|
866
962
|
secretKey?: string | undefined
|
|
963
|
+
/** Selects a subset of composed HTTP offers before challenges are issued. Successfully matched credential dispatch bypasses this hook. */
|
|
964
|
+
selectOffers?: transport extends Transport.Http
|
|
965
|
+
? SelectOffers<FlattenMethods<methods>> | undefined
|
|
966
|
+
: never
|
|
867
967
|
/** Transport to use. @default Transport.http() */
|
|
868
968
|
transport?: transport | undefined
|
|
869
969
|
}
|
|
@@ -879,6 +979,7 @@ function createMethodFn<
|
|
|
879
979
|
// biome-ignore lint/correctness/noUnusedVariables: _
|
|
880
980
|
function createMethodFn(parameters: createMethodFn.Parameters): createMethodFn.ReturnType {
|
|
881
981
|
const {
|
|
982
|
+
attest,
|
|
882
983
|
authorize,
|
|
883
984
|
defaults,
|
|
884
985
|
events,
|
|
@@ -897,7 +998,7 @@ function createMethodFn(parameters: createMethodFn.Parameters): createMethodFn.R
|
|
|
897
998
|
return (options) => {
|
|
898
999
|
const { description, meta, scope, ...rest } = options
|
|
899
1000
|
const staticMeta = Scope.merge({ meta, scope })
|
|
900
|
-
const internal
|
|
1001
|
+
const internal = {
|
|
901
1002
|
...method,
|
|
902
1003
|
...defaults,
|
|
903
1004
|
...options,
|
|
@@ -907,9 +1008,21 @@ function createMethodFn(parameters: createMethodFn.Parameters): createMethodFn.R
|
|
|
907
1008
|
html: method.html,
|
|
908
1009
|
_canonicalRequest: PaymentRequest.fromMethod(method, { ...defaults, ...rest }),
|
|
909
1010
|
_stableBinding: stableBinding as never,
|
|
910
|
-
}
|
|
1011
|
+
} as unknown as ConfiguredHandler['_internal']
|
|
1012
|
+
Object.defineProperty(internal, '_method', { value: method })
|
|
911
1013
|
|
|
912
1014
|
const handler = async (input: Transport.InputOf): Promise<MethodFn.Response> => {
|
|
1015
|
+
if (attest && input instanceof globalThis.Request) {
|
|
1016
|
+
const response = await attest(input)
|
|
1017
|
+
if (response)
|
|
1018
|
+
return {
|
|
1019
|
+
status: 200,
|
|
1020
|
+
withReceipt() {
|
|
1021
|
+
return response
|
|
1022
|
+
},
|
|
1023
|
+
} as MethodFn.Response
|
|
1024
|
+
}
|
|
1025
|
+
|
|
913
1026
|
if (method.html && isServiceWorkerRequest(input))
|
|
914
1027
|
return {
|
|
915
1028
|
status: 402,
|
|
@@ -1454,6 +1567,7 @@ declare namespace createMethodFn {
|
|
|
1454
1567
|
transport extends Transport.AnyTransport = Transport.Http,
|
|
1455
1568
|
defaults extends Record<string, unknown> = Record<string, unknown>,
|
|
1456
1569
|
> = {
|
|
1570
|
+
attest?: (request: globalThis.Request) => Promise<globalThis.Response | undefined>
|
|
1457
1571
|
authorize?: Method.AuthorizeFn<method>
|
|
1458
1572
|
defaults?: defaults
|
|
1459
1573
|
method: method
|
|
@@ -1477,6 +1591,39 @@ declare namespace createMethodFn {
|
|
|
1477
1591
|
> = MethodFn<method, transport, defaults>
|
|
1478
1592
|
}
|
|
1479
1593
|
|
|
1594
|
+
function createAttestationGuard(verifiers: Attestation.VerifierMap) {
|
|
1595
|
+
const entries = Object.entries(verifiers)
|
|
1596
|
+
if (entries.length === 0)
|
|
1597
|
+
throw new TypeError('Mppx server attestation must configure at least one verifier.')
|
|
1598
|
+
|
|
1599
|
+
const cache = new WeakMap<globalThis.Request, Promise<globalThis.Response | undefined>>()
|
|
1600
|
+
return (request: globalThis.Request): Promise<globalThis.Response | undefined> => {
|
|
1601
|
+
const cached = cache.get(request)
|
|
1602
|
+
if (cached) return cached
|
|
1603
|
+
|
|
1604
|
+
const verification = AttestationServer.verify(request, verifiers).then((outcomes) => {
|
|
1605
|
+
for (const [name, outcome] of Object.entries(outcomes))
|
|
1606
|
+
if (outcome.status === 'invalid')
|
|
1607
|
+
return new globalThis.Response(
|
|
1608
|
+
`Request attestation "${name}" is invalid: ${outcome.reason}`,
|
|
1609
|
+
{ status: 401 },
|
|
1610
|
+
)
|
|
1611
|
+
|
|
1612
|
+
for (const [name, outcome] of Object.entries(outcomes)) {
|
|
1613
|
+
if (outcome.status === 'verified') continue
|
|
1614
|
+
const reason =
|
|
1615
|
+
outcome.status === 'unverified'
|
|
1616
|
+
? `Request attestation "${name}" could not be verified: ${outcome.reason}`
|
|
1617
|
+
: `Request attestation "${name}" is required.`
|
|
1618
|
+
return new globalThis.Response(reason, { status: 403 })
|
|
1619
|
+
}
|
|
1620
|
+
return undefined
|
|
1621
|
+
})
|
|
1622
|
+
cache.set(request, verification)
|
|
1623
|
+
return verification
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1480
1627
|
type ServerEventDispatcher<
|
|
1481
1628
|
methods extends readonly Method.Method[],
|
|
1482
1629
|
transport extends Transport.AnyTransport,
|
|
@@ -2169,6 +2316,8 @@ declare namespace MethodFn {
|
|
|
2169
2316
|
/** A configured handler — the return value of e.g. `mppx.charge({ ... })`. @internal */
|
|
2170
2317
|
type ConfiguredHandler = ((input: Request) => Promise<MethodFn.Response<Transport.Http>>) & {
|
|
2171
2318
|
_internal: {
|
|
2319
|
+
_method: Method.AnyServer
|
|
2320
|
+
description?: string | undefined
|
|
2172
2321
|
name: string
|
|
2173
2322
|
intent: string
|
|
2174
2323
|
html: Html.Options | undefined
|
|
@@ -2179,6 +2328,16 @@ type ConfiguredHandler = ((input: Request) => Promise<MethodFn.Response<Transpor
|
|
|
2179
2328
|
}
|
|
2180
2329
|
}
|
|
2181
2330
|
|
|
2331
|
+
type ComposedHandler = ((input: Request) => Promise<MethodFn.Response<Transport.Http>>) & {
|
|
2332
|
+
_internal?: {
|
|
2333
|
+
offers: readonly ConfiguredHandler['_internal'][]
|
|
2334
|
+
}
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2337
|
+
type HandlerDiscoveryMetadata =
|
|
2338
|
+
| ConfiguredHandler['_internal']
|
|
2339
|
+
| NonNullable<ComposedHandler['_internal']>
|
|
2340
|
+
|
|
2182
2341
|
const paymentAuthChallengeHeader = Constants.Headers.wwwAuthenticate
|
|
2183
2342
|
|
|
2184
2343
|
const challengeHeaderMerges = [
|
|
@@ -2252,9 +2411,7 @@ type ComposeEntry<methods extends readonly Method.AnyServer[]> =
|
|
|
2252
2411
|
*/
|
|
2253
2412
|
type ComposeHtmlOptions = Html.Config
|
|
2254
2413
|
|
|
2255
|
-
export function compose(
|
|
2256
|
-
...args: readonly unknown[]
|
|
2257
|
-
): (input: Request) => Promise<MethodFn.Response<Transport.Http>> {
|
|
2414
|
+
export function compose(...args: readonly unknown[]): ComposedHandler {
|
|
2258
2415
|
// Extract optional html options from last argument
|
|
2259
2416
|
const last = args[args.length - 1]
|
|
2260
2417
|
const composeOptions: Html.Options | undefined =
|
|
@@ -2277,9 +2434,28 @@ export function compose(
|
|
|
2277
2434
|
input: Request,
|
|
2278
2435
|
) => Promise<MethodFn.Response<Transport.Http>>)[]
|
|
2279
2436
|
|
|
2437
|
+
return composeHandlers(handlers, composeOptions)
|
|
2438
|
+
}
|
|
2439
|
+
|
|
2440
|
+
function composeHandlers(
|
|
2441
|
+
handlers: readonly ((input: Request) => Promise<MethodFn.Response<Transport.Http>>)[],
|
|
2442
|
+
composeOptions?: Html.Options,
|
|
2443
|
+
selectOffers?: SelectOffers<readonly Method.AnyServer[]>,
|
|
2444
|
+
): (input: Request) => Promise<MethodFn.Response<Transport.Http>> {
|
|
2280
2445
|
if (handlers.length === 0) throw new Error('compose() requires at least one handler')
|
|
2281
2446
|
|
|
2282
|
-
|
|
2447
|
+
const offerSelector = selectOffers
|
|
2448
|
+
const offerEntries = handlers.map((handler) => {
|
|
2449
|
+
const internal = (handler as ConfiguredHandler)._internal
|
|
2450
|
+
const offer =
|
|
2451
|
+
internal && !isComposedHandlerMetadata(internal) ? createServerOffer(internal) : undefined
|
|
2452
|
+
const method = internal && !isComposedHandlerMetadata(internal) ? internal._method : undefined
|
|
2453
|
+
return { handler, method, offer }
|
|
2454
|
+
})
|
|
2455
|
+
const hasOfferPolicy =
|
|
2456
|
+
offerSelector !== undefined || offerEntries.some(({ method }) => method?.canOffer !== undefined)
|
|
2457
|
+
|
|
2458
|
+
const composed: ComposedHandler = async (input: Request) => {
|
|
2283
2459
|
// Serve service worker for html-enabled compose
|
|
2284
2460
|
if (new URL(input.url).searchParams.has(Html.params.serviceWorker)) {
|
|
2285
2461
|
const hasHtml = handlers.some((h) => (h as ConfiguredHandler)._internal?.html)
|
|
@@ -2314,45 +2490,53 @@ export function compose(
|
|
|
2314
2490
|
const credReq = credential.challenge.request as Record<string, unknown>
|
|
2315
2491
|
|
|
2316
2492
|
// Filter by name+intent, then narrow by comparing stable request fields
|
|
2317
|
-
// from the echoed challenge against each handler's
|
|
2493
|
+
// from the echoed challenge against each handler's configured offers.
|
|
2318
2494
|
// Uses the schema-parsed canonical form (not raw options) so that
|
|
2319
2495
|
// transformed fields (e.g. amount with decimals) match correctly.
|
|
2320
2496
|
// Also checks inside methodDetails for fields moved there by transforms.
|
|
2321
|
-
const candidates = handlers.filter((
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2497
|
+
const candidates = handlers.filter((handler) =>
|
|
2498
|
+
getConfiguredOffers(handler).some((internal) => {
|
|
2499
|
+
try {
|
|
2500
|
+
if (internal.name !== credMethod || internal.intent !== credIntent) return false
|
|
2501
|
+
const mismatch = internal._stableBinding
|
|
2502
|
+
? getRequestBindingMismatch(
|
|
2503
|
+
getStableBinding(internal._canonicalRequest, internal._stableBinding),
|
|
2504
|
+
getStableBinding(credReq, internal._stableBinding),
|
|
2505
|
+
)
|
|
2506
|
+
: getPinnedRequestBindingMismatch(internal._canonicalRequest, credReq)
|
|
2507
|
+
return !mismatch && opaqueValuesMatch(internal.meta, credential.challenge.meta)
|
|
2508
|
+
} catch {
|
|
2325
2509
|
return false
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
getStableBinding(credReq, internal._stableBinding),
|
|
2330
|
-
)
|
|
2331
|
-
: getPinnedRequestBindingMismatch(internal._canonicalRequest, credReq)
|
|
2332
|
-
return !mismatch && opaqueValuesMatch(internal.meta, credential.challenge.meta)
|
|
2333
|
-
} catch {
|
|
2334
|
-
return false
|
|
2335
|
-
}
|
|
2336
|
-
})
|
|
2510
|
+
}
|
|
2511
|
+
}),
|
|
2512
|
+
)
|
|
2337
2513
|
|
|
2338
2514
|
const match =
|
|
2339
2515
|
candidates[0] ??
|
|
2340
|
-
handlers.find((
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2516
|
+
handlers.find((handler) =>
|
|
2517
|
+
getConfiguredOffers(handler).some(
|
|
2518
|
+
(internal) => internal.name === credMethod && internal.intent === credIntent,
|
|
2519
|
+
),
|
|
2520
|
+
)
|
|
2344
2521
|
if (match) return match(input)
|
|
2345
2522
|
}
|
|
2346
2523
|
|
|
2347
|
-
//
|
|
2348
|
-
//
|
|
2349
|
-
return handlers[0]!(input)
|
|
2524
|
+
// Unrecognized or malformed credentials still use the currently eligible
|
|
2525
|
+
// offer set before the first handler issues its rejection challenge.
|
|
2350
2526
|
}
|
|
2351
2527
|
|
|
2528
|
+
const selectedHandlers = hasOfferPolicy
|
|
2529
|
+
? await selectOfferHandlers({
|
|
2530
|
+
entries: offerEntries,
|
|
2531
|
+
input,
|
|
2532
|
+
selectOffers: offerSelector,
|
|
2533
|
+
})
|
|
2534
|
+
: handlers
|
|
2535
|
+
|
|
2352
2536
|
// No credential — evaluate handlers sequentially so authorize()/renewal hooks
|
|
2353
2537
|
// can safely claim the request without racing each other.
|
|
2354
2538
|
const results: MethodFn.Response<Transport.Http>[] = []
|
|
2355
|
-
for (const handler of
|
|
2539
|
+
for (const handler of selectedHandlers) {
|
|
2356
2540
|
const result = await handler(input)
|
|
2357
2541
|
if (result.status === 200) return result
|
|
2358
2542
|
results.push(result)
|
|
@@ -2365,7 +2549,7 @@ export function compose(
|
|
|
2365
2549
|
result: Extract<MethodFn.Response<Transport.Http>, { status: 402 }>
|
|
2366
2550
|
}[] = []
|
|
2367
2551
|
|
|
2368
|
-
for (let i = 0; i <
|
|
2552
|
+
for (let i = 0; i < selectedHandlers.length; i++) {
|
|
2369
2553
|
const result = results[i]
|
|
2370
2554
|
if (result?.status !== 402) continue
|
|
2371
2555
|
|
|
@@ -2374,7 +2558,7 @@ export function compose(
|
|
|
2374
2558
|
if (!wwwAuth) continue
|
|
2375
2559
|
|
|
2376
2560
|
entries.push({
|
|
2377
|
-
handler:
|
|
2561
|
+
handler: selectedHandlers[i] as ConfiguredHandler,
|
|
2378
2562
|
challenge: Challenge.deserialize(wwwAuth),
|
|
2379
2563
|
result,
|
|
2380
2564
|
})
|
|
@@ -2501,6 +2685,118 @@ export function compose(
|
|
|
2501
2685
|
challenge: new Response(body, { status: 402, headers: mergedHeaders }),
|
|
2502
2686
|
}
|
|
2503
2687
|
}
|
|
2688
|
+
|
|
2689
|
+
const offers = handlers.flatMap(getConfiguredOffers)
|
|
2690
|
+
if (offers.length > 0) composed._internal = { offers }
|
|
2691
|
+
return composed
|
|
2692
|
+
}
|
|
2693
|
+
|
|
2694
|
+
/** Returns the flattened configured offers accepted by a handler. */
|
|
2695
|
+
function getConfiguredOffers(
|
|
2696
|
+
handler: ConfiguredHandler | ComposedHandler,
|
|
2697
|
+
): readonly ConfiguredHandler['_internal'][] {
|
|
2698
|
+
const internal = handler._internal
|
|
2699
|
+
if (!internal) return []
|
|
2700
|
+
if (isComposedHandlerMetadata(internal)) return internal.offers
|
|
2701
|
+
return [internal]
|
|
2702
|
+
}
|
|
2703
|
+
|
|
2704
|
+
function isComposedHandlerMetadata(
|
|
2705
|
+
internal: HandlerDiscoveryMetadata,
|
|
2706
|
+
): internal is NonNullable<ComposedHandler['_internal']> {
|
|
2707
|
+
return 'offers' in internal && !('_canonicalRequest' in internal)
|
|
2708
|
+
}
|
|
2709
|
+
|
|
2710
|
+
function createServerOffer(internal: ConfiguredHandler['_internal']): ServerOffer {
|
|
2711
|
+
return Object.freeze({
|
|
2712
|
+
key: `${internal.name}/${internal.intent}`,
|
|
2713
|
+
method: Object.freeze({
|
|
2714
|
+
...(internal._method.alias ? { alias: internal._method.alias } : {}),
|
|
2715
|
+
intent: internal.intent,
|
|
2716
|
+
name: internal.name,
|
|
2717
|
+
}),
|
|
2718
|
+
request: immutableSnapshot(internal._canonicalRequest),
|
|
2719
|
+
}) as ServerOffer
|
|
2720
|
+
}
|
|
2721
|
+
|
|
2722
|
+
/** Applies and validates the server-level offer selection policy. */
|
|
2723
|
+
async function selectOfferHandlers(parameters: {
|
|
2724
|
+
entries: readonly {
|
|
2725
|
+
handler: (input: Request) => Promise<MethodFn.Response<Transport.Http>>
|
|
2726
|
+
method: Method.AnyServer | undefined
|
|
2727
|
+
offer: ServerOffer | undefined
|
|
2728
|
+
}[]
|
|
2729
|
+
input: Request
|
|
2730
|
+
selectOffers: SelectOffers<readonly Method.AnyServer[]> | undefined
|
|
2731
|
+
}) {
|
|
2732
|
+
const { entries, input, selectOffers } = parameters
|
|
2733
|
+
const eligibleEntries: (typeof entries)[number][] = []
|
|
2734
|
+
for (const entry of entries) {
|
|
2735
|
+
const canOffer = entry.method?.canOffer
|
|
2736
|
+
if (canOffer) {
|
|
2737
|
+
const approved = await canOffer({
|
|
2738
|
+
input: cloneOfferInput(input),
|
|
2739
|
+
request: entry.offer!.request,
|
|
2740
|
+
})
|
|
2741
|
+
if (typeof approved !== 'boolean') throw new Error('canOffer() must return a boolean')
|
|
2742
|
+
if (!approved) continue
|
|
2743
|
+
}
|
|
2744
|
+
eligibleEntries.push(entry)
|
|
2745
|
+
}
|
|
2746
|
+
|
|
2747
|
+
if (eligibleEntries.length === 0)
|
|
2748
|
+
throw new Error('No payment offers are available for this request')
|
|
2749
|
+
if (!selectOffers) return eligibleEntries.map(({ handler }) => handler)
|
|
2750
|
+
|
|
2751
|
+
const offers = eligibleEntries.map(({ offer }) => {
|
|
2752
|
+
if (!offer) throw new Error('selectOffers() can only select configured payment offers')
|
|
2753
|
+
return offer
|
|
2754
|
+
})
|
|
2755
|
+
const selected = await selectOffers(
|
|
2756
|
+
Object.freeze(offers),
|
|
2757
|
+
Object.freeze({ request: cloneOfferInput(input) }),
|
|
2758
|
+
)
|
|
2759
|
+
|
|
2760
|
+
if (!Array.isArray(selected)) throw new Error('selectOffers() must return an array of offers')
|
|
2761
|
+
if (selected.length === 0) throw new Error('selectOffers() must select at least one offer')
|
|
2762
|
+
|
|
2763
|
+
let previousIndex = -1
|
|
2764
|
+
const selectedHandlers = selected.map((offer) => {
|
|
2765
|
+
const index = offers.indexOf(offer)
|
|
2766
|
+
if (index === -1) throw new Error('selectOffers() must return only offers from its input array')
|
|
2767
|
+
if (index <= previousIndex)
|
|
2768
|
+
throw new Error('selectOffers() must preserve offer order and must not return duplicates')
|
|
2769
|
+
previousIndex = index
|
|
2770
|
+
return eligibleEntries[index]!.handler
|
|
2771
|
+
})
|
|
2772
|
+
|
|
2773
|
+
return selectedHandlers
|
|
2774
|
+
}
|
|
2775
|
+
|
|
2776
|
+
/** Clones a request for offer hooks, falling back to a bodyless metadata copy. */
|
|
2777
|
+
function cloneOfferInput(input: Request): Request {
|
|
2778
|
+
try {
|
|
2779
|
+
return input.clone()
|
|
2780
|
+
} catch {
|
|
2781
|
+
return new globalThis.Request(input.url, {
|
|
2782
|
+
headers: new Headers(input.headers),
|
|
2783
|
+
method: input.method,
|
|
2784
|
+
signal: input.signal,
|
|
2785
|
+
})
|
|
2786
|
+
}
|
|
2787
|
+
}
|
|
2788
|
+
|
|
2789
|
+
/** Clones and recursively freezes protocol data exposed to offer hooks. */
|
|
2790
|
+
function immutableSnapshot<value>(value: value): DeepReadonly<value> {
|
|
2791
|
+
return deepFreeze(structuredClone(value))
|
|
2792
|
+
}
|
|
2793
|
+
|
|
2794
|
+
function deepFreeze<value>(value: value): DeepReadonly<value> {
|
|
2795
|
+
if (!value || typeof value !== 'object' || Object.isFrozen(value))
|
|
2796
|
+
return value as DeepReadonly<value>
|
|
2797
|
+
|
|
2798
|
+
for (const nested of Object.values(value)) deepFreeze(nested)
|
|
2799
|
+
return Object.freeze(value) as DeepReadonly<value>
|
|
2504
2800
|
}
|
|
2505
2801
|
|
|
2506
2802
|
type ChallengeHeaderMerge = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Mppx, stripe } from 'mppx/server'
|
|
2
|
-
import { test } from 'vp/test'
|
|
2
|
+
import { expectTypeOf, test } from 'vp/test'
|
|
3
3
|
|
|
4
4
|
import type { StripeClient } from '../internal/types.js'
|
|
5
5
|
import type { charge as StripeCharge } from './Charge.js'
|
|
@@ -7,6 +7,21 @@ import type { charge as StripeCharge } from './Charge.js'
|
|
|
7
7
|
const client = {} as StripeClient
|
|
8
8
|
const secretKey = 'test-secret-key-test-secret-key-32'
|
|
9
9
|
|
|
10
|
+
test('accepts a typed constructor canOffer policy', () => {
|
|
11
|
+
stripe.charge({
|
|
12
|
+
client,
|
|
13
|
+
canOffer({ input, request }) {
|
|
14
|
+
expectTypeOf(input).toEqualTypeOf<Request>()
|
|
15
|
+
expectTypeOf(request.amount).toEqualTypeOf<string>()
|
|
16
|
+
expectTypeOf(request.currency).toEqualTypeOf<string>()
|
|
17
|
+
expectTypeOf(request.methodDetails.networkId).toEqualTypeOf<string>()
|
|
18
|
+
return request.amount !== '0'
|
|
19
|
+
},
|
|
20
|
+
networkId: 'internal',
|
|
21
|
+
paymentMethodTypes: ['card'],
|
|
22
|
+
})
|
|
23
|
+
})
|
|
24
|
+
|
|
10
25
|
test('requires request fields not configured as Stripe defaults', () => {
|
|
11
26
|
const server = Mppx.create({
|
|
12
27
|
methods: [
|