Skip to content

feat(lore-0145): raise the @x402 packages to 2.31.0 - #184

Merged
adamkoot merged 6 commits into
developfrom
lore-0145-x402-2-31-upgrade
Nov 13, 2026
Merged

adamkoot merged 6 commits into
developfrom
lore-0145-x402-2-31-upgrade

Conversation

@adamkoot

@adamkoot adamkoot commented Nov 13, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

0145: the repo's TypeScript moves from @x402 2.28.0 to 2.31.0, the newest upstream, so the
facilitator, the TypeScript examples and the Rust crate (0136, held equal to @x402/express
2.31.0) follow the same upstream.

  • Versions (11 package.json, pnpm-lock.yaml): every @x402/* on ~2.31.0; express
    ^5.3.0, which @x402/express 2.31.0 needs; @modelcontextprotocol/sdk ^1.32.0, which
    @x402/mcp 2.31.0 needs; @stellar/stellar-sdk ^16.4.1, which
    @x402/stellar 2.31.0 needs. One @x402/core (2.31.0) and one @stellar/stellar-sdk (16.4.1)
    resolve.
  • zod 4 in packages/bazaar (src/service-metadata.ts): @x402/core 2.31.0 builds its
    schemas 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 /verify
    and /settle answer 500 to every request and the seller check fails every listing.
  • AD-14 (docs/architecture/m1-spine.md, packages/signer-pool/test/xdr-fixture.test.ts): the
    pin and its guard test name 2.31.
  • The task (lore/1-tasks/active/0145_FEATURE_x402-2-31-upgrade.md): what 2.31.0 changes for
    the facilitator, the decisions, the testnet and parity runs. apps/mcp-local/e2e/results: the
    testnet run.

Reviewers, please confirm:

  • @karolko9 (0130): 2.31.0 does not carry the upstream fix (ResourceInfoSchema still refuses
    an over-long serviceName, tags or iconUrl), so the schema in packages/bazaar stays, now on
    zod 4; a payment with 6 tags still parses and tags: "x" is still refused.

Please confirm

  1. zod 4 in packages/bazaar only (payments, discovery): it is the one place the repo builds a
    schema from upstream's. The facilitator's config.ts and discovery.ts, packages/mcp,
    apps/mcp-local, examples/http-api and infra parse with their own zod 3 schemas and pass on
    2.31.0; moving them would change how the facilitator reads its config in production, for
    nothing this bump needs. The tree holds two zods.
  2. @modelcontextprotocol/sdk ^1.32.0 in every package (discovery): @x402/mcp 2.31.0 asks
    for 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.
  3. express ^5.3.0 in the facilitator too (payments), not only in examples/http-api: one
    express for the repo's own code.
  4. No minimumReleaseAgeExclude (platform): pnpm 11 holds back a release younger than a day
    and wrote the six 2.31.0 packages into pnpm-workspace.yaml at the bump. A fresh
    pnpm install --frozen-lockfile passes 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.verify is 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.
  • Upstream's settle() now answers TRY_AGAIN_LATER as
    settle_exact_stellar_transaction_submission_retryable; ours never calls it (AD-3), and the
    submitter retries TRY_AGAIN_LATER itself. x402Facilitator's hook semantics changed; ours does
    not use the class.
  • HTTPFacilitatorClient sends the same body and reads at most 1 MiB of an answer;
    settleWithPendingRetry is unchanged, so our settlement_pending repeat holds. The bazaar
    discovery 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 --check on every tracked file → clean. Locally pnpm format:check and
    pnpm lint also flag git-ignored files (.vibe-wise/, packages/sdk/rust/target/doc) that CI
    doesn't have.
  • Testnet: pnpm mcp:e2e at 706a8e9a → 121 of 121. packages/mcp on @x402/fetch 2.31.0 paid
    examples/http-api on @x402/express 2.31.0 through this branch's facilitator, 0.001 USDC each,
    the facilitator paying the fees: E-21
    118b37d00e3590bb8090815b4d0385cc0cc3923d0a3f1ccf963c0629ce0f789e, E-22a
    494233720028a9e56592580d088e733a5bf5e6fd033418ca05c3d4cc89cef6b9.
  • Parity: 0136's 45 requests to examples/http-api (2.31.0) and examples/weather.rs behind one
    fake 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.

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 stkrolikiewicz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:101 still argues from "the pin ~2.28.0 lets upstream patches float". The pin is ~2.31.0 now.
  • apps/facilitator/src/catalog/seller-check.ts:100 and apps/facilitator/test/mcp-seller.ts:29 describe how upstream's MCP payment wrapper sends terms "as @x402/mcp 2.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.

Comment thread apps/facilitator/package.json Outdated
"@stellar-x402/metrics-catalog": "workspace:*",
"@stellar-x402/seller-fetch": "workspace:*",
"@stellar-x402/signer-pool": "workspace:*",
"@stellar/stellar-sdk": "^16.3.0",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread docs/architecture/m1-spine.md Outdated
| 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 |

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
@adamkoot

Copy link
Copy Markdown
Collaborator Author

On the two points outside the diff (29347d2):

  • docs/architecture/m1-spine.md:101 now says ~2.31.0.
  • createPaymentRequiredResult in @x402/mcp 2.31.0 answers the same as in 2.28.0 (it only copies accepts first), so seller-check.ts and mcp-seller.ts cite 2.31.0. I also updated main.ts:107 and validate.ts:193, re-read against 2.31.0.

@adamkoot
adamkoot merged commit 311114b into develop Nov 13, 2026
3 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants