Repository navigation
feat(lore-0145): raise the @x402 packages to 2.31.0 - #184
Conversation
Every @x402 package moves from ~2.28.0 to ~2.31.0, express to ^5.3.0 (which @x402/express 2.31.0 needs) and @modelcontextprotocol/sdk to ^1.32.0 (which @x402/mcp 2.31.0 needs). @x402/core 2.31.0 builds its schemas with zod 4. packages/bazaar extends them with its own fields, and a zod 3 field there throws on every parse, so /verify and /settle would answer 500. packages/bazaar moves to zod 4; the rest of the repo keeps zod 3 for its own schemas. AD-14's pin and its guard test name 2.31. One @x402/core and one @stellar/stellar-sdk (16.4.1) resolve.
What changed for the facilitator between 2.28.0 and 2.31.0: only packages/bazaar's zod; verify, the wire types and the settlement_pending retry are unchanged. The decisions taken during the bump.
pnpm test passes on the bump, and the MCP testnet run settled two payments from @x402/fetch 2.31.0 through this branch's facilitator.
examples/http-api on @x402 2.31.0 and the Rust crate's example answer 43 of 0136's 45 requests the same; OPTIONS and POST on the GET route are the frameworks' own answers.
stkrolikiewicz
left a comment
There was a problem hiding this comment.
The zod 4 move in packages/bazaar looks right to me. Comments inline. Two more that sit outside the diff:
docs/architecture/m1-spine.md:101still argues from "the pin~2.28.0lets upstream patches float". The pin is~2.31.0now.apps/facilitator/src/catalog/seller-check.ts:100andapps/facilitator/test/mcp-seller.ts:29describe how upstream's MCP payment wrapper sends terms "as@x402/mcp2.28.0" does. Is that the same in 2.31.0? If so, the citation can say so. If not, the fake seller still imitates 2.28.0.
| "@stellar-x402/metrics-catalog": "workspace:*", | ||
| "@stellar-x402/seller-fetch": "workspace:*", | ||
| "@stellar-x402/signer-pool": "workspace:*", | ||
| "@stellar/stellar-sdk": "^16.3.0", |
There was a problem hiding this comment.
@x402/stellar 2.31.0 depends on @stellar/stellar-sdk ^16.4.1, but this range (and the one in every other workspace package) still allows 16.3.x. The lock has a single 16.4.1 only because pnpm picks the highest match. If the lock is regenerated differently (a partial pnpm update, resolution-mode=lowest-direct, or an install outside our lock), our code can get 16.3.x while upstream gets 16.4.1. That is two stellar-sdk copies in one process, which is exactly what AD-14 prevents. xdr-fixture.test.ts only checks /^16\./, so it wouldn't notice. Raise to ^16.4.1 everywhere?
There was a problem hiding this comment.
Confirmed: @x402/stellar 2.31.0 asks for ^16.4.1. Raised to ^16.4.1 in all 8 packages (29347d2). xdr-fixture.test.ts now also checks that upstream resolves the same copy of the SDK we do, so a second copy fails there.
| | TypeScript | ~6.0.3 (ESM, NodeNext, strict; staying on 6.x in T1 is deliberate) | | ||
| | @x402/core, @x402/stellar, @x402/extensions | ~2.28.0 | | ||
| | @x402/core, @x402/stellar, @x402/extensions | ~2.31.0 | | ||
| | @stellar/stellar-sdk | ^16.3.0 | |
There was a problem hiding this comment.
This row still says ^16.3.0 (see the comment on the floor). The zod row two lines down lists only ^3.25.76, while packages/bazaar is on ^4.6.7 now. I'd note the second zod there so nobody "aligns" bazaar back to 3.
There was a problem hiding this comment.
Fixed in 29347d2: the row says ^16.4.1, and the zod row and AD-14 name the second zod in packages/bazaar and why it is there.
| "zod": "^3.25.76" | ||
| "@x402/core": "~2.31.0", | ||
| "@x402/extensions": "~2.31.0", | ||
| "zod": "^4.6.7" |
There was a problem hiding this comment.
This zod has to stay on the major @x402/core builds its schemas with, otherwise every parse of the extended schemas throws, and /verify and /settle answer 500. Right now only the comment in service-metadata.ts says so. Could an assert next to the AD-14 test cover it (bazaar's installed zod major == the major of @x402/core's zod dependency)? The existing tests would fail too, but with expected a Zod schema, which doesn't name the cause.
There was a problem hiding this comment.
Added packages/bazaar/test/zod-major.test.ts (29347d2): it compares the package's installed zod major with the one @x402/core resolves, and its message names the cause. It sits in bazaar, not next to the AD-14 test, because signer-pool has no zod.
@stellar/stellar-sdk moves to ^16.4.1 in every package, the range @x402/stellar 2.31.0 asks for: with ^16.3.0 only the lockfile kept our code on upstream's copy. The AD-14 test now checks that upstream loads the copy we load, and a test in packages/bazaar names the zod major it must share with @x402/core. The spine lists the new floor and the second zod, and the comments that cite upstream cite 2.31.0 where the code was read again.
|
On the two points outside the diff (29347d2):
|
Summary
0145: the repo's TypeScript moves from
@x4022.28.0 to 2.31.0, the newest upstream, so thefacilitator, the TypeScript examples and the Rust crate (0136, held equal to
@x402/express2.31.0) follow the same upstream.
package.json,pnpm-lock.yaml): every@x402/*on~2.31.0;express^5.3.0, which@x402/express2.31.0 needs;@modelcontextprotocol/sdk^1.32.0, which@x402/mcp2.31.0 needs;@stellar/stellar-sdk^16.4.1, which@x402/stellar2.31.0 needs. One@x402/core(2.31.0) and one@stellar/stellar-sdk(16.4.1)resolve.
packages/bazaar(src/service-metadata.ts):@x402/core2.31.0 builds itsschemas with zod 4, and 0130's schema extends them. With zod 3 fields every parse throws
(
Invalid element at key "serviceName": expected a Zod schema), so on the bump alone/verifyand
/settleanswer 500 to every request and the seller check fails every listing.docs/architecture/m1-spine.md,packages/signer-pool/test/xdr-fixture.test.ts): thepin and its guard test name 2.31.
lore/1-tasks/active/0145_FEATURE_x402-2-31-upgrade.md): what 2.31.0 changes forthe facilitator, the decisions, the testnet and parity runs.
apps/mcp-local/e2e/results: thetestnet run.
Reviewers, please confirm:
ResourceInfoSchemastill refusesan over-long
serviceName,tagsoriconUrl), so the schema inpackages/bazaarstays, now onzod 4; a payment with 6 tags still parses and
tags: "x"is still refused.Please confirm
packages/bazaaronly (payments, discovery): it is the one place the repo builds aschema from upstream's. The facilitator's
config.tsanddiscovery.ts,packages/mcp,apps/mcp-local,examples/http-apiandinfraparse with their own zod 3 schemas and pass on2.31.0; moving them would change how the facilitator reads its config in production, for
nothing this bump needs. The tree holds two zods.
@modelcontextprotocol/sdk^1.32.0in every package (discovery):@x402/mcp2.31.0 asksfor it, and one range keeps one version (1.32.2). pnpm still keeps two peer variants of it, one
per zod;
examples/mcp-metered, the only user of@x402/mcp, is a placeholder.express^5.3.0in the facilitator too (payments), not only inexamples/http-api: oneexpress for the repo's own code.
minimumReleaseAgeExclude(platform): pnpm 11 holds back a release younger than a dayand wrote the six 2.31.0 packages into
pnpm-workspace.yamlat the bump. A freshpnpm install --frozen-lockfilepasses without them, so they are not kept.Please note
What 2.31.0 changes for the facilitator, read from the built packages (no changelog ships):
ExactStellarScheme.verifyis unchanged, and the exact client builds the same transaction (new:typed errors when its simulation fails). The wire types (
VerifyResponse,SettleResponse,SupportedResponse,PaymentRequirements) are equal.settle()now answersTRY_AGAIN_LATERassettle_exact_stellar_transaction_submission_retryable; ours never calls it (AD-3), and thesubmitter retries
TRY_AGAIN_LATERitself.x402Facilitator's hook semantics changed; ours doesnot use the class.
HTTPFacilitatorClientsends the same body and reads at most 1 MiB of an answer;settleWithPendingRetryis unchanged, so oursettlement_pendingrepeat holds. The bazaardiscovery client reads at most 4 MiB; a page of 100 stays under 1.6 MB.
The deployed facilitator stays on 2.28.0 until its next deploy after the merge.
Testing
pnpm lint,pnpm typecheck,pnpm test,pnpm build→ pass. Tests: facilitator 1012(3 skipped, against the local PostgreSQL), infra 355, signer-pool 190, bazaar 135, mcp 115,
deploy 113, conformance 50, metrics-catalog 31, mcp-local 23, example-http-api 13, seller-fetch
13, config 2.
prettier --checkon every tracked file → clean. Locallypnpm format:checkandpnpm lintalso flag git-ignored files (.vibe-wise/,packages/sdk/rust/target/doc) that CIdoesn't have.
pnpm mcp:e2eat706a8e9a→ 121 of 121.packages/mcpon@x402/fetch2.31.0 paidexamples/http-apion@x402/express2.31.0 through this branch's facilitator, 0.001 USDC each,the facilitator paying the fees: E-21
118b37d00e3590bb8090815b4d0385cc0cc3923d0a3f1ccf963c0629ce0f789e, E-22a494233720028a9e56592580d088e733a5bf5e6fd033418ca05c3d4cc89cef6b9.examples/http-api(2.31.0) andexamples/weather.rsbehind onefake facilitator → the terms equal, 43 answers equal. OPTIONS and POST on the GET route are the
frameworks' own answers (express 200 and 404, axum 405), as in 0136.