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
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import { describe, expect, test, vi } from 'vp/test'
|
|
2
|
+
|
|
3
|
+
import * as Mppx from '../server/Mppx.js'
|
|
4
|
+
import * as Proxy from './Proxy.js'
|
|
5
|
+
import * as Service from './Service.js'
|
|
6
|
+
|
|
7
|
+
type CreatePaidProxyParameters = {
|
|
8
|
+
fetch: typeof globalThis.fetch
|
|
9
|
+
method?: 'GET' | 'POST' | undefined
|
|
10
|
+
onPayment?: (() => void) | undefined
|
|
11
|
+
onProxyError?: Service.UpstreamErrorHandler | undefined
|
|
12
|
+
onServiceError?: Service.UpstreamErrorHandler | undefined
|
|
13
|
+
rewriteRequest?: Service.Service['rewriteRequest']
|
|
14
|
+
rewriteResponse?: Service.Service['rewriteResponse']
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function createPaidProxy(parameters: CreatePaidProxyParameters): Proxy.Proxy {
|
|
18
|
+
const method = parameters.method ?? 'GET'
|
|
19
|
+
const service = Service.from('api', {
|
|
20
|
+
baseUrl: 'https://upstream.example',
|
|
21
|
+
onUpstreamError: parameters.onServiceError,
|
|
22
|
+
rewriteRequest: parameters.rewriteRequest,
|
|
23
|
+
routes: {
|
|
24
|
+
[`${method} /resource`]: createPaidHandler(parameters.onPayment),
|
|
25
|
+
},
|
|
26
|
+
})
|
|
27
|
+
service.rewriteResponse = parameters.rewriteResponse
|
|
28
|
+
return Proxy.create({
|
|
29
|
+
fetch: parameters.fetch,
|
|
30
|
+
onUpstreamError: parameters.onProxyError,
|
|
31
|
+
services: [service],
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function createPaidHandler(onPayment?: () => void): Service.IntentHandler {
|
|
36
|
+
return async () => {
|
|
37
|
+
onPayment?.()
|
|
38
|
+
return {
|
|
39
|
+
status: 200,
|
|
40
|
+
withReceipt<response>(response: response): response {
|
|
41
|
+
if (!(response instanceof Response)) throw new Mppx.MissingReceiptResponseError()
|
|
42
|
+
const headers = new Headers(response.headers)
|
|
43
|
+
headers.set('Payment-Receipt', 'test-receipt')
|
|
44
|
+
return new Response(response.body, {
|
|
45
|
+
headers,
|
|
46
|
+
status: response.status,
|
|
47
|
+
statusText: response.statusText,
|
|
48
|
+
}) as response
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function paidRequest(init?: RequestInit): Request {
|
|
55
|
+
const headers = new Headers(init?.headers)
|
|
56
|
+
headers.set('Authorization', 'Payment test-credential')
|
|
57
|
+
return new Request('https://proxy.example/api/resource', {
|
|
58
|
+
...init,
|
|
59
|
+
headers,
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
describe('onUpstreamError', () => {
|
|
64
|
+
test('retries upstream without verifying payment again', async () => {
|
|
65
|
+
const onPayment = vi.fn()
|
|
66
|
+
const onUpstreamError = vi.fn((context: Service.UpstreamErrorContext) => ({
|
|
67
|
+
retry: context.attempt < 3,
|
|
68
|
+
})) as Service.UpstreamErrorHandler
|
|
69
|
+
let attempts = 0
|
|
70
|
+
const fetch = vi.fn(async () => {
|
|
71
|
+
attempts++
|
|
72
|
+
if (attempts < 3) return new Response('unavailable', { status: 503 })
|
|
73
|
+
return Response.json({ ok: true })
|
|
74
|
+
}) as typeof globalThis.fetch
|
|
75
|
+
const proxy = createPaidProxy({ fetch, onPayment, onServiceError: onUpstreamError })
|
|
76
|
+
|
|
77
|
+
const response = await proxy.fetch(paidRequest())
|
|
78
|
+
|
|
79
|
+
expect(response.status).toBe(200)
|
|
80
|
+
expect(response.headers.get('Payment-Receipt')).toBe('test-receipt')
|
|
81
|
+
expect(await response.json()).toEqual({ ok: true })
|
|
82
|
+
expect(fetch).toHaveBeenCalledTimes(3)
|
|
83
|
+
expect(onPayment).toHaveBeenCalledTimes(1)
|
|
84
|
+
expect(onUpstreamError).toHaveBeenCalledTimes(2)
|
|
85
|
+
expect(onUpstreamError).toHaveBeenCalledWith(
|
|
86
|
+
expect.objectContaining({
|
|
87
|
+
attempt: 1,
|
|
88
|
+
error: undefined,
|
|
89
|
+
response: expect.objectContaining({ status: 503 }),
|
|
90
|
+
service: expect.objectContaining({ id: 'api' }),
|
|
91
|
+
upstreamPath: '/resource',
|
|
92
|
+
upstreamRequest: expect.objectContaining({ url: 'https://upstream.example/resource' }),
|
|
93
|
+
}),
|
|
94
|
+
)
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
test('uses the proxy handler when the service has no override', async () => {
|
|
98
|
+
const upstreamError = new Error('connection reset')
|
|
99
|
+
const onProxyError = vi.fn((context: Service.UpstreamErrorContext) => ({
|
|
100
|
+
retry: context.attempt < 2,
|
|
101
|
+
})) as Service.UpstreamErrorHandler
|
|
102
|
+
let attempts = 0
|
|
103
|
+
const fetch = vi.fn(async () => {
|
|
104
|
+
attempts++
|
|
105
|
+
if (attempts === 1) throw upstreamError
|
|
106
|
+
return new Response('recovered')
|
|
107
|
+
}) as typeof globalThis.fetch
|
|
108
|
+
const proxy = createPaidProxy({ fetch, onProxyError })
|
|
109
|
+
|
|
110
|
+
const response = await proxy.fetch(paidRequest())
|
|
111
|
+
|
|
112
|
+
expect(response.status).toBe(200)
|
|
113
|
+
expect(await response.text()).toBe('recovered')
|
|
114
|
+
expect(response.headers.get('Payment-Receipt')).toBe('test-receipt')
|
|
115
|
+
expect(onProxyError).toHaveBeenCalledWith(
|
|
116
|
+
expect.objectContaining({
|
|
117
|
+
attempt: 1,
|
|
118
|
+
error: upstreamError,
|
|
119
|
+
response: undefined,
|
|
120
|
+
}),
|
|
121
|
+
)
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
test('prefers the service handler over the proxy default', async () => {
|
|
125
|
+
const onProxyError = vi.fn(() => ({ retry: true as const }))
|
|
126
|
+
const onServiceError = vi.fn(() => ({ retry: false as const }))
|
|
127
|
+
const fetch = vi.fn(
|
|
128
|
+
async () => new Response('rate limited', { status: 429 }),
|
|
129
|
+
) as typeof globalThis.fetch
|
|
130
|
+
const proxy = createPaidProxy({ fetch, onProxyError, onServiceError })
|
|
131
|
+
|
|
132
|
+
const response = await proxy.fetch(paidRequest())
|
|
133
|
+
|
|
134
|
+
expect(response.status).toBe(429)
|
|
135
|
+
expect(response.headers.get('Payment-Receipt')).toBe('test-receipt')
|
|
136
|
+
expect(fetch).toHaveBeenCalledTimes(1)
|
|
137
|
+
expect(onServiceError).toHaveBeenCalledTimes(1)
|
|
138
|
+
expect(onProxyError).not.toHaveBeenCalled()
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
test('returns a handler fallback and attaches a receipt when it succeeds', async () => {
|
|
142
|
+
const onServiceError = vi.fn(() => ({
|
|
143
|
+
response: Response.json({ cached: true }),
|
|
144
|
+
retry: false as const,
|
|
145
|
+
}))
|
|
146
|
+
const fetch = vi.fn(
|
|
147
|
+
async () => new Response('unavailable', { status: 503 }),
|
|
148
|
+
) as typeof globalThis.fetch
|
|
149
|
+
const proxy = createPaidProxy({ fetch, onServiceError })
|
|
150
|
+
|
|
151
|
+
const response = await proxy.fetch(paidRequest())
|
|
152
|
+
|
|
153
|
+
expect(response.status).toBe(200)
|
|
154
|
+
expect(response.headers.get('Payment-Receipt')).toBe('test-receipt')
|
|
155
|
+
expect(await response.json()).toEqual({ cached: true })
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
test('attaches a receipt when an upstream error is returned', async () => {
|
|
159
|
+
const fetch = vi.fn(
|
|
160
|
+
async () => new Response('upstream failed', { status: 500 }),
|
|
161
|
+
) as typeof globalThis.fetch
|
|
162
|
+
const proxy = createPaidProxy({ fetch })
|
|
163
|
+
|
|
164
|
+
const response = await proxy.fetch(paidRequest())
|
|
165
|
+
|
|
166
|
+
expect(response.status).toBe(500)
|
|
167
|
+
expect(response.headers.get('Payment-Receipt')).toBe('test-receipt')
|
|
168
|
+
expect(await response.text()).toBe('upstream failed')
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
test('preserves streaming when error recovery is disabled', async () => {
|
|
172
|
+
const clone = vi.spyOn(Request.prototype, 'clone')
|
|
173
|
+
const fetch = vi.fn(async (input: URL | RequestInfo, init?: RequestInit) => {
|
|
174
|
+
expect(await new Request(input, init).text()).toBe('streamed body')
|
|
175
|
+
return new Response('ok')
|
|
176
|
+
}) as typeof globalThis.fetch
|
|
177
|
+
const proxy = Proxy.create({
|
|
178
|
+
fetch,
|
|
179
|
+
services: [
|
|
180
|
+
Service.from('api', {
|
|
181
|
+
baseUrl: 'https://upstream.example',
|
|
182
|
+
routes: { 'POST /resource': true },
|
|
183
|
+
}),
|
|
184
|
+
],
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
const response = await proxy.fetch(
|
|
189
|
+
new Request('https://proxy.example/api/resource', {
|
|
190
|
+
body: 'streamed body',
|
|
191
|
+
method: 'POST',
|
|
192
|
+
}),
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
expect(response.status).toBe(200)
|
|
196
|
+
expect(clone).not.toHaveBeenCalled()
|
|
197
|
+
} finally {
|
|
198
|
+
clone.mockRestore()
|
|
199
|
+
}
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
test('preserves a failed response body read by the handler', async () => {
|
|
203
|
+
const onServiceError = vi.fn(async ({ response }: Service.UpstreamErrorContext) => {
|
|
204
|
+
expect(await response?.text()).toBe('upstream failed')
|
|
205
|
+
return { retry: false as const }
|
|
206
|
+
})
|
|
207
|
+
const fetch = vi.fn(
|
|
208
|
+
async () => new Response('upstream failed', { status: 503 }),
|
|
209
|
+
) as typeof globalThis.fetch
|
|
210
|
+
const proxy = createPaidProxy({ fetch, onServiceError })
|
|
211
|
+
|
|
212
|
+
const response = await proxy.fetch(paidRequest())
|
|
213
|
+
|
|
214
|
+
expect(response.status).toBe(503)
|
|
215
|
+
expect(await response.text()).toBe('upstream failed')
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
test('preserves a recovery response derived from the failed body', async () => {
|
|
219
|
+
const onServiceError = vi.fn(({ response }: Service.UpstreamErrorContext) => ({
|
|
220
|
+
response: new Response(response?.body, { status: 200 }),
|
|
221
|
+
retry: false as const,
|
|
222
|
+
}))
|
|
223
|
+
const fetch = vi.fn(
|
|
224
|
+
async () => new Response('recovered body', { status: 503 }),
|
|
225
|
+
) as typeof globalThis.fetch
|
|
226
|
+
const proxy = createPaidProxy({ fetch, onServiceError })
|
|
227
|
+
|
|
228
|
+
const response = await proxy.fetch(paidRequest())
|
|
229
|
+
|
|
230
|
+
expect(response.status).toBe(200)
|
|
231
|
+
expect(response.headers.get('Payment-Receipt')).toBe('test-receipt')
|
|
232
|
+
expect(await response.text()).toBe('recovered body')
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
test('does not block a retry when the handler partially reads the failed body', async () => {
|
|
236
|
+
const onServiceError = vi.fn(async ({ response }: Service.UpstreamErrorContext) => {
|
|
237
|
+
await response?.body?.getReader().read()
|
|
238
|
+
return { retry: true as const }
|
|
239
|
+
})
|
|
240
|
+
let attempts = 0
|
|
241
|
+
const fetch = vi.fn(async () => {
|
|
242
|
+
attempts++
|
|
243
|
+
if (attempts > 1) return new Response('recovered')
|
|
244
|
+
return new Response(
|
|
245
|
+
new ReadableStream({
|
|
246
|
+
start(controller) {
|
|
247
|
+
controller.enqueue(new TextEncoder().encode('partial failure'))
|
|
248
|
+
},
|
|
249
|
+
}),
|
|
250
|
+
{ status: 503 },
|
|
251
|
+
)
|
|
252
|
+
}) as typeof globalThis.fetch
|
|
253
|
+
const proxy = createPaidProxy({ fetch, onServiceError })
|
|
254
|
+
|
|
255
|
+
const response = await proxy.fetch(paidRequest())
|
|
256
|
+
|
|
257
|
+
expect(response.status).toBe(200)
|
|
258
|
+
expect(await response.text()).toBe('recovered')
|
|
259
|
+
expect(fetch).toHaveBeenCalledTimes(2)
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
test('does not retry response rewrite failures', async () => {
|
|
263
|
+
const rewriteError = new Error('invalid upstream response')
|
|
264
|
+
const onServiceError = vi.fn(() => ({ retry: true as const }))
|
|
265
|
+
const rewriteResponse = vi.fn(() => {
|
|
266
|
+
throw rewriteError
|
|
267
|
+
})
|
|
268
|
+
const fetch = vi.fn(async () => new Response('created')) as typeof globalThis.fetch
|
|
269
|
+
const proxy = createPaidProxy({
|
|
270
|
+
fetch,
|
|
271
|
+
method: 'POST',
|
|
272
|
+
onServiceError,
|
|
273
|
+
rewriteResponse,
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
await expect(
|
|
277
|
+
proxy.fetch(paidRequest({ body: 'create resource', method: 'POST' })),
|
|
278
|
+
).rejects.toBe(rewriteError)
|
|
279
|
+
expect(fetch).toHaveBeenCalledTimes(1)
|
|
280
|
+
expect(onServiceError).not.toHaveBeenCalled()
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
test('preserves a POST body across delayed retries', async () => {
|
|
284
|
+
const bodies: string[] = []
|
|
285
|
+
const rewriteRequest = vi.fn((request: Request) => request)
|
|
286
|
+
const onServiceError = vi.fn(() => ({ delay: 1, retry: true as const }))
|
|
287
|
+
const fetch = vi.fn(async (input: URL | RequestInfo, init?: RequestInit) => {
|
|
288
|
+
const request = new Request(input, init)
|
|
289
|
+
bodies.push(await request.text())
|
|
290
|
+
if (bodies.length === 1) return new Response('rate limited', { status: 429 })
|
|
291
|
+
return Response.json({ ok: true })
|
|
292
|
+
}) as typeof globalThis.fetch
|
|
293
|
+
const proxy = createPaidProxy({
|
|
294
|
+
fetch,
|
|
295
|
+
method: 'POST',
|
|
296
|
+
onServiceError,
|
|
297
|
+
rewriteRequest,
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
const response = await proxy.fetch(
|
|
301
|
+
paidRequest({
|
|
302
|
+
body: JSON.stringify({ prompt: 'hello' }),
|
|
303
|
+
headers: { 'Content-Type': 'application/json' },
|
|
304
|
+
method: 'POST',
|
|
305
|
+
}),
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
expect(response.status).toBe(200)
|
|
309
|
+
expect(bodies).toEqual(['{"prompt":"hello"}', '{"prompt":"hello"}'])
|
|
310
|
+
expect(rewriteRequest).toHaveBeenCalledTimes(2)
|
|
311
|
+
expect(onServiceError).toHaveBeenCalledTimes(1)
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
test('stops a delayed retry when the client aborts', async () => {
|
|
315
|
+
const controller = new AbortController()
|
|
316
|
+
let handlerCalled: (() => void) | undefined
|
|
317
|
+
const called = new Promise<void>((resolve) => {
|
|
318
|
+
handlerCalled = resolve
|
|
319
|
+
})
|
|
320
|
+
const onServiceError: Service.UpstreamErrorHandler = () => {
|
|
321
|
+
handlerCalled?.()
|
|
322
|
+
return { delay: 60_000, retry: true }
|
|
323
|
+
}
|
|
324
|
+
const fetch = vi.fn(
|
|
325
|
+
async () => new Response('unavailable', { status: 503 }),
|
|
326
|
+
) as typeof globalThis.fetch
|
|
327
|
+
const proxy = createPaidProxy({ fetch, onServiceError })
|
|
328
|
+
const response = proxy.fetch(paidRequest({ signal: controller.signal }))
|
|
329
|
+
const assertion = expect(response).rejects.toThrow('stop retrying')
|
|
330
|
+
|
|
331
|
+
await called
|
|
332
|
+
controller.abort(new Error('stop retrying'))
|
|
333
|
+
|
|
334
|
+
await assertion
|
|
335
|
+
expect(fetch).toHaveBeenCalledTimes(1)
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
test('also recovers free upstream routes without adding a receipt', async () => {
|
|
339
|
+
const onUpstreamError = vi.fn(() => ({ retry: true as const }))
|
|
340
|
+
let attempts = 0
|
|
341
|
+
const fetch = vi.fn(async () => {
|
|
342
|
+
attempts++
|
|
343
|
+
if (attempts === 1) return new Response('unavailable', { status: 503 })
|
|
344
|
+
return new Response('public resource')
|
|
345
|
+
}) as typeof globalThis.fetch
|
|
346
|
+
const proxy = Proxy.create({
|
|
347
|
+
fetch,
|
|
348
|
+
services: [
|
|
349
|
+
Service.from('api', {
|
|
350
|
+
baseUrl: 'https://upstream.example',
|
|
351
|
+
onUpstreamError,
|
|
352
|
+
routes: { 'GET /resource': true },
|
|
353
|
+
}),
|
|
354
|
+
],
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
const response = await proxy.fetch(new Request('https://proxy.example/api/resource'))
|
|
358
|
+
|
|
359
|
+
expect(response.status).toBe(200)
|
|
360
|
+
expect(await response.text()).toBe('public resource')
|
|
361
|
+
expect(response.headers.get('Payment-Receipt')).toBeNull()
|
|
362
|
+
expect(fetch).toHaveBeenCalledTimes(2)
|
|
363
|
+
})
|
|
364
|
+
})
|
|
@@ -12,6 +12,17 @@ describe('from', () => {
|
|
|
12
12
|
expect(service.baseUrl).toBe('https://api.example.com')
|
|
13
13
|
})
|
|
14
14
|
|
|
15
|
+
test('behavior: preserves upstream error hook', () => {
|
|
16
|
+
const onUpstreamError: Service.UpstreamErrorHandler = () => ({ retry: false })
|
|
17
|
+
const service = Service.from('api', {
|
|
18
|
+
baseUrl: 'https://api.example.com',
|
|
19
|
+
onUpstreamError,
|
|
20
|
+
routes: { 'GET /v1/status': true },
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
expect(service.onUpstreamError).toBe(onUpstreamError)
|
|
24
|
+
})
|
|
25
|
+
|
|
15
26
|
test('behavior: bearer sets Authorization header', async () => {
|
|
16
27
|
const service = Service.from('api', {
|
|
17
28
|
baseUrl: 'https://api.example.com',
|
|
@@ -123,7 +134,7 @@ describe('paymentOf', () => {
|
|
|
123
134
|
expect(Service.paymentOf({ pay: handler, options: {} })).toBeNull()
|
|
124
135
|
})
|
|
125
136
|
|
|
126
|
-
test('behavior:
|
|
137
|
+
test('behavior: derives payment metadata from the canonical request', () => {
|
|
127
138
|
const handler = Object.assign(
|
|
128
139
|
async () => ({
|
|
129
140
|
status: 200 as const,
|
|
@@ -131,11 +142,18 @@ describe('paymentOf', () => {
|
|
|
131
142
|
}),
|
|
132
143
|
{
|
|
133
144
|
_internal: {
|
|
134
|
-
_canonicalRequest:
|
|
145
|
+
_canonicalRequest: {
|
|
146
|
+
amount: '1000000',
|
|
147
|
+
currency: '0xUSDC',
|
|
148
|
+
recipient: '0x1',
|
|
149
|
+
},
|
|
135
150
|
_stableBinding: () => ({}),
|
|
136
151
|
amount: '1',
|
|
152
|
+
asset: 'raw-asset',
|
|
137
153
|
authorize: () => undefined,
|
|
154
|
+
client: { apiKey: 'secret' },
|
|
138
155
|
decimals: 6,
|
|
156
|
+
description: 'Generate text',
|
|
139
157
|
defaults: {},
|
|
140
158
|
intent: 'charge',
|
|
141
159
|
name: 'mock',
|
|
@@ -151,9 +169,61 @@ describe('paymentOf', () => {
|
|
|
151
169
|
|
|
152
170
|
expect(Service.paymentOf(handler as never)).toEqual({
|
|
153
171
|
amount: '1000000',
|
|
154
|
-
|
|
172
|
+
currency: '0xUSDC',
|
|
173
|
+
description: 'Generate text',
|
|
155
174
|
intent: 'charge',
|
|
156
175
|
method: 'mock',
|
|
176
|
+
recipient: '0x1',
|
|
177
|
+
})
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
test('behavior: derives every explicitly composed payment offer', () => {
|
|
181
|
+
const handler = Object.assign(
|
|
182
|
+
async () => ({
|
|
183
|
+
status: 200 as const,
|
|
184
|
+
withReceipt: <T>(r: T) => r,
|
|
185
|
+
}),
|
|
186
|
+
{
|
|
187
|
+
_internal: {
|
|
188
|
+
offers: [
|
|
189
|
+
{
|
|
190
|
+
_canonicalRequest: { amount: '1000000', currency: '0xUSDC' },
|
|
191
|
+
amount: '1',
|
|
192
|
+
decimals: 6,
|
|
193
|
+
description: 'USDC',
|
|
194
|
+
intent: 'charge',
|
|
195
|
+
name: 'tempo',
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
_canonicalRequest: { amount: '2000000', currency: '0xNANOUSD' },
|
|
199
|
+
amount: '2',
|
|
200
|
+
decimals: 6,
|
|
201
|
+
description: 'NANOUSD',
|
|
202
|
+
intent: 'charge',
|
|
203
|
+
name: 'tempo',
|
|
204
|
+
},
|
|
205
|
+
],
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
expect(Service.paymentOf(handler as never)).toEqual({
|
|
211
|
+
offers: [
|
|
212
|
+
{
|
|
213
|
+
amount: '1000000',
|
|
214
|
+
currency: '0xUSDC',
|
|
215
|
+
description: 'USDC',
|
|
216
|
+
intent: 'charge',
|
|
217
|
+
method: 'tempo',
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
amount: '2000000',
|
|
221
|
+
currency: '0xNANOUSD',
|
|
222
|
+
description: 'NANOUSD',
|
|
223
|
+
intent: 'charge',
|
|
224
|
+
method: 'tempo',
|
|
225
|
+
},
|
|
226
|
+
],
|
|
157
227
|
})
|
|
158
228
|
})
|
|
159
229
|
})
|
package/src/proxy/Service.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as Metadata from '../discovery/internal/Metadata.js'
|
|
2
2
|
|
|
3
3
|
/** A proxied upstream service with route definitions and optional request/response hooks. */
|
|
4
4
|
export type Service = {
|
|
@@ -12,6 +12,8 @@ export type Service = {
|
|
|
12
12
|
docs?: Docs | undefined
|
|
13
13
|
/** Unique identifier used as the URL prefix (e.g. `'openai'` → `/{id}/...`). */
|
|
14
14
|
id: string
|
|
15
|
+
/** Handles failed upstream attempts before the proxy returns a response. Retries do not re-verify payment. */
|
|
16
|
+
onUpstreamError?: UpstreamErrorHandler | undefined
|
|
15
17
|
/** Hook to modify the upstream request before sending (e.g. inject auth headers). */
|
|
16
18
|
rewriteRequest?: ((req: Request, ctx: Context) => Request | Promise<Request>) | undefined
|
|
17
19
|
/** Hook to modify the upstream response before returning to the client. */
|
|
@@ -61,13 +63,50 @@ export type Context = {
|
|
|
61
63
|
upstreamPath: string
|
|
62
64
|
} & EndpointOptions
|
|
63
65
|
|
|
66
|
+
/** Context passed to an upstream error handler after a failed proxy attempt. */
|
|
67
|
+
export type UpstreamErrorContext = Context & {
|
|
68
|
+
/** One-based upstream attempt number. */
|
|
69
|
+
attempt: number
|
|
70
|
+
/** Error thrown while preparing or sending the request. Undefined for HTTP error responses. */
|
|
71
|
+
error: unknown | undefined
|
|
72
|
+
/** Non-2xx upstream response. Undefined when the attempt threw. */
|
|
73
|
+
response: Response | undefined
|
|
74
|
+
/** Rewritten request sent to the upstream service. */
|
|
75
|
+
upstreamRequest: Request
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Action returned by an upstream error handler. */
|
|
79
|
+
export type UpstreamErrorAction =
|
|
80
|
+
| {
|
|
81
|
+
/** Wait this many milliseconds before retrying. */
|
|
82
|
+
delay?: number | undefined
|
|
83
|
+
retry: true
|
|
84
|
+
}
|
|
85
|
+
| {
|
|
86
|
+
/** Optional response to return instead of the original failure. */
|
|
87
|
+
response?: Response | undefined
|
|
88
|
+
retry: false
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Handles a non-2xx upstream response or thrown request error.
|
|
93
|
+
*
|
|
94
|
+
* This hook runs before the response is returned. It cannot observe failures
|
|
95
|
+
* from a streaming body after response headers have been sent.
|
|
96
|
+
*/
|
|
97
|
+
export type UpstreamErrorHandler<options = unknown> = (
|
|
98
|
+
context: UpstreamErrorContext & Partial<Omit<options & {}, 'onUpstreamError' | 'routes'>>,
|
|
99
|
+
) => UpstreamErrorAction | Promise<UpstreamErrorAction>
|
|
100
|
+
|
|
64
101
|
export type From<
|
|
65
102
|
options extends {
|
|
66
103
|
routes: string
|
|
67
104
|
},
|
|
68
105
|
> = {
|
|
69
106
|
routes: EndpointMap<options['routes']>
|
|
70
|
-
} & Omit<options, 'routes'>
|
|
107
|
+
} & Omit<options, 'onUpstreamError' | 'routes'> & {
|
|
108
|
+
onUpstreamError?: UpstreamErrorHandler<options> | undefined
|
|
109
|
+
}
|
|
71
110
|
|
|
72
111
|
/**
|
|
73
112
|
* Creates a service definition.
|
|
@@ -92,6 +131,7 @@ export function from<options = unknown>(id: string, config: from.Config<options>
|
|
|
92
131
|
description: config.description,
|
|
93
132
|
docs: resolveDocs(config),
|
|
94
133
|
id,
|
|
134
|
+
onUpstreamError: config.onUpstreamError as Service['onUpstreamError'],
|
|
95
135
|
routes: config.routes,
|
|
96
136
|
title: config.title,
|
|
97
137
|
rewriteRequest: config.rewriteRequest
|
|
@@ -126,6 +166,8 @@ export declare namespace from {
|
|
|
126
166
|
| undefined
|
|
127
167
|
/** Shorthand: full request mutation function. Takes priority over `bearer`/`headers`. */
|
|
128
168
|
mutate?: ((req: Request) => Request | Promise<Request>) | undefined
|
|
169
|
+
/** Handles failed upstream attempts before the proxy returns a response. Retries do not re-verify payment. */
|
|
170
|
+
onUpstreamError?: UpstreamErrorHandler<options> | undefined
|
|
129
171
|
/** Hook to modify the upstream request. Receives typed per-endpoint options via `ctx`. */
|
|
130
172
|
rewriteRequest?:
|
|
131
173
|
| ((req: Request, ctx: Context & Partial<options & {}>) => Request | Promise<Request>)
|
|
@@ -206,31 +248,16 @@ export function getOptions(endpoint: Endpoint): EndpointOptions | undefined {
|
|
|
206
248
|
return undefined
|
|
207
249
|
}
|
|
208
250
|
|
|
251
|
+
/** Derives discovery payment metadata from an explicitly priced endpoint handler. */
|
|
209
252
|
export function paymentOf(endpoint: Endpoint): Record<string, unknown> | null {
|
|
210
253
|
if (endpoint === true) return null
|
|
211
254
|
const handler = typeof endpoint === 'function' ? endpoint : endpoint.pay
|
|
212
255
|
if (!('_internal' in handler)) return null
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
_canonicalRequest,
|
|
219
|
-
_stableBinding: _sb,
|
|
220
|
-
authorize: _a,
|
|
221
|
-
request: _r,
|
|
222
|
-
respond: _re,
|
|
223
|
-
stableBinding: _st,
|
|
224
|
-
transport: _t,
|
|
225
|
-
verify: _v,
|
|
226
|
-
...rest
|
|
227
|
-
} = handler._internal as Record<string, unknown>
|
|
228
|
-
const amount = (() => {
|
|
229
|
-
if (typeof rest.amount === 'string' && typeof rest.decimals === 'number')
|
|
230
|
-
return String(Value.from(rest.amount, rest.decimals))
|
|
231
|
-
return rest.amount
|
|
232
|
-
})()
|
|
233
|
-
return { intent, method: name, ...rest, ...(amount !== undefined && { amount }) }
|
|
256
|
+
const metadata = handler._internal as Metadata.Metadata | undefined
|
|
257
|
+
if (!metadata) return null
|
|
258
|
+
if (Metadata.isComposed(metadata))
|
|
259
|
+
return { offers: Metadata.offers(metadata).map(Metadata.paymentOffer) }
|
|
260
|
+
return Metadata.paymentOffer(metadata)
|
|
234
261
|
}
|
|
235
262
|
|
|
236
263
|
function resolveDocs(config: from.Config): Docs | undefined {
|
|
@@ -26,6 +26,7 @@ export function anthropic(config: anthropic.Config) {
|
|
|
26
26
|
apiReference: 'https://docs.anthropic.com/en/api/getting-started',
|
|
27
27
|
homepage: 'https://docs.anthropic.com/en/docs/intro-to-claude',
|
|
28
28
|
},
|
|
29
|
+
onUpstreamError: config.onUpstreamError,
|
|
29
30
|
rewriteRequest(request, ctx) {
|
|
30
31
|
const apiKey = ctx.apiKey ?? config.apiKey
|
|
31
32
|
request.headers.set('x-api-key', apiKey)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { expectTypeOf, test } from 'vp/test'
|
|
2
|
+
|
|
3
|
+
import { openai } from './openai.js'
|
|
4
|
+
|
|
5
|
+
test('upstream error hooks preserve service-specific context', () => {
|
|
6
|
+
openai({
|
|
7
|
+
apiKey: 'test',
|
|
8
|
+
onUpstreamError(context) {
|
|
9
|
+
expectTypeOf(context.apiKey).toEqualTypeOf<string | undefined>()
|
|
10
|
+
return { retry: false }
|
|
11
|
+
},
|
|
12
|
+
routes: { 'POST /v1/chat/completions': true },
|
|
13
|
+
})
|
|
14
|
+
})
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vp/test'
|
|
2
|
+
|
|
3
|
+
import type * as Service from '../Service.js'
|
|
4
|
+
import { anthropic } from './anthropic.js'
|
|
5
|
+
import { openai } from './openai.js'
|
|
6
|
+
import { stripe } from './stripe.js'
|
|
7
|
+
|
|
8
|
+
describe('service hooks', () => {
|
|
9
|
+
const onUpstreamError: Service.UpstreamErrorHandler = () => ({ retry: false })
|
|
10
|
+
|
|
11
|
+
test.each([
|
|
12
|
+
[
|
|
13
|
+
'openai',
|
|
14
|
+
() =>
|
|
15
|
+
openai({
|
|
16
|
+
apiKey: 'test',
|
|
17
|
+
onUpstreamError,
|
|
18
|
+
routes: { 'POST /v1/chat/completions': true },
|
|
19
|
+
}),
|
|
20
|
+
],
|
|
21
|
+
[
|
|
22
|
+
'anthropic',
|
|
23
|
+
() =>
|
|
24
|
+
anthropic({
|
|
25
|
+
apiKey: 'test',
|
|
26
|
+
onUpstreamError,
|
|
27
|
+
routes: { 'POST /v1/messages': true },
|
|
28
|
+
}),
|
|
29
|
+
],
|
|
30
|
+
[
|
|
31
|
+
'stripe',
|
|
32
|
+
() =>
|
|
33
|
+
stripe({
|
|
34
|
+
apiKey: 'test',
|
|
35
|
+
onUpstreamError,
|
|
36
|
+
routes: { 'POST /v1/charges': true },
|
|
37
|
+
}),
|
|
38
|
+
],
|
|
39
|
+
] as const)('preserves hooks for %s', (_name, createService) => {
|
|
40
|
+
const service = createService()
|
|
41
|
+
|
|
42
|
+
expect(service.onUpstreamError).toBe(onUpstreamError)
|
|
43
|
+
})
|
|
44
|
+
})
|
|
@@ -27,6 +27,7 @@ export function openai(config: openai.Config) {
|
|
|
27
27
|
homepage: 'https://platform.openai.com/docs',
|
|
28
28
|
llms: 'https://context7.com/websites/platform_openai/llms.txt',
|
|
29
29
|
},
|
|
30
|
+
onUpstreamError: config.onUpstreamError,
|
|
30
31
|
rewriteRequest(request, ctx) {
|
|
31
32
|
const apiKey = ctx.apiKey ?? config.apiKey
|
|
32
33
|
request.headers.delete('OpenAI-Organization')
|
|
@@ -27,6 +27,7 @@ export function stripe(config: stripe.Config) {
|
|
|
27
27
|
homepage: 'https://docs.stripe.com',
|
|
28
28
|
llms: 'https://docs.stripe.com/llms.txt',
|
|
29
29
|
},
|
|
30
|
+
onUpstreamError: config.onUpstreamError,
|
|
30
31
|
rewriteRequest(request, ctx) {
|
|
31
32
|
const apiKey = ctx.apiKey ?? config.apiKey
|
|
32
33
|
request.headers.delete('Stripe-Account')
|