- 1ba7af2: Hardened sponsored Tempo session
openandtopUpflows by enforcing fee-payer policy limits, blocking call smuggling, and addingfeePayerPolicysupport. - 1ba7af2: Fixed fee-sponsored Tempo charge flows by simulating sponsored transactions before broadcast and binding swap approvals to the DEX input token.
- 1ba7af2: Normalized Tempo session channel IDs across storage and verification paths, preventing case-variant aliases from creating duplicate channel state.
- 7e16df7: Make Tempo charge fee-sponsorship policy resolve per chain and allow overriding it with
feePayerPolicy. - 13d2851: Fixed Tempo HTML pay button text overrides and make the HTML page title follow a custom
paymentRequiredlabel whentitleis omitted. - e81f45c: Add Tempo charge
supportedModesrequest support so clients and servers can explicitly negotiatepushvspullsettlement.
- f6ce313: Add typed
paymentPreferencessupport that emitsAccept-Paymenton client requests and filters composed server challenges accordingly. - 7059598: Accept zero-dollar proof credentials signed by authorized Tempo access keys and export Tempo proof DID helpers from
mppx/tempo. - b6a18c4: Raised too low fee-payer
maxTotalFeepolicy
- 2aff2c0: Handled malformed Host headers in the Node request listener instead of letting them crash the process.
- d95c01c: Pruned internal dependencies.
- 4d7fe94: Bumped internal deps
- 00572a0: Normalized Tempo fee-payer co-signing for charge flows so the final sponsored transaction is rebuilt from validated fields with centralized fee-payer policy checks.
- 7d4fdab: Centralize the authoritative challenge verification inputs by adding captured-request and verified-envelope context plumbing, shared canonical HMAC input generation, and a single pinned-request comparison path without changing the existing server hook model.
- b087c21: Add an optional atomic
Store.update()primitive for custom store backends and use it to make Tempo replay protection and channel state updates safe across distributed deployments.
- 9cffd24: Added
Config,Text, andThemetype exports tomppx/htmlentrypoint.
- 0c4ce6f: Added
.composesupport to HTML payment links.
-
e7147c2: Bind attribution memo nonce to challenge ID. The 7-byte nonce field (bytes 25–31) is now derived from
keccak256(challengeId)[0..6]instead of random bytes, preventing transaction hash stealing in push mode.Attribution.encode()now requireschallengeId. The server verifies challenge binding and server fingerprint forhash(push) credentials. Pull-modetransactioncredentials are not affected — the server controls broadcast, so there is no hash-stealing risk.Breaking:
Attribution.encode()now requireschallengeId— callers must pass the challenge ID to generate a memo. Old push-mode clients that generate random attribution nonces or plain transfers without memos are rejected by the server. Pull-mode clients are unaffected.
- c3f522c: Fixed CLI defaulting to testnet when
--rpc-urlis omitted. The CLI now defaults to Tempo mainnet. Also addedresolveRpcUrlhelper soMPPX_RPC_URLandRPC_URLenv vars are respected consistently across all commands. - f086276: Added theming to automatic HTML payment links.
- ba0bb60: Override vulnerable
lodash(<=4.17.23) to>=4.18.0in pnpm overrides. Fixes code injection via_.template(GHSA-r5fr-rjxr-66jc) and prototype pollution via_.unset/_.omit(GHSA-f23m-r3pf-42rh).
- 2a7dbd3: Added experimental support for payment links
- 20f3fe4: Hardened credential verification, transport billing, error responses, and proxy routing. Credential request binding now verifies fields match the actual incoming request. SSE transport derives billing context directly from the verified credential payload. 402 error responses no longer leak internal details. Proxy routing binds management POST fallback to the credential's payment method and intent for correct disambiguation.
- dd27cb1: Validate the
did:pkh:eip155source DID on zero-dollar Tempo proof credentials. Servers now reject malformed proof source DIDs and chain ID mismatches between the source DID and the challenge signing domain.
- 5e7750b: Added a
proofcredential type for zero-amount Tempo charge requests. Clients now sign an EIP-712 proof over the challenge ID instead of creating a broadcastable transaction, and servers verify the proof against the credential source DID before accepting the request. This prevents zero-dollar auth flows from burning gas when the payer would otherwise have been the fee payer.
- 5684b94: Fixed
settleOnChainandcloseOnChainto use the payee account asmsg.senderinstead of the fee payer when submitting fee-sponsored transactions. Previously,sendFeePayerTxused the fee payer as both sender and gas sponsor, causing the escrow contract to revert withNotPayee(). Addedaccountoption totempo.settle()so callers can specify the signing account separately from the fee payer. - 3bc8657: Added compile-time guard to
tempo.session()andtempo.charge(). Unknown properties (e.g.streaminstead ofsse) now cause a type error instead of being silently accepted. - 0531edd: Added split-payment support to Tempo charge requests, including client transaction construction and stricter server verification for split transfers.
- 6188184: Added
realmauto-detection from the requestHostheader when not explicitly configured. Resolution order: explicit value → env vars (MPP_REALM,FLY_APP_NAME,VERCEL_URL, etc.) → request URL hostname →"MPP Payment"fallback with a one-time warning. Removed the hard-coded"MPP Payment"default and deprioritizedHOST/HOSTNAMEenv vars in favor of platform-specific alternatives. - ba79504: Return
410 ChannelClosedErrorinstead of402 AmountExceedsDepositErrorwhen a channel's on-chain deposit is zero but the channel still exists (payer is non-zero). This handles a race window during settlement where the escrow contract zeros the deposit before setting the finalized flag.
- Fixed close voucher validation to reject vouchers equal to the on-chain settled amount. (GHSA-mv9j-8jvg-j8mr)
- Added Stripe credential replay protection via the
Idempotent-Replayedheader. (GHSA-8mhj-rffc-rcvw)
-
b4e1a3d: Add OpenAPI-first discovery tooling via
mppx/discovery, frameworkdiscovery()helpers, andmppx discover validate.This also changes
mppx/proxydiscovery routes:GET /openapi.jsonis now the canonical machine-readable discovery document.GET /llms.txtremains available as the text-friendly discovery view.- Legacy
/discover*routes now return410 Gone.
-
70f6595: Fix two production session/SSE robustness issues.
- Accept exact voucher replays (
cumulativeAmount == highestVoucherAmount) as idempotent success after signature verification, while still rejecting lower cumulative amounts and preserving monotonic state advancement rules. - Prevent invalid null-body response wrapping in SSE receipt transport by returning
101/204/205/304responses directly instead of stream-wrapping them.
- Accept exact voucher replays (
-
3c713c9:
tempo.session()now throws immediately at initialization if no viemAccountis provided, instead of failing later with an opaque error during channel close. The error message includes an example fix.
- d9b651d: Added
Store.redis()adapter for standard Redis clients (ioredis, node-redis, Valkey) with BigInt-safe serialization. - b69bbee: Fixed Express middleware hanging by constructing a Fetch
Requestdirectly from Express'sreqAPI. - 7da6cfd: Fixed SSE header normalization.
- a2c6cc9: Skipped route amount/currency/recipient validation for topUp and voucher credentials. These
POSTs carry no application body so the route's request hook may produce a different amount than the challenge echoed from the original request. The on-chain voucher signature is the real validation.
- 99920d0: Updated validation. (GHSA-8x4m-qw58-3pcx)
- 2a0b88e: Fixed cooperative close to sign the server-reported spent amount instead of the high-water mark (
cumulativeAmount), preventing overcharging when actual usage was below the pre-authorized voucher amount.
- 281005c: Added support for
feePayeras a URL string ontempomethod.
- bbd4b3f: Updated Moderato (testnet) escrow contract address to
0xe1c4d3dce17bc111181ddf716f75bae49e61a336.
- b09a35a: fix: update getChannel ABI field order to match new escrow contract
- c520705: Fixed
Client.getResolverto inject Tempo serializers onto clients missing them, preventing the default serializer from rejecting Tempo-specific transaction fields. - b09a35a: chore: update mainnet escrow contract address
- 7f8d103: chore: update mainnet escrow contract address
- c089da5: Added CLI config via
mppx.config.(js|mjs|ts). Allows for extendingmppxCLI to support non-built-in methods.
- f2bc051: Support keychain V2 (
0x04) signatures via ox 0.14 upgrade
- 143ebc9: Support handler function refs in
compose().[mppx.tempo.charge, { amount: '1' }]syntax —compose()now accepts handler function references (e.g.mppx.tempo.charge) as the first element of entry tuples, in addition toMethod.AnyServerobjects and"name/intent"string keys._methodmetadata on nested handlers — nested handler functions are tagged with their sourceMethod.AnyServer, enablingcompose()to resolve the correct handler.
-
db2033c: Set
feeTokenduring server co-sign and simulation for fee-payer transactions.When the client sends a fee-payer (0x78) envelope,
feeTokenis intentionally omitted. The server must set it at co-sign time, but previously never did — causing "Fee token spending limit exceeded" errors. Now resolvesfeeTokenfrom the deserialized transaction or falls back to the chain's default currency.
- 79bbfc6: Added multi-challenge
mppx.challenge()combinator for presenting multiple payment methods in a single 402 response, nested accessors (mppx.tempo.charge(...)),Mppx.challenge()static,Challenge.fromResponseList(), and automatic client preference-based challenge selection. - b4f3c92: Migrated to use
callinstead of manualeth_estimateGas.
- cd42c28: Added
rawFetchproperty to the clientMppxinstance, exposing the original unwrapped fetch function for requests that should bypass 402 payment interception. - 230ef16: Moved CLI payment logs (Payment Required, Payment Receipt, channel open/close) behind
-vflag. Added-vvfor full HTTP headers.
- 345425f: Removed
expiresfrom charge request schemas (tempo, stripe). Expiry is now conveyed exclusively via theexpiresauth-param on the Challenge, not duplicated in the request body. Server handlers default toExpires.minutes(5)whenexpiresis not explicitly provided. - eb19f32: Added
modeparameter totempo.charge()client —'push'(client broadcasts tx, sends hash) and'pull'(client signs tx, server broadcasts). Defaults to'push'for JSON-RPC accounts,'pull'otherwise.
- 82206f5: Made
constantTimeEqualisomorphic by replacingnode:cryptowithoxsha256 and a custom constant-time comparison.
- c28944e: Added
autoSwapflag totempomethod. When enabled, the client automatically swaps from supported currencies via the DEX if the payer lacks the target token. - 9c23cb7: Fixed fetch polyfill to pass
initthrough unmodified for non-402 responses. Previously, every request eagerly destructuredinitto strip thecontextproperty, creating a new object that could break libraries relying on object identity (e.g. WebSocket upgrade handshakes).
- fd466c3: Added
waitForConfirmationoption tosession()andcharge()payment methods. Whenfalse, transactions are simulated viaeth_estimateGasand broadcast without waiting for on-chain confirmation, reducing latency. - ddb7057: Fixed
Handlerstype to omit shorthand intent keys when multiple methods share the same intent, matching runtime behavior and preventingTypeErroron collision.
- 558279e: Added
closeRequestedAtcheck in session voucher handler with configurablechannelStateTtl(default: 60s). Prevented payers from using a channel after initiating a forced close. - 558279e: Added expiration check on credentials in the core handler. Expired credentials are now rejected with
PaymentExpiredErrorinstead of being processed. - 558279e: Added token address validation in
broadcastTopUpTransactionfee-payer logic. Prevented approve calls to arbitrary contracts in fee-sponsored topUp transactions. - 558279e: Bound credential verification to the route's configured request. Prevented cross-route scope confusion where a credential issued for one route could be presented at another.
- 558279e: Removed insecure hardcoded
'tmp'fallback forsecretKey.Mppx.create()now throws a clear error if neitherMPP_SECRET_KEYenv var nor explicitsecretKeyis provided. - 5d4bb93: Removed
realmfromPaymentRequiredErrordetail message to avoid leaking deployment URLs and hostnames in error responses.
- a016e1f: Added fee payer support to
settleOnChainandcloseOnChainfor server-originated transactions on chains where the server EOA has no native tokens. Transactions are built usingprepareTransactionRequest→ dual-sign →sendRawTransactionSyncwith an explicitly resolved fee token.
- 7cb0d5f: Fixed CLI failing with "No account found" when
MPPX_PRIVATE_KEYis set to an empty string.
- e4f0138: Added
nonceKey: 'expiring'to tempo charge transactions to avoid nonce collisions on parallel requests.
- d2fb5e3: Fixed issue where mainnet would not default to USDC unless
testnet: falsewas explicitly passed.
-
6e2be11: Replaced
--channel <id>and--deposit <amount>CLI flags with-M/--method-optfor passing method-specific options.# Before - mppx example.com/content --channel 0x123 --deposit 1000000 # After + mppx example.com/content -M channel=0x123 -M deposit=1000000
-
6e2be11: Added Stripe payment method support to the CLI.
# Set your Stripe test-mode secret key export MPPX_STRIPE_SECRET_KEY=sk_test_... # Make a request to a Stripe-enabled endpoint mppx https://example.com/content
-
955deb2: Renamed USDC.e to USDC in account view token list.
- 9cf4943: Added USDC.e to account view mainnet token list and use
MPPX_RPC_URLfor default mainnet balance fetching. - 11c0422: Renamed internal
streamterminology tosessionto align with the MPP spec. This includes renaming thesrc/tempo/stream/directory tosrc/tempo/session/, updating all problem type URIs from…/problems/stream/…to…/problems/session/…, and renaming associated types (e.g.,StreamCredentialPayload→SessionCredentialPayload). No public API changes.
- 04b04c9: Added auto-detection of
realmandsecretKeyfrom environment variables inMppx.create().- Realm: checks
MPP_REALM,FLY_APP_NAME,HEROKU_APP_NAME,HOST,HOSTNAME,RAILWAY_PUBLIC_DOMAIN,RENDER_EXTERNAL_HOSTNAME,VERCEL_URL,WEBSITE_HOSTNAME - Secret key: checks
MPP_SECRET_KEY
- Realm: checks
- b927c06: -
mppx/proxy: Modified routes to show service in path for completeness (e.g.POST /openai/v1/chat/completionsinstead ofPOST /v1/chat/completions).
- e6c9f85: Fixed
/discover.mdroute returning 404.
- d60f623: -
mpp/proxy(Breaking): Renamed/services*discovery routes to/discover*.mpp/proxy: Simplifiedllms.txtto a brief service overview, linking each service to/discover/<id>.mpp/proxy: Added/discoverand/discover/<id>endpoints with content negotiation (JSON by default, markdown forAccept: text/markdown/text/plainor bot/CLI user agents).mpp/proxy: Added.mdextension variants (/discover.md,/discover/<id>.md) for explicit markdown.mpp/proxy: Added/discover/allfor full markdown listing with route details.
-
83c3bab: - Added
titleanddescriptionoptions toProxy.createconfig, used to populate thellms.txtheading and description.const proxy = Proxy.create({ title: 'My AI Gateway', description: 'A paid proxy for LLM and AI services.', services: [...] })
- Added
title,description, anddocsLlmsUrlproperties toServicetype andService.fromconfig.
Service.from('my-api', { baseUrl: 'https://api.example.com', title: 'My API', description: 'A custom API service.', docsLlmsUrl: 'https://example.com/llms.txt', routes: { ... }, }) // or with per-endpoint docs Service.from('my-api', { baseUrl: 'https://api.example.com', docsLlmsUrl: (endpoint) => endpoint ? `https://example.com/api/${encodeURIComponent(endpoint)}.md` : 'https://example.com/llms.txt', routes: { ... }, })
- Added
- 01fa8ba: Added fallback
authorizedSignertoaccount.accessKeyAddresswhen not explicitly provided.
- 83d0175: Bumped
viempeer dependency to>=2.46.2.
- c0aa6ad: Fixed Stripe
createWithClientto useshared_payment_granted_tokeninstead ofpayment_methodwhen creating a PaymentIntent with an SPT. This aligns the SDK client path with the raw fetch path and fixes 402 errors on credential retry. - e7f5985: Rejected keychain and non-secp256k1 signatures in
verifyVoucher.
- 360fc03: Added
Json.canonicalizefromox
- eb72c76: Breaking:
- Renamed
Challenge.fromIntenttoChallenge.fromMethod. - Renamed
PaymentRequest.fromIntenttoPaymentRequest.fromMethod.
- Renamed
- 627f5ec: Breaking:
- Renamed
IntentandMethodIntentmodules toMethod. - Removed
Intentexport frommppx. UseMethodinstead. - Removed
MethodIntentexport frommppx. UseMethodinstead. - Renamed
MethodIntentsexport toMethodsinmppx/tempoandmppx/stripe.
- Renamed
- 910102d: Fixed SSE streaming reliability: pass
signalthroughSessionManager.sse()so HTTP connections close on abort, snapshot challenge at SSE open time to prevent concurrent requests from corrupting voucher credentials, and forwardrequest.signaltoSse.serve()sochargeOrWaitbreaks on disconnect.
- badab1a: Initial release.