Skip to content

Conversation

@joaquim-verges
Copy link
Member

@joaquim-verges joaquim-verges commented Sep 19, 2025


PR-Codex overview

This PR focuses on integrating the x402 payment 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

  • Added x402 payment protocol support in multiple files.
  • Updated page.tsx in payments/x402 to include client-side examples.
  • Implemented facilitator and wrapFetchWithPayment functions in x402 for handling payments.
  • Enhanced middleware in middleware.ts to include payment processing.
  • Modified navigation links and sidebar to include the x402 option.
  • Updated package.json files to include new dependencies for x402-next and related packages.
  • Created a new X402ClientPreview component for user interaction with the payment API.

The following files were skipped due to too many changes: pnpm-lock.yaml

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • New Features

    • Added an x402 Payments playground with client/server examples, live client preview, and a paid API-call demo.
    • Added a paywalled API endpoint and site middleware to enable a $0.01 paywall flow.
    • Added “x402” links in Payments navigation and sidebar.
  • Documentation

    • Added an x402 docs page with copyable examples and usage guidance.
  • Refactor

    • Removed the legacy Payments overview page.
  • Chores

    • Bumped package versions and added x402 runtime deps and public exports.

@vercel
Copy link

vercel bot commented Sep 19, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
docs-v2 Ready Ready Preview Comment Sep 19, 2025 11:45am
nebula Ready Ready Preview Comment Sep 19, 2025 11:45am
thirdweb_playground Ready Ready Preview Comment Sep 19, 2025 11:45am
thirdweb-www Ready Ready Preview Comment Sep 19, 2025 11:45am
wallet-ui Ready Ready Preview Comment Sep 19, 2025 11:45am

@changeset-bot
Copy link

changeset-bot bot commented Sep 19, 2025

🦋 Changeset detected

Latest commit: 61c5202

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
thirdweb Minor
@thirdweb-dev/nebula Patch
@thirdweb-dev/wagmi-adapter Patch

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 19, 2025

Walkthrough

Adds 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

Cohort / File(s) Summary
Repo metadata
./.changeset/sad-hairs-smash.md
Adds a changeset bumping thirdweb (minor) with note "x402 utilities".
Playground Web — deps & nav
apps/playground-web/package.json, apps/playground-web/src/app/navLinks.ts
Adds dependency x402-next@^0.6.1. Adds Payments submenu link { href: "/payments/x402", label: "x402" }.
Playground Web — removed page
apps/playground-web/src/app/payments/page.tsx (deleted)
Removes legacy Payments overview page (default export Page).
Playground Web — x402 page & preview
apps/playground-web/src/app/payments/x402/page.tsx, apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
Adds x402 playground page with metadata, client/server code examples, and a client-side X402ClientPreview component that connects a wallet and performs paid API calls via wrapFetchWithPayment.
Playground Web — API route & middleware
apps/playground-web/src/app/api/paywall/route.ts, apps/playground-web/src/middleware.ts
Adds GET /api/paywall (exports maxDuration = 300) returning static JSON. Adds paymentMiddleware wired to /api/paywall using a facilitator configured from env vars; exports middleware and config.matcher.
thirdweb package — package metadata & exports
packages/thirdweb/package.json, packages/thirdweb/src/exports/x402.ts
Adds runtime dependency [email protected]. Adds public export path ./x402. Adds barrel export re-exporting facilitator, ThirdwebX402FacilitatorConfig type, and wrapFetchWithPayment.
thirdweb package — x402 facilitator
packages/thirdweb/src/x402/facilitator.ts
New ThirdwebX402FacilitatorConfig type and facilitator(config) that validates config and returns a FacilitatorConfig producing auth headers and base URL for x402 API (supports vault token header).
thirdweb package — fetch-with-payment
packages/thirdweb/src/x402/fetchWithPayment.ts
New wrapFetchWithPayment(fetch, client, wallet, maxValue?) that handles 402 responses: parses requirements, selects requirement, validates amount, resolves chain and signer, builds payment header, retries request with X-PAYMENT header, and surfaces errors for missing wallet/chain/requirements/exceeded limits.
Docs/comments (JSDoc tags)
packages/thirdweb/src/react/web/ui/Bridge/*
Minor JSDoc tag adjustments (@bridge Widgets@bridge) in several Bridge widget files; no runtime changes.
Portal — sidebar & docs
apps/portal/src/app/payments/sidebar.tsx, apps/portal/src/app/payments/x402/page.mdx
Adds Payments sidebar link to /payments/x402. Adds MDX docs describing x402 client/server workflows and examples.

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
Loading
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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title "[SDK] Add x402 payment protocol utilities" is concise, follows the repository prefix convention, and accurately summarizes the primary change (adding x402 payment utilities across the SDK and playground). It is a single clear sentence without noise and will be understandable to teammates scanning PR history.
Description Check ✅ Passed The PR description contains the repository template (left as a comment) plus a detailed PR-Codex overview that documents objectives, file-level changes, and the x402 integration, so reviewers can see what changed and why; however the explicit template sections "Notes for the reviewer" and "How to test" remain as placeholders and do not provide concrete testing steps or reviewer guidance. Because the technical details and file summaries are present, the description is mostly complete for a code review but would benefit from actionable testing instructions.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch _SDK_Add_x402_payment_protocol_utilities

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • TEAM-0000: Entity not found: Issue - Could not find referenced Issue.

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added Playground Changes involving the Playground codebase. packages SDK Involves changes to the thirdweb SDK labels Sep 19, 2025
Copy link
Member Author


How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • merge-queue - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

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.

@socket-security
Copy link

socket-security bot commented Sep 19, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedx402-next@​0.6.1751009995100
Addedx402@​0.6.1901009196100

View full report

@github-actions
Copy link
Contributor

github-actions bot commented Sep 19, 2025

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
thirdweb (esm) 63.96 KB (0%) 1.3 s (0%) 214 ms (+318.71% 🔺) 1.5 s
thirdweb (cjs) 361.44 KB (0%) 7.3 s (0%) 627 ms (+27.75% 🔺) 7.9 s
thirdweb (minimal + tree-shaking) 5.73 KB (0%) 115 ms (0%) 88 ms (+1514.68% 🔺) 202 ms
thirdweb/chains (tree-shaking) 526 B (0%) 11 ms (0%) 52 ms (+3614.57% 🔺) 62 ms
thirdweb/react (minimal + tree-shaking) 19.14 KB (0%) 383 ms (0%) 101 ms (+2746.42% 🔺) 484 ms

@codecov
Copy link

codecov bot commented Sep 19, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 56.34%. Comparing base (7b8ceeb) to head (61c5202).
⚠️ Report is 3 commits behind head on main.

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              
Flag Coverage Δ
packages 56.34% <ø> (-0.01%) ⬇️
Files with missing lines Coverage Δ
...ges/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx 9.03% <ø> (ø)

... and 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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: Add x402 entry to typesVersions
The typesVersions block in packages/thirdweb/package.json is missing the "x402" mapping. Without it, TypeScript won’t resolve the generated declarations. Add:

"x402": ["./dist/types/exports/x402.d.ts"]

under the "*" key in typesVersions.

🧹 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 1d90437 and 8089774.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is 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 @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless 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 @/types where applicable
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless 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.ts
  • apps/playground-web/src/middleware.ts
  • packages/thirdweb/src/exports/x402.ts
  • packages/thirdweb/src/x402/facilitator.ts
  • packages/thirdweb/src/x402/fetchWithPayment.ts
  • apps/playground-web/src/app/navLinks.ts
  • apps/playground-web/src/app/payments/x402/page.tsx
  • apps/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.ts
  • apps/playground-web/src/middleware.ts
  • packages/thirdweb/src/exports/x402.ts
  • packages/thirdweb/src/x402/facilitator.ts
  • packages/thirdweb/src/x402/fetchWithPayment.ts
  • apps/playground-web/src/app/navLinks.ts
  • apps/playground-web/src/app/payments/x402/page.tsx
  • apps/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
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() from @/lib/utils for conditional class logic
Use design system tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components (Node edge): Start files with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components

Files:

  • apps/playground-web/src/app/api/paywall/route.ts
  • apps/playground-web/src/middleware.ts
  • apps/playground-web/src/app/navLinks.ts
  • apps/playground-web/src/app/payments/x402/page.tsx
  • apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
.changeset/*.md

📄 CodeRabbit inference engine (AGENTS.md)

.changeset/*.md: Each change in packages/* 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 via exports/ directory, grouped by feature in the SDK public API
Every public symbol must have comprehensive TSDoc with at least one @example block 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 @example and 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.ts
  • packages/thirdweb/src/x402/facilitator.ts
  • packages/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.json
  • packages/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.ts
  • 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 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/x402 exports. 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/x402 page.

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 via exports/ barrel.

Consistent with SDK export structure.

Please ensure wrapFetchWithPayment has TSDoc with @example and 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: true and runtime: 'nodejs' in middleware.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 TypeScript
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} : Write idiomatic TypeScript with explicit function declarations and return types
Learnt 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 prose
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} : Avoid `any` and `unknown` unless unavoidable; narrow generics when possible
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} : Avoid `any` and `unknown` unless unavoidable; narrow generics when possible
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: 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 clarity
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} : 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 TypeScript
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} : Write idiomatic TypeScript with explicit function declarations and return types
Learnt 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).

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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/x402 types.

🧹 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/paywall reduces 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 ServerCodeExample and X402Example.

-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 size

packages/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.

📥 Commits

Reviewing files that changed from the base of the PR and between 8089774 and e0e2b4e.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is 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 @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless 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 @/types where applicable
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless 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.ts
  • apps/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.ts
  • apps/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
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() from @/lib/utils for conditional class logic
Use design system tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components (Node edge): Start files with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components

Files:

  • apps/playground-web/src/app/api/paywall/route.ts
  • 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:

  • apps/playground-web/package.json
  • packages/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.

@joaquim-verges joaquim-verges force-pushed the _SDK_Add_x402_payment_protocol_utilities branch from e0e2b4e to 61c5202 Compare September 19, 2025 11:31
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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.ts
packages/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 Request

Create 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.

📥 Commits

Reviewing files that changed from the base of the PR and between e0e2b4e and 61c5202.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is 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 @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless 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 @/types where applicable
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless 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.tsx
  • packages/thirdweb/src/x402/fetchWithPayment.ts
  • apps/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.tsx
  • packages/thirdweb/src/x402/fetchWithPayment.ts
  • apps/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 @example and 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
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() from @/lib/utils for conditional class logic
Use design system tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components (Node edge): Start files with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in 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.tsx
  • 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/portal/src/app/payments/sidebar.tsx
  • 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: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.

Comment on lines +41 to +91
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>
Copy link
Contributor

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 -C3

Length 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.

Suggested change
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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

packages Playground Changes involving the Playground codebase. Portal Involves changes to the Portal (docs) codebase. SDK Involves changes to the thirdweb SDK

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant