Skip to content

Declare @x402/fetch as an optional peer dependency (undeclared dynamic import breaks bundlers/tracers) #24

Description

@ryantbrown

Problem

The SDK lazily imports @x402/fetch for the optional payments feature, but the package is not declared anywhere in package.json:

  • src/wrapper/x402.tsconst { x402HTTPClient } = await import("@x402/fetch"); (plus a type import)
  • src/wrapper/Client.tsconst { wrapFetchWithPayment } = await import("@x402/fetch");
  • package.jsondependencies: { "ws": "..." } only; no peerDependencies, no optionalDependencies

That makes @x402/fetch a phantom optional dependency. It works in plain Node only if the consumer coincidentally has the package installed, and it breaks any toolchain that statically analyzes the import:

  • Bundlers (rollup/rolldown/vite/esbuild) fail with unresolvable-import errors unless every consumer manually externalizes @x402/fetch.
  • File tracers / snapshot builders (@vercel/nft, and build systems that materialize dependency closures, e.g. eve 0.24+) fail hard because a configured external must be resolvable on disk: Cannot resolve external package "@x402/fetch".
  • Isolated installers (bun isolated linker, pnpm) guarantee phantom resolution never works, so the runtime fallback path can't save it either.

We hit this as a hard production build failure and now carry two workarounds in our monorepo: externalizing @x402/fetch in three bundler configs and installing it as a direct dependency of the consuming app purely so build tooling can resolve an import that never executes.

Suggested fix

Declare the dependency so tooling and consumers can see it:

{
  "peerDependencies": {
    "@x402/fetch": "^2"
  },
  "peerDependenciesMeta": {
    "@x402/fetch": { "optional": true }
  }
}

This keeps the feature opt-in (consumers install @x402/fetch only if they use payments), lets bundlers and tracers understand the import instead of erroring, and documents the requirement instead of leaving it to runtime discovery.

Observed on agentmail@0.5.14/0.5.15 and current main.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions