-
Couldn't load subscription status.
- Fork 611
[SDK] Add x402 payment protocol utilities #8076
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: 61c5202 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
WalkthroughAdds x402 paywall support across the repo: new thirdweb x402 exports and dependency, facilitator and wrapFetchWithPayment utilities, middleware protecting /api/paywall, a Next.js paywall route, playground x402 page and client preview, nav and package updates, and removal of the legacy payments overview. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Client as X402ClientPreview
participant Wrapper as wrapFetchWithPayment
participant Route as /api/paywall
participant MW as paymentMiddleware
participant X402 as x402 Service
User->>Client: Click "Pay Now" (starts fetch)
Client->>Wrapper: fetch("/api/paywall")
Wrapper->>Route: initial request
Route-->>Wrapper: 402 Payment Required (+requirements)
Wrapper->>Wrapper: select requirement, validate amount, build payment header
Wrapper->>Route: retry request with X-PAYMENT header
Route->>MW: middleware settles/forwards (uses facilitator headers)
MW->>X402: verify/settle/list calls
X402-->>MW: settlement OK
MW-->>Route: authorized request forwarded
Route-->>Wrapper: 200 JSON response
Wrapper-->>Client: response returned
Client-->>User: display response
sequenceDiagram
autonumber
participant Edge as Next.js Edge Runtime
participant MW as paymentMiddleware
participant FAC as facilitator(config)
participant X402 as x402 Service
Edge->>MW: Request matches "/api/paywall"
MW->>FAC: createAuthHeaders()
FAC-->>MW: headers for verify/settle/list (includes secretKey, serverWalletAddress, optional vault token)
MW->>X402: verify/list/settle (with headers)
X402-->>MW: responses
MW-->>Edge: continue or respond based on flow
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
Comment |
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
size-limit report 📦
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8076 +/- ##
==========================================
- Coverage 56.34% 56.34% -0.01%
==========================================
Files 906 906
Lines 59171 59171
Branches 4173 4176 +3
==========================================
- Hits 33342 33337 -5
- Misses 25723 25728 +5
Partials 106 106
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/thirdweb/package.json (1)
356-425: Addx402entry totypesVersions
ThetypesVersionsblock inpackages/thirdweb/package.jsonis missing the"x402"mapping. Without it, TypeScript won’t resolve the generated declarations. Add:"x402": ["./dist/types/exports/x402.d.ts"]under the
"*"key intypesVersions.
🧹 Nitpick comments (9)
apps/playground-web/package.json (1)
51-52: Pin 0.x dependency more tightly to avoid accidental breaks.Semver <1.0 treats minor bumps as breaking in many libs. Prefer
~0.6.1(or exact) here.Apply:
- "x402-next": "^0.6.1", + "x402-next": "~0.6.1",apps/playground-web/src/app/api/paywall/route.ts (1)
1-10: Mark server-only and add explicit return type.Aligns with app guidelines and TS clarity.
Apply:
+import "server-only"; import { NextResponse } from "next/server"; // Allow streaming responses up to 5 minutes export const maxDuration = 300; -export async function GET(_req: Request) { +export async function GET( + _req: Request, +): Promise<NextResponse<{ success: boolean; message: string }>> { return NextResponse.json({ success: true, message: "Congratulations! You have accessed the protected route.", }); }apps/playground-web/src/middleware.ts (1)
1-7: Import NextResponse for safe fallback.Needed if we gate the middleware when env is missing.
Apply:
+import { NextResponse } from "next/server"; import { createThirdwebClient } from "thirdweb"; import { facilitator } from "thirdweb/x402"; import { paymentMiddleware } from "x402-next";packages/thirdweb/src/x402/fetchWithPayment.ts (4)
125-126: Remove request-side Access-Control-Expose-Headers.This is a response header; sending it in the request is a no-op and can confuse future readers.
Apply:
headers: { ...(initParams.headers || {}), "X-PAYMENT": paymentHeader, - "Access-Control-Expose-Headers": "X-PAYMENT-RESPONSE", },
27-28: Fix JSDoc default value mismatch (0.1 vs 1 USDC).Comment says 0.1 USDC; code defaults to 1 USDC. Align docs.
- * @param maxValue - The maximum allowed payment amount in base units (defaults to 0.1 USDC) + * @param maxValue - The maximum allowed payment amount in base units (defaults to 1 USDC)
1-1: Lazy-load heavy dependency createPaymentHeader.Reduce initial bundle by importing only on 402 path.
-import { createPaymentHeader } from "x402/client"; @@ - const paymentHeader = await createPaymentHeader( + const { createPaymentHeader } = await import("x402/client"); + const paymentHeader = await createPaymentHeader( walletClient, x402Version, selectedPaymentRequirements, );Also applies to: 108-112
135-139: Annotate helper return type.Tiny clarity and inference improvement.
-function defaultPaymentRequirementsSelector( +function defaultPaymentRequirementsSelector( paymentRequirements: PaymentRequirements[], chainId: number, scheme: "exact", -) { +): PaymentRequirements {apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx (2)
55-65: Guard optional token to avoid runtime crash on undefined.getDefaultToken can return undefined; current non-null assertions will throw.
<ConnectButton client={THIRDWEB_CLIENT} chain={chain} - detailsButton={{ - displayBalanceToken: { - [chain.id]: token!.address, - }, - }} - supportedTokens={{ - [chain.id]: [token!], - }} + detailsButton={ + token + ? { + displayBalanceToken: { [chain.id]: token.address }, + } + : undefined + } + supportedTokens={token ? { [chain.id]: [token] } : undefined} />
26-39: Deduplicate connect logic (optional).Connect in one place (onClick) and pass wallet to the mutation to avoid double prompts.
-const paidApiCall = useMutation({ - mutationFn: async () => { - let wallet = activeWallet; - if (!wallet) { - wallet = await modal.connect({ - client: THIRDWEB_CLIENT, - chain, - }); - } - const fetchWithPay = wrapFetchWithPayment(fetch, THIRDWEB_CLIENT, wallet); - const response = await fetchWithPay("/api/paywall"); - return response.json(); - }, -}); +const paidApiCall = useMutation({ + mutationKey: ["x402-paywall", chain.id], + mutationFn: async (wallet: any) => { + const fetchWithPay = wrapFetchWithPayment(fetch, THIRDWEB_CLIENT, wallet); + const response = await fetchWithPay("/api/paywall"); + if (!response.ok) { + throw new Error(`${response.status} ${response.statusText}`); + } + return response.json(); + }, +}); @@ - const handlePayClick = async () => { + const handlePayClick = async () => { let wallet = activeWallet; if (!wallet) { wallet = await modal.connect({ client: THIRDWEB_CLIENT, chain, }); } - paidApiCall.mutate(); + paidApiCall.mutate(wallet); };Also applies to: 41-50
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (12)
.changeset/sad-hairs-smash.md(1 hunks)apps/playground-web/package.json(1 hunks)apps/playground-web/src/app/api/paywall/route.ts(1 hunks)apps/playground-web/src/app/navLinks.ts(1 hunks)apps/playground-web/src/app/payments/page.tsx(0 hunks)apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx(1 hunks)apps/playground-web/src/app/payments/x402/page.tsx(1 hunks)apps/playground-web/src/middleware.ts(1 hunks)packages/thirdweb/package.json(2 hunks)packages/thirdweb/src/exports/x402.ts(1 hunks)packages/thirdweb/src/x402/facilitator.ts(1 hunks)packages/thirdweb/src/x402/fetchWithPayment.ts(1 hunks)
💤 Files with no reviewable changes (1)
- apps/playground-web/src/app/payments/page.tsx
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
**/*.{ts,tsx}: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from@/typeswhere applicable
Prefertypealiases overinterfaceexcept for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size
Files:
apps/playground-web/src/app/api/paywall/route.tsapps/playground-web/src/middleware.tspackages/thirdweb/src/exports/x402.tspackages/thirdweb/src/x402/facilitator.tspackages/thirdweb/src/x402/fetchWithPayment.tsapps/playground-web/src/app/navLinks.tsapps/playground-web/src/app/payments/x402/page.tsxapps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
apps/playground-web/src/app/api/paywall/route.tsapps/playground-web/src/middleware.tspackages/thirdweb/src/exports/x402.tspackages/thirdweb/src/x402/facilitator.tspackages/thirdweb/src/x402/fetchWithPayment.tsapps/playground-web/src/app/navLinks.tsapps/playground-web/src/app/payments/x402/page.tsxapps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
UseNavLinkfor internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()from@/lib/utilsfor conditional class logic
Use design system tokens (e.g.,bg-card,border-border,text-muted-foreground)
Server Components (Node edge): Start files withimport "server-only";
Client Components (browser): Begin files with'use client';
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader – never embed tokens in URLs
Return typed results (e.g.,Project[],User[]) – avoidany
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysfor React Query cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components
Files:
apps/playground-web/src/app/api/paywall/route.tsapps/playground-web/src/middleware.tsapps/playground-web/src/app/navLinks.tsapps/playground-web/src/app/payments/x402/page.tsxapps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
.changeset/*.md
📄 CodeRabbit inference engine (AGENTS.md)
.changeset/*.md: Each change inpackages/*must include a changeset for the appropriate package
Version bump rules: patch for non‑API changes; minor for new/modified public API
Files:
.changeset/sad-hairs-smash.md
packages/thirdweb/src/exports/**
📄 CodeRabbit inference engine (CLAUDE.md)
packages/thirdweb/src/exports/**: Export everything viaexports/directory, grouped by feature in the SDK public API
Every public symbol must have comprehensive TSDoc with at least one@exampleblock that compiles and custom annotation tags (@beta,@internal,@experimental)
Files:
packages/thirdweb/src/exports/x402.ts
packages/thirdweb/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
packages/thirdweb/**/*.{ts,tsx}: Every public symbol must have comprehensive TSDoc with at least one compiling@exampleand a custom tag (@beta,@internal,@experimental, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
Lazy‑load heavy dependencies inside async paths (e.g.,const { jsPDF } = await import("jspdf"))
Files:
packages/thirdweb/src/exports/x402.tspackages/thirdweb/src/x402/facilitator.tspackages/thirdweb/src/x402/fetchWithPayment.ts
**/package.json
📄 CodeRabbit inference engine (AGENTS.md)
Track bundle budgets via
package.json#size-limit
Files:
apps/playground-web/package.jsonpackages/thirdweb/package.json
🧠 Learnings (11)
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to .changeset/*.md : Version bump rules: patch for non‑API changes; minor for new/modified public API
Applied to files:
.changeset/sad-hairs-smash.md
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to packages/thirdweb/exports/** : Export all public API via `packages/thirdweb/exports/`, grouped by feature
Applied to files:
packages/thirdweb/src/exports/x402.tspackages/thirdweb/package.json
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to packages/thirdweb/src/exports/** : Export everything via `exports/` directory, grouped by feature in the SDK public API
Applied to files:
packages/thirdweb/src/exports/x402.ts
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to src/exports/react.native.ts : React Native specific exports are in `src/exports/react.native.ts`
Applied to files:
packages/thirdweb/package.json
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout changes.
Applied to files:
apps/playground-web/src/app/payments/x402/page.tsx
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout PR #7888.
Applied to files:
apps/playground-web/src/app/payments/x402/page.tsx
📚 Learning: 2025-08-07T17:24:31.965Z
Learnt from: MananTank
PR: thirdweb-dev/js#7812
File: apps/dashboard/src/app/(app)/team/~/~project/[[...paths]]/page.tsx:1-11
Timestamp: 2025-08-07T17:24:31.965Z
Learning: In Next.js App Router, page components (page.tsx files) are server components by default and do not require the "server-only" import directive. The "server-only" directive is primarily used for utility functions, API helpers, and data access modules that should never be included in the client bundle.
Applied to files:
apps/playground-web/src/app/payments/x402/page.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).
Applied to files:
apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Anything that consumes hooks from `tanstack/react-query` or thirdweb SDKs.
Applied to files:
apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Use React Query (`tanstack/react-query`) for all client data fetching.
Applied to files:
apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
📚 Learning: 2025-09-17T11:02:13.528Z
Learnt from: MananTank
PR: thirdweb-dev/js#8044
File: packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-tokens.ts:15-17
Timestamp: 2025-09-17T11:02:13.528Z
Learning: The thirdweb `client` object is serializable and can safely be used in React Query keys, similar to the `contract` object.
Applied to files:
apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
🧬 Code graph analysis (4)
apps/playground-web/src/middleware.ts (1)
packages/thirdweb/src/x402/facilitator.ts (1)
facilitator(20-56)
packages/thirdweb/src/x402/fetchWithPayment.ts (1)
packages/thirdweb/src/chains/utils.ts (1)
getCachedChain(79-89)
apps/playground-web/src/app/payments/x402/page.tsx (3)
apps/playground-web/src/components/blocks/APIHeader.tsx (1)
PageLayout(49-70)apps/playground-web/src/components/code/code-example.tsx (2)
TabName(58-68)CodeExample(17-56)apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx (1)
X402ClientPreview(22-100)
apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx (2)
apps/playground-web/src/lib/client.ts (1)
THIRDWEB_CLIENT(20-43)packages/thirdweb/src/x402/fetchWithPayment.ts (1)
wrapFetchWithPayment(44-133)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: Size
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: Unit Tests
- GitHub Check: Build Packages
- GitHub Check: Lint Packages
- GitHub Check: Analyze (javascript)
🔇 Additional comments (7)
.changeset/sad-hairs-smash.md (1)
2-5: Minor bump is correct for new public API.Scope looks right for exposing new
thirdweb/x402exports. Consider a slightly more descriptive summary (mention new exports) for changelog clarity.Can you confirm no other publishable packages added/changed public API in this PR?
apps/playground-web/src/app/navLinks.ts (1)
209-212: LGTM: new nav entry wired correctly.Matches the new
/payments/x402page.packages/thirdweb/package.json (1)
43-45: LGTM: add runtime dep on x402.Pinned exact version is good for SDK determinism.
packages/thirdweb/src/exports/x402.ts (1)
1-5: LGTM: x402 surface exported viaexports/barrel.Consistent with SDK export structure.
Please ensure
wrapFetchWithPaymenthas TSDoc with@exampleand a custom tag as well.apps/playground-web/src/middleware.ts (1)
13-30: Guard against missing env to avoid build/runtime crashes. The conditional export (export const middleware = process.env.THIRDWEB_SECRET_KEY && BACKEND_WALLET_ADDRESS ? paymentMiddleware(...) : () => NextResponse.next()) is fully compatible with Next.js’s static middleware detection and with x402-next@^0.5.2. Ensure you’ve enabled Node.js middleware in your Next.js config (experimental.nodeMiddleware: trueandruntime: 'nodejs'inmiddleware.ts) as per the x402-next docs, and note that the current x402-next release is v0.5.2 (not v0.6.x).apps/playground-web/src/app/payments/x402/page.tsx (1)
24-39: Add explicit return types to components.Matches TS guidelines for this repo.
-export default function Page() { +export default function Page(): JSX.Element { @@ -function ServerCodeExample() { +function ServerCodeExample(): JSX.Element { @@ -function X402Example() { +function X402Example(): JSX.Element {Also applies to: 41-96, 98-134
⛔ Skipped due to learnings
Learnt from: CR PR: thirdweb-dev/js#0 File: AGENTS.md:0-0 Timestamp: 2025-08-29T15:37:38.513Z Learning: Applies to **/*.{ts,tsx} : Use explicit function declarations and explicit return types in TypeScriptLearnt from: CR PR: thirdweb-dev/js#0 File: CLAUDE.md:0-0 Timestamp: 2025-07-18T19:19:55.613Z Learning: Applies to **/*.{ts,tsx} : Write idiomatic TypeScript with explicit function declarations and return typesLearnt from: MananTank PR: thirdweb-dev/js#7977 File: apps/playground-web/src/app/page.tsx:61-65 Timestamp: 2025-09-03T23:35:50.476Z Learning: In the thirdweb-dev/js codebase, specifically for React components in **/*.{ts,tsx} files, do not suggest adding explicit return types like `: JSX.Element` or `: React.ReactElement` to function components. The project maintainer MananTank has explicitly declined these suggestions.Learnt from: CR PR: thirdweb-dev/js#0 File: CLAUDE.md:0-0 Timestamp: 2025-07-18T19:19:55.613Z Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Return typed results (e.g., `Project[]`, `User[]`) – avoid `any`Learnt from: CR PR: thirdweb-dev/js#0 File: CLAUDE.md:0-0 Timestamp: 2025-07-18T19:19:55.613Z Learning: Applies to **/*.{ts,tsx} : Comment only ambiguous logic; avoid restating TypeScript in proseLearnt from: CR PR: thirdweb-dev/js#0 File: CLAUDE.md:0-0 Timestamp: 2025-07-18T19:19:55.613Z Learning: Applies to **/*.{ts,tsx} : Avoid `any` and `unknown` unless unavoidable; narrow generics when possibleLearnt from: CR PR: thirdweb-dev/js#0 File: AGENTS.md:0-0 Timestamp: 2025-08-29T15:37:38.513Z Learning: Applies to **/*.{ts,tsx} : Avoid `any` and `unknown` unless unavoidable; narrow generics when possibleLearnt from: CR PR: thirdweb-dev/js#0 File: .cursor/rules/dashboard.mdc:0-0 Timestamp: 2025-07-18T19:20:32.530Z Learning: Applies to dashboard/**/*.{tsx,jsx} : Accept a typed `props` object and export a named function (`export function MyComponent()`).Learnt from: CR PR: thirdweb-dev/js#0 File: CLAUDE.md:0-0 Timestamp: 2025-07-18T19:19:55.613Z Learning: Applies to **/*.{ts,tsx} : Limit each file to one stateless, single-responsibility function for clarityLearnt from: CR PR: thirdweb-dev/js#0 File: CLAUDE.md:0-0 Timestamp: 2025-07-18T19:19:55.613Z Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Server Components (Node edge): Start files with `import "server-only";`apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx (1)
22-26: Add explicit return type.Keep component signatures explicit.
-export function X402ClientPreview() { +export function X402ClientPreview(): JSX.Element {⛔ Skipped due to learnings
Learnt from: CR PR: thirdweb-dev/js#0 File: AGENTS.md:0-0 Timestamp: 2025-08-29T15:37:38.513Z Learning: Applies to **/*.{ts,tsx} : Use explicit function declarations and explicit return types in TypeScriptLearnt from: CR PR: thirdweb-dev/js#0 File: CLAUDE.md:0-0 Timestamp: 2025-07-18T19:19:55.613Z Learning: Applies to **/*.{ts,tsx} : Write idiomatic TypeScript with explicit function declarations and return typesLearnt from: MananTank PR: thirdweb-dev/js#7977 File: apps/playground-web/src/app/page.tsx:61-65 Timestamp: 2025-09-03T23:35:50.476Z Learning: In the thirdweb-dev/js codebase, specifically for React components in **/*.{ts,tsx} files, do not suggest adding explicit return types like `: JSX.Element` or `: React.ReactElement` to function components. The project maintainer MananTank has explicitly declined these suggestions.Learnt from: CR PR: thirdweb-dev/js#0 File: .cursor/rules/dashboard.mdc:0-0 Timestamp: 2025-07-18T19:20:32.530Z Learning: Applies to dashboard/**/*.{tsx,jsx} : Accept a typed `props` object and export a named function (`export function MyComponent()`).Learnt from: CR PR: thirdweb-dev/js#0 File: .cursor/rules/dashboard.mdc:0-0 Timestamp: 2025-07-18T19:20:32.530Z Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).
apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
Show resolved
Hide resolved
2ed6591 to
e0e2b4e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
packages/thirdweb/package.json (1)
423-426: typesVersions mapping added — resolves TS consumers.This addresses the prior request to map
thirdweb/x402types.
🧹 Nitpick comments (9)
apps/playground-web/src/app/api/paywall/route.ts (2)
5-10: Add explicit return type and disable caching.Return type clarity and no-store avoids accidental CDN caching of paid responses.
Apply:
-export async function GET(_req: Request) { - return NextResponse.json({ - success: true, - message: "Congratulations! You have accessed the protected route.", - }); -} +export async function GET( + _req: Request, +): Promise<Response> { + return NextResponse.json( + { + success: true, + message: "Congratulations! You have accessed the protected route.", + }, + { headers: { "Cache-Control": "no-store" } }, + ); +}
3-3: Optional: force dynamic.Being explicit makes intent clear even if defaults change.
export const maxDuration = 300; + +export const dynamic = "force-dynamic";apps/playground-web/src/app/payments/x402/page.tsx (5)
5-7: Prefer path aliases over deep relative imports.Use the existing
@/alias for consistency and easier refactors.-import { PageLayout } from "../../../components/blocks/APIHeader"; -import { createMetadata } from "../../../lib/metadata"; +import { PageLayout } from "@/components/blocks/APIHeader"; +import { createMetadata } from "@/lib/metadata";
24-39: Add explicit return types.Keep to the TS guideline for components.
-export default function Page() { +export default function Page(): JSX.Element {
41-96: Example mismatch: “Server Code Example” shows chat/api/chat, not the paywalled route.Either switch to a paywall example or clarify it’s unrelated. Aligning with
/api/paywallreduces confusion.
98-134: Client code example should demonstrate wrapFetchWithPayment.Header says to wrap fetch with payment, but the snippet shows chat transport. Suggest updating to a minimal, accurate example.
- code={`'use client'; - -import { useChat } from '@ai-sdk/react'; -import { DefaultChatTransport } from 'ai'; -import { useState } from 'react'; -import { ThirdwebAiMessage } from '@thirdweb-dev/ai-sdk-provider'; - -export default function Page() { - const { messages, sendMessage } = useChat<ThirdwebAiMessage>({ - transport: new DefaultChatTransport({ - // see server implementation below - api: '/api/chat', - }), - }); - - return ( - <> - {messages.map(message => ( - <RenderMessage message={message} /> - ))} - <ChatInputBox send={sendMessage} /> - </> - ); -}`} + code={`'use client'; +import { useMutation } from '@tanstack/react-query'; +import { useActiveWallet } from 'thirdweb/react'; +import { wrapFetchWithPayment } from 'thirdweb/x402'; +import { THIRDWEB_CLIENT } from '@/components/thirdweb-provider'; + +export default function Example() { + const wallet = useActiveWallet(); + const payAndCall = useMutation(async () => { + if (!wallet) throw new Error('No active wallet'); + const fetchWithPay = wrapFetchWithPayment(fetch, THIRDWEB_CLIENT, wallet); + const res = await fetchWithPay('/api/paywall'); + return res.json(); + }); + + return ( + <button + onClick={() => payAndCall.mutate()} + disabled={!wallet || payAndCall.isPending} + > + Pay and call API + </button> + ); +}`}
41-41: Add explicit return type to helper components.Same guideline applies to
ServerCodeExampleandX402Example.-function ServerCodeExample() { +function ServerCodeExample(): JSX.Element { @@ -function X402Example() { +function X402Example(): JSX.Element {packages/thirdweb/package.json (1)
43-44: x402 dependency addition looks good — add a size‑limit entry to guard bundle sizepackages/thirdweb has size-limit as a devDependency and a "size" script but no size-limit config; packages/thirdweb/src/exports/x402.ts exports facilitator and wrapFetchWithPayment. Add a size-limit entry for dist/esm/exports/x402.js (in package.json "size-limit" or a .size-limit.json) to track regressions.
apps/playground-web/package.json (1)
51-52: Keep x402-next server-only; add a size-limit budget for the playground
- Verified: x402-next is only imported in apps/playground-web/src/middleware.ts (import { paymentMiddleware } from "x402-next") — file is server-side (no "use client").
- Action: add a size-limit budget for the playground route/component — no "size-limit" key in apps/playground-web/package.json or root and no .size-limit* files; add a "size-limit" entry in apps/playground-web/package.json or a .size-limit file to enforce bundle budgets.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (16)
.changeset/sad-hairs-smash.md(1 hunks)apps/playground-web/package.json(1 hunks)apps/playground-web/src/app/api/paywall/route.ts(1 hunks)apps/playground-web/src/app/navLinks.ts(1 hunks)apps/playground-web/src/app/payments/page.tsx(0 hunks)apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx(1 hunks)apps/playground-web/src/app/payments/x402/page.tsx(1 hunks)apps/playground-web/src/middleware.ts(1 hunks)packages/thirdweb/package.json(3 hunks)packages/thirdweb/src/exports/x402.ts(1 hunks)packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx(1 hunks)packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx(1 hunks)packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx(1 hunks)packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx(1 hunks)packages/thirdweb/src/x402/facilitator.ts(1 hunks)packages/thirdweb/src/x402/fetchWithPayment.ts(1 hunks)
💤 Files with no reviewable changes (1)
- apps/playground-web/src/app/payments/page.tsx
✅ Files skipped from review due to trivial changes (4)
- packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx
- packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx
- packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx
- packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx
🚧 Files skipped from review as they are similar to previous changes (7)
- packages/thirdweb/src/exports/x402.ts
- packages/thirdweb/src/x402/facilitator.ts
- packages/thirdweb/src/x402/fetchWithPayment.ts
- apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
- .changeset/sad-hairs-smash.md
- apps/playground-web/src/app/navLinks.ts
- apps/playground-web/src/middleware.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
**/*.{ts,tsx}: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from@/typeswhere applicable
Prefertypealiases overinterfaceexcept for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size
Files:
apps/playground-web/src/app/api/paywall/route.tsapps/playground-web/src/app/payments/x402/page.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
apps/playground-web/src/app/api/paywall/route.tsapps/playground-web/src/app/payments/x402/page.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
UseNavLinkfor internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()from@/lib/utilsfor conditional class logic
Use design system tokens (e.g.,bg-card,border-border,text-muted-foreground)
Server Components (Node edge): Start files withimport "server-only";
Client Components (browser): Begin files with'use client';
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader – never embed tokens in URLs
Return typed results (e.g.,Project[],User[]) – avoidany
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysfor React Query cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components
Files:
apps/playground-web/src/app/api/paywall/route.tsapps/playground-web/src/app/payments/x402/page.tsx
**/package.json
📄 CodeRabbit inference engine (AGENTS.md)
Track bundle budgets via
package.json#size-limit
Files:
apps/playground-web/package.jsonpackages/thirdweb/package.json
🧠 Learnings (6)
📓 Common learnings
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout changes.
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout changes.
Applied to files:
apps/playground-web/src/app/payments/x402/page.tsx
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout PR #7888.
Applied to files:
apps/playground-web/src/app/payments/x402/page.tsx
📚 Learning: 2025-08-07T17:24:31.965Z
Learnt from: MananTank
PR: thirdweb-dev/js#7812
File: apps/dashboard/src/app/(app)/team/~/~project/[[...paths]]/page.tsx:1-11
Timestamp: 2025-08-07T17:24:31.965Z
Learning: In Next.js App Router, page components (page.tsx files) are server components by default and do not require the "server-only" import directive. The "server-only" directive is primarily used for utility functions, API helpers, and data access modules that should never be included in the client bundle.
Applied to files:
apps/playground-web/src/app/payments/x402/page.tsx
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to packages/thirdweb/exports/** : Export all public API via `packages/thirdweb/exports/`, grouped by feature
Applied to files:
packages/thirdweb/package.json
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to src/exports/react.native.ts : React Native specific exports are in `src/exports/react.native.ts`
Applied to files:
packages/thirdweb/package.json
🧬 Code graph analysis (1)
apps/playground-web/src/app/payments/x402/page.tsx (3)
apps/playground-web/src/components/blocks/APIHeader.tsx (1)
PageLayout(49-70)apps/playground-web/src/components/code/code-example.tsx (2)
TabName(58-68)CodeExample(17-56)apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx (1)
X402ClientPreview(21-102)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Size
- GitHub Check: Unit Tests
🔇 Additional comments (1)
packages/thirdweb/package.json (1)
231-235: New subpath export is correct.Export paths (types/esm/cjs) align with repo conventions.
e0e2b4e to
61c5202
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (3)
packages/thirdweb/package.json (1)
423-426: typesVersions mapping present — resolves prior feedback.The "x402" entry under typesVersions ensures TS resolution for thirdweb/x402.
Optionally validate presence of the source barrel and built d.ts:
#!/bin/bash fd x402.ts packages/thirdweb/src/exports rg -nP 'export\s+\*\s+from\s+"..\/x402\/' packages/thirdweb/src/exports/x402.ts || rg -n 'wrapFetchWithPayment' packages/thirdweb/src/exports/x402.tspackages/thirdweb/src/x402/fetchWithPayment.ts (2)
14-52: Missing required TSDoc stability tag.Per package guidelines, add a stability tag (e.g., @beta) to public APIs.
/** * Enables the payment of APIs using the x402 payment protocol. @@ * @returns A wrapped fetch function that handles 402 responses automatically + * @beta * * @example#!/bin/bash rg -nP '@beta|@experimental|@internal' packages/thirdweb/src/x402/fetchWithPayment.ts -n
53-59: Add explicit return type to exported wrapper.Makes the public surface stable and aligns with repo rules.
+type FetchLike = (input: RequestInfo, init?: RequestInit) => Promise<Response>; + export function wrapFetchWithPayment( fetch: typeof globalThis.fetch, client: ThirdwebClient, wallet: Wallet, maxValue: bigint = BigInt(1 * 10 ** 6), // Default to 1 USDC -) { +): FetchLike {
🧹 Nitpick comments (3)
packages/thirdweb/src/x402/fetchWithPayment.ts (3)
66-73: Be tolerant to mixed/invalid accepts entries.Use safeParse to skip unknown items instead of throwing on the first invalid entry.
- const parsedPaymentRequirements = accepts - .map((x) => PaymentRequirementsSchema.parse(x)) - .filter((x) => x.scheme === "exact"); // TODO (402): accept other schemes + const parsedPaymentRequirements = accepts + .map((x) => PaymentRequirementsSchema.safeParse(x)) + .filter((r) => r.success) + .map((r) => r.data) + .filter((x) => x.scheme === "exact"); // TODO (402): accept other schemes
82-90: Amount guard message could include details.Include required vs max values to aid debugging.
- throw new Error("Payment amount exceeds maximum allowed"); + throw new Error( + `Payment amount ${selectedPaymentRequirements.maxAmountRequired} exceeds maximum allowed ${maxValue.toString()}`, + );
59-64: Make retries body-safe by cloning the RequestCreate a base Request from the incoming args (clone if input is a Request, else new Request(input, init || {})); call fetch(baseReq.clone()) for the first attempt and construct the paid retry from baseReq so one-shot bodies (ReadableStream) can be resent. Preserve the existing __is402Retry flag and the Access-Control-Expose-Headers behavior (see lines ~125, 134–136).
- return async (input: RequestInfo, init?: RequestInit) => { - const response = await fetch(input, init); + return async (input: RequestInfo, init?: RequestInit) => { + const initParams = init || {}; + const baseReq = input instanceof Request ? input.clone() : new Request(input, initParams); + const response = await fetch(baseReq.clone()); @@ - const secondResponse = await fetch(input, newInit); + const paidRequest = new Request(baseReq, { ...newInit, headers: newInit.headers as Headers }); + const secondResponse = await fetch(paidRequest); return secondResponse;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (18)
.changeset/sad-hairs-smash.md(1 hunks)apps/playground-web/package.json(1 hunks)apps/playground-web/src/app/api/paywall/route.ts(1 hunks)apps/playground-web/src/app/navLinks.ts(1 hunks)apps/playground-web/src/app/payments/page.tsx(0 hunks)apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx(1 hunks)apps/playground-web/src/app/payments/x402/page.tsx(1 hunks)apps/playground-web/src/middleware.ts(1 hunks)apps/portal/src/app/payments/sidebar.tsx(1 hunks)apps/portal/src/app/payments/x402/page.mdx(1 hunks)packages/thirdweb/package.json(3 hunks)packages/thirdweb/src/exports/x402.ts(1 hunks)packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx(1 hunks)packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx(1 hunks)packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx(1 hunks)packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx(1 hunks)packages/thirdweb/src/x402/facilitator.ts(1 hunks)packages/thirdweb/src/x402/fetchWithPayment.ts(1 hunks)
💤 Files with no reviewable changes (1)
- apps/playground-web/src/app/payments/page.tsx
✅ Files skipped from review due to trivial changes (4)
- apps/portal/src/app/payments/x402/page.mdx
- packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx
- .changeset/sad-hairs-smash.md
- packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx
🚧 Files skipped from review as they are similar to previous changes (9)
- packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx
- apps/playground-web/src/app/api/paywall/route.ts
- apps/playground-web/package.json
- apps/playground-web/src/middleware.ts
- packages/thirdweb/src/exports/x402.ts
- packages/thirdweb/src/x402/facilitator.ts
- apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
- apps/playground-web/src/app/navLinks.ts
- packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
**/*.{ts,tsx}: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from@/typeswhere applicable
Prefertypealiases overinterfaceexcept for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size
Files:
apps/portal/src/app/payments/sidebar.tsxpackages/thirdweb/src/x402/fetchWithPayment.tsapps/playground-web/src/app/payments/x402/page.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
apps/portal/src/app/payments/sidebar.tsxpackages/thirdweb/src/x402/fetchWithPayment.tsapps/playground-web/src/app/payments/x402/page.tsx
packages/thirdweb/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
packages/thirdweb/**/*.{ts,tsx}: Every public symbol must have comprehensive TSDoc with at least one compiling@exampleand a custom tag (@beta,@internal,@experimental, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
Lazy‑load heavy dependencies inside async paths (e.g.,const { jsPDF } = await import("jspdf"))
Files:
packages/thirdweb/src/x402/fetchWithPayment.ts
apps/{dashboard,playground-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
UseNavLinkfor internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()from@/lib/utilsfor conditional class logic
Use design system tokens (e.g.,bg-card,border-border,text-muted-foreground)
Server Components (Node edge): Start files withimport "server-only";
Client Components (browser): Begin files with'use client';
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader – never embed tokens in URLs
Return typed results (e.g.,Project[],User[]) – avoidany
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysfor React Query cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components
Files:
apps/playground-web/src/app/payments/x402/page.tsx
**/package.json
📄 CodeRabbit inference engine (AGENTS.md)
Track bundle budgets via
package.json#size-limit
Files:
packages/thirdweb/package.json
🧠 Learnings (5)
📓 Common learnings
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout changes.
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout PR #7888.
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout changes.
Applied to files:
apps/portal/src/app/payments/sidebar.tsxapps/playground-web/src/app/payments/x402/page.tsx
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout PR #7888.
Applied to files:
apps/portal/src/app/payments/sidebar.tsxapps/playground-web/src/app/payments/x402/page.tsx
📚 Learning: 2025-08-07T17:24:31.965Z
Learnt from: MananTank
PR: thirdweb-dev/js#7812
File: apps/dashboard/src/app/(app)/team/~/~project/[[...paths]]/page.tsx:1-11
Timestamp: 2025-08-07T17:24:31.965Z
Learning: In Next.js App Router, page components (page.tsx files) are server components by default and do not require the "server-only" import directive. The "server-only" directive is primarily used for utility functions, API helpers, and data access modules that should never be included in the client bundle.
Applied to files:
apps/playground-web/src/app/payments/x402/page.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to src/exports/react.native.ts : React Native specific exports are in `src/exports/react.native.ts`
Applied to files:
packages/thirdweb/package.json
🧬 Code graph analysis (2)
packages/thirdweb/src/x402/fetchWithPayment.ts (2)
packages/thirdweb/src/exports/x402.ts (1)
wrapFetchWithPayment(5-5)packages/thirdweb/src/chains/utils.ts (1)
getCachedChain(79-89)
apps/playground-web/src/app/payments/x402/page.tsx (3)
apps/playground-web/src/components/blocks/APIHeader.tsx (1)
PageLayout(49-70)apps/playground-web/src/components/code/code-example.tsx (2)
TabName(58-68)CodeExample(17-56)apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx (1)
X402ClientPreview(21-102)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Size
- GitHub Check: Lint Packages
- GitHub Check: Analyze (javascript)
🔇 Additional comments (5)
apps/portal/src/app/payments/sidebar.tsx (1)
64-67: Add x402 guide link — looks good.Entry is consistent with existing slugs and placement under Guides.
packages/thirdweb/package.json (2)
231-235: New subpath export "./x402" wired correctly.Types/ESM/CJS paths match repo conventions.
43-43: Pinning [email protected] is fine — no action required.
apps/playground-web has "x402-next": "^0.6.1" and packages/thirdweb pins "x402": "0.6.1"; versions align.apps/playground-web/src/app/payments/x402/page.tsx (2)
24-39: Page scaffold and metadata — solid.Server component wrapping client preview via provider/layout follows app patterns.
97-126: Client example snippet — minimal and clear.Matches the live preview usage of wrapFetchWithPayment.
| function ServerCodeExample() { | ||
| return ( | ||
| <> | ||
| <div className="mb-4"> | ||
| <h2 className="font-semibold text-xl tracking-tight"> | ||
| Next.js Server Code Example | ||
| </h2> | ||
| <p className="max-w-4xl text-muted-foreground text-balance text-sm md:text-base"> | ||
| Use any x402 middleware + the thirdweb facilitator to settle | ||
| transactions with our server wallet. | ||
| </p> | ||
| </div> | ||
| <div className="overflow-hidden rounded-lg border bg-card"> | ||
| <div className="flex grow flex-col border-b md:border-r md:border-b-0"> | ||
| <TabName icon={Code2Icon} name="Server Code" /> | ||
| <CodeServer | ||
| className="h-full rounded-none border-none" | ||
| code={`// src/middleware.ts | ||
| import { facilitator } from "thirdweb/x402"; | ||
| import { createThirdwebClient } from "thirdweb"; | ||
| import { paymentMiddleware } from "x402-next"; | ||
| const client = createThirdwebClient({ secretKey: "your-secret-key" }); | ||
| export const middleware = paymentMiddleware( | ||
| "0xYourWalletAddress", | ||
| { | ||
| "/api/paid-endpoint": { | ||
| price: "$0.01", | ||
| network: "base-sepolia", | ||
| config: { | ||
| description: "Access to paid content", | ||
| }, | ||
| }, | ||
| }, | ||
| facilitator({ | ||
| client, | ||
| serverWalletAddress: "0xYourServerWalletAddress", | ||
| }), | ||
| ); | ||
| // Configure which paths the middleware should run on | ||
| export const config = { | ||
| matcher: ["/api/paid-endpoint"], | ||
| }; | ||
| `} | ||
| lang="tsx" | ||
| /> | ||
| </div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
🧩 Analysis chain
Align server example route with the actual demo endpoint.
Preview calls “/api/paywall”, but the server snippet uses “/api/paid-endpoint”. Align to avoid copy-paste errors.
Apply this diff inside the example string:
- "/api/paid-endpoint": {
+ "/api/paywall": {
@@
-export const config = {
- matcher: ["/api/paid-endpoint"],
-};
+export const config = {
+ matcher: ["/api/paywall"],
+};Also confirm the paymentMiddleware signature (recipient vs server wallet) matches x402-next docs.
🏁 Script executed:
#!/bin/bash
rg -nP 'export\s+const\s+middleware\s*=\s*paymentMiddleware\(' apps/playground-web/src/middleware.ts -n -C3Length of output: 264
Align server example route with the actual demo endpoint.
Update the snippet in apps/playground-web/src/app/payments/x402/page.tsx to use /api/paywall:
- "/api/paid-endpoint": {
+ "/api/paywall": {
@@
-export const config = {
- matcher: ["/api/paid-endpoint"],
-};
+export const config = {
+ matcher: ["/api/paywall"],
+};The paymentMiddleware(payTo, routes, facilitator) signature already matches the x402-next docs.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| function ServerCodeExample() { | |
| return ( | |
| <> | |
| <div className="mb-4"> | |
| <h2 className="font-semibold text-xl tracking-tight"> | |
| Next.js Server Code Example | |
| </h2> | |
| <p className="max-w-4xl text-muted-foreground text-balance text-sm md:text-base"> | |
| Use any x402 middleware + the thirdweb facilitator to settle | |
| transactions with our server wallet. | |
| </p> | |
| </div> | |
| <div className="overflow-hidden rounded-lg border bg-card"> | |
| <div className="flex grow flex-col border-b md:border-r md:border-b-0"> | |
| <TabName icon={Code2Icon} name="Server Code" /> | |
| <CodeServer | |
| className="h-full rounded-none border-none" | |
| code={`// src/middleware.ts | |
| import { facilitator } from "thirdweb/x402"; | |
| import { createThirdwebClient } from "thirdweb"; | |
| import { paymentMiddleware } from "x402-next"; | |
| const client = createThirdwebClient({ secretKey: "your-secret-key" }); | |
| export const middleware = paymentMiddleware( | |
| "0xYourWalletAddress", | |
| { | |
| "/api/paid-endpoint": { | |
| price: "$0.01", | |
| network: "base-sepolia", | |
| config: { | |
| description: "Access to paid content", | |
| }, | |
| }, | |
| }, | |
| facilitator({ | |
| client, | |
| serverWalletAddress: "0xYourServerWalletAddress", | |
| }), | |
| ); | |
| // Configure which paths the middleware should run on | |
| export const config = { | |
| matcher: ["/api/paid-endpoint"], | |
| }; | |
| `} | |
| lang="tsx" | |
| /> | |
| </div> | |
| function ServerCodeExample() { | |
| return ( | |
| <> | |
| <div className="mb-4"> | |
| <h2 className="font-semibold text-xl tracking-tight"> | |
| Next.js Server Code Example | |
| </h2> | |
| <p className="max-w-4xl text-muted-foreground text-balance text-sm md:text-base"> | |
| Use any x402 middleware + the thirdweb facilitator to settle | |
| transactions with our server wallet. | |
| </p> | |
| </div> | |
| <div className="overflow-hidden rounded-lg border bg-card"> | |
| <div className="flex grow flex-col border-b md:border-r md:border-b-0"> | |
| <TabName icon={Code2Icon} name="Server Code" /> | |
| <CodeServer | |
| className="h-full rounded-none border-none" | |
| code={`// src/middleware.ts | |
| import { facilitator } from "thirdweb/x402"; | |
| import { createThirdwebClient } from "thirdweb"; | |
| import { paymentMiddleware } from "x402-next"; | |
| const client = createThirdwebClient({ secretKey: "your-secret-key" }); | |
| export const middleware = paymentMiddleware( | |
| "0xYourWalletAddress", | |
| { | |
| "/api/paywall": { | |
| price: "$0.01", | |
| network: "base-sepolia", | |
| config: { | |
| description: "Access to paid content", | |
| }, | |
| }, | |
| }, | |
| facilitator({ | |
| client, | |
| serverWalletAddress: "0xYourServerWalletAddress", | |
| }), | |
| ); | |
| // Configure which paths the middleware should run on | |
| export const config = { | |
| matcher: ["/api/paywall"], | |
| }; | |
| `} | |
| lang="tsx" | |
| /> | |
| </div> |
🤖 Prompt for AI Agents
In apps/playground-web/src/app/payments/x402/page.tsx around lines 41 to 91, the
embedded server example uses the route "/api/paid-endpoint" but the demo expects
"/api/paywall"; update the code snippet so the routes object key and the matcher
both use "/api/paywall" (replace "/api/paid-endpoint" occurrences with
"/api/paywall") and ensure the comment or surrounding text remains consistent
with the change.

PR-Codex overview
This PR focuses on integrating the
x402payment protocol into the application, enabling users to make paid API calls using microtransactions. It includes updates to various components to support this new functionality.Detailed summary
x402payment protocol support in multiple files.page.tsxinpayments/x402to include client-side examples.facilitatorandwrapFetchWithPaymentfunctions inx402for handling payments.middleware.tsto include payment processing.x402option.package.jsonfiles to include new dependencies forx402-nextand related packages.X402ClientPreviewcomponent for user interaction with the payment API.Summary by CodeRabbit
New Features
Documentation
Refactor
Chores