x402 icon indicating copy to clipboard operation
x402 copied to clipboard

Proposal: separate paywall / middleware from the base x402 typescript package

Open dngpng opened this issue 2 months ago • 1 comments

Summary

Refactor paywall-related code out of the x402 TypeScript package and move it into one or more separate packages (e.g., x402-paywall or x402-middleware). The core x402 package should remain a small, vendor-agnostic protocol library containing only abstractions and basic functionality.

Rationale

  1. Separation of concerns
    • The x402 package is a protocol base package and should only contain protocol abstractions and minimal utilities. Paywall is a higher-level feature used by middleware and applications, not part of the protocol itself.
  2. Bundle size and integration limits
    • The current paywall implementation pulls heavy frontend and vendor dependencies (React, wagmi, @coinbase/onchainkit, etc.), which dramatically increases package size.
    • This causes integration problems in size-constrained environments. Example: a basic edge function implementation depending on x402 and @coinbase/x402 produced a bundle of 35.32 MB — exceeding Supabase Edge Function limits (20 MB).
  3. Vendor-agnostic core
    • The base package should be vendor-agnostic. The current PaywallConfig and default paywall depend on vendor-specific concepts (e.g., cdpClientKey and cdp/onchainkit), coupling core protocol code to specific middleware providers.

Proposal

  • Extract paywall/middleware code into a separate package (or packages), for example:
    • x402-paywall
    • or x402-middleware
  • Keep x402 as a lightweight, vendor-agnostic protocol package that provides only core abstractions and utilities.
  • Provide the paywall implementation(s) from a vender specific package like @coinbase/x402-paywall; downstream projects can opt-in by adding the paywall package as a dependency (similar to how facilitator code is provided today).

Benefits

  • Smaller, cleaner core package: easier to audit, maintain, and reason about the protocol.
  • Reduced bundle sizes for consumers who only need protocol functionality.
  • Better compatibility with size-limited runtimes (edge functions, serverless).
  • Clear vendor separation: paywall implementations can be vendor-specific without polluting the protocol package.
  • Easier to extend: multiple paywall implementations (vendor-specific or generic) can be published independently.

dngpng avatar Oct 20 '25 01:10 dngpng

This is a solid way to go.

We did this with our x402 implementation inside of Faremeter, and it worked well. For something like running the middleware, the dependencies end up looking like:

  • @logtape/logtape - 636k - We use this on Faremeter for all of our logging, but this will soon become optional
  • arktype - 332k - ArkType handles all of our type creation and runtime validation.
  • @faremeter/types - 116k - All of your base x402 type definitions (and some helpers for different chains).
  • @faremeter/middleware - 200k - Compatible middleware for a bunch of systems (e.g. express, Hono).
  • @faremeter/info - 118k - Helpers for looking up network names and asset addresses.

... and of course you can bundle/tree shake that, and it'll get down to a much smaller size. It lets you compose things much more easily than just having a huge monolith.

We've spoken with @CarsonRoscoe about this approach, and he's definitely aware of the benefits as things move forward into coinbase/x402 v2.

alexanderguy avatar Oct 20 '25 16:10 alexanderguy