Skip to content

Conversation

@MananTank
Copy link
Member

@MananTank MananTank commented Dec 19, 2025


PR-Codex overview

This PR focuses on enhancing the CheckoutWidget and related components by removing redundant UI elements, introducing new constants, and improving the handling of query parameters for better validation and functionality in the checkout process.

Detailed summary

  • Removed fiat price duplication in the CheckoutWidget.
  • Added NEXT_PUBLIC_CHECKOUT_IFRAME_CLIENT_ID constant.
  • Implemented parseQueryParams utility for better parameter handling.
  • Introduced isValidCurrency function to validate currencies.
  • Updated CheckoutWidgetEmbed to use new constants and improved logic.
  • Enhanced error handling for required parameters in the checkout page.
  • Modified tests to skip certain cases and ensure proper execution.

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

Summary by CodeRabbit

  • New Features

    • Embeddable checkout widget with a dedicated checkout page and layout; new public env var for iframe client ID.
    • Content-Security-Policy headers applied to checkout widget routes.
  • Bug Fixes

    • Removed duplicate fiat price display in the checkout button.
  • Chores / Refactor

    • Centralized query-parameter parsing and currency validation; added input sanitization utilities.
    • Added a patch-level changeset entry.
  • Tests

    • Several integration tests marked skipped by default; one parallel-execution test enabled.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Dec 19, 2025

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

Project Deployment Review Updated (UTC)
docs-v2 Ready Ready Preview, Comment Dec 19, 2025 7:40pm
nebula Ready Ready Preview, Comment Dec 19, 2025 7:40pm
thirdweb_playground Ready Ready Preview, Comment Dec 19, 2025 7:40pm
thirdweb-www Ready Ready Preview, Comment Dec 19, 2025 7:40pm
wallet-ui Ready Ready Preview, Comment Dec 19, 2025 7:40pm

@MananTank MananTank marked this pull request as ready for review December 19, 2025 17:18
@MananTank MananTank requested review from a team as code owners December 19, 2025 17:19
@linear
Copy link

linear bot commented Dec 19, 2025

@changeset-bot
Copy link

changeset-bot bot commented Dec 19, 2025

🦋 Changeset detected

Latest commit: fdd2557

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

This PR includes changesets to release 4 packages
Name Type
thirdweb Patch
@thirdweb-dev/nebula Patch
@thirdweb-dev/wagmi-adapter Patch
wagmi-inapp 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

@github-actions github-actions bot added Dashboard Involves changes to the Dashboard. packages SDK Involves changes to the thirdweb SDK labels Dec 19, 2025
Copy link
Member Author

MananTank commented Dec 19, 2025


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.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 19, 2025

Walkthrough

Adds a Checkout Widget iframe feature with CSP headers and a public env var; new query parsing and currency-validation utilities; embed client, layout, and page for the checkout iframe; refactors bridge widget to use utilities; removes inline fiat display from buy button; and updates smart-wallet test suites to be skipped/modified.

Changes

Cohort / File(s) Summary
Configuration & Environment
apps/dashboard/next.config.ts, apps/dashboard/src/@/constants/public-envs.ts
Added CSP header entries for /bridge/checkout-widget routes and exported NEXT_PUBLIC_CHECKOUT_IFRAME_CLIENT_ID.
Query Parameter Utilities
apps/dashboard/src/app/bridge/_common/isValidCurrency.ts, apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
New isValidCurrency type guard and parseQueryParams<T> plus onlyAddress/onlyNumber helpers for sanitized query parsing.
Checkout Widget Embed & Pages
apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx, apps/dashboard/src/app/bridge/checkout-widget/layout.tsx, apps/dashboard/src/app/bridge/checkout-widget/page.tsx
Added client-side CheckoutWidgetEmbed (posts success/error via postMessage), a minimal embed layout, and a page that validates query params and renders the embed inside Providers using NEXT_PUBLIC_CHECKOUT_IFRAME_CLIENT_ID.
Bridge Widget Refactor
apps/dashboard/src/app/bridge/widget/page.tsx
Replaced inline query parsing/validation with centralized parseQueryParams and isValidCurrency.
UI Updates (Buy Button)
packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
Removed inline fiat price display from the buy button; shows buttonLabel if provided, otherwise "Buy Now".
Tests
packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts, packages/thirdweb/src/wallets/smart/smart-wallet-integration-v07.test.ts, packages/thirdweb/src/wallets/smart/smart-wallet-modular.test.ts
Converted several smart-wallet test suites to describe.skip.sequential(...) (unconditional skip) and toggled some tests between it and it.skip.
Release Documentation
.changeset/short-wasps-show.md
Added patch changeset noting removal of fiat price in CheckoutWidget button.

Sequence Diagram(s)

sequenceDiagram
    participant Browser
    participant NextJS as Next.js Page
    participant Providers as BridgeProviders
    participant Thirdweb as Thirdweb Client/Widget

    Note over Browser,NextJS: Request to /bridge/checkout-widget with query params
    Browser->>NextJS: GET /bridge/checkout-widget?...
    NextJS->>NextJS: parseQueryParams + isValidCurrency
    alt invalid or missing required params
        NextJS-->>Browser: render error UI
    else valid params
        NextJS->>Providers: initialize (uses NEXT_PUBLIC_CHECKOUT_IFRAME_CLIENT_ID)
        Providers->>Thirdweb: create configured iframe client
        NextJS-->>Browser: render CheckoutWidgetEmbed (client component)
        Browser->>Thirdweb: widget initializes (iframe)
        Thirdweb-->>Browser: postMessage(success/error) [source: "checkout-widget"]
        Browser->>NextJS: (parent) receives postMessage event
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Inspect parseQueryParams and isValidCurrency for edge-case validation and type-safety.
  • Verify checkout-widget/page.tsx handles missing NEXT_PUBLIC_CHECKOUT_IFRAME_CLIENT_ID safely and that Providers initialization is correct.
  • Review CSP entries in apps/dashboard/next.config.ts for correctness and coverage of routes.
  • Confirm CheckoutWidgetEmbed.client.tsx postMessage payloads and error handling are appropriate and secure.
  • Check DirectPayment.tsx button change for layout and accessibility regressions.
  • Verify test-suite skips/changes reflect intended CI/test strategy.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 3 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ❓ Inconclusive The PR description includes the repository template structure but lacks specific details. It relies heavily on an auto-generated PR-Codex summary instead of providing detailed manual documentation about the changes, testing approach, or implementation notes. Expand the description with specific implementation details, testing instructions, and reviewer notes beyond the auto-generated summary. Address the 'How to test' section explicitly.
Linked Issues check ❓ Inconclusive The linked issue (MNY-343) provides only a title with no detailed objectives, making comprehensive validation difficult. However, the PR title and summary align with adding a checkout widget iframe. Provide detailed requirements in the linked issue or clarify specific coding objectives that this PR should accomplish beyond the iframe addition.
Out of Scope Changes check ❓ Inconclusive The PR includes changes to test files (skipping/enabling tests in smart-wallet tests) that appear tangential to the main checkout widget iframe feature and lack clear justification in the PR description. Clarify the purpose of test modifications in smart-wallet tests and confirm they are necessary for the checkout widget iframe functionality.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title '[MNY-343] Add checkout widget iframe' is clear, concise, and accurately reflects the main objective of adding a checkout widget iframe as described in the PR objectives.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mny-343

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.

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

🧹 Nitpick comments (5)
apps/dashboard/src/app/bridge/checkout-widget/layout.tsx (1)

15-26: Consider adding basic <head> elements for proper document structure.

The layout renders <html> and <body> but omits a <head> with essential meta tags like <meta charset="utf-8"> and <meta name="viewport">. Even for iframe embeds, these ensure consistent rendering across browsers.

🔎 Suggested improvement
     return (
       <html lang="en" suppressHydrationWarning>
+        <head>
+          <meta charSet="utf-8" />
+          <meta name="viewport" content="width=device-width, initial-scale=1" />
+        </head>
         <body
           className={cn(
             "min-h-dvh bg-background font-sans antialiased flex flex-col",
             fontSans.variable,
           )}
         >
           {children}
         </body>
       </html>
     );
apps/dashboard/src/app/bridge/_common/isValidCurrency.ts (1)

3-10: Consider simplifying the type guard and reordering declarations.

The function works correctly, but could be more concise. Also, moving VALID_CURRENCIES before its usage improves readability.

🔎 Suggested simplification
 import type { SupportedFiatCurrency } from "thirdweb/react";
 
+const VALID_CURRENCIES: Record<SupportedFiatCurrency, true> = {
+  USD: true,
+  EUR: true,
+  // ... rest of currencies
+};
+
 export function isValidCurrency(
   currency: string,
 ): currency is SupportedFiatCurrency {
-  if (currency in VALID_CURRENCIES) {
-    return true;
-  }
-  return false;
+  return currency in VALID_CURRENCIES;
 }
-
-const VALID_CURRENCIES: Record<SupportedFiatCurrency, true> = {
-  // ...
-};
apps/dashboard/src/app/bridge/checkout-widget/page.tsx (2)

1-14: Missing import "server-only"; directive.

Per coding guidelines, server component files should start with import "server-only"; to prevent accidental client bundling. This is an async server component that reads searchParams.

🔎 Proposed fix
 import type { Metadata } from "next";
+import "server-only";
 import "@workspace/ui/global.css";

45-49: Variable title shadows module-level constant.

The local variable title on line 45 shadows the module-level title constant defined on line 16. This could cause confusion. Consider renaming to productTitle or similar.

🔎 Proposed fix
-  const title = parseQueryParams(searchParams.title, (v) => v);
+  const productTitle = parseQueryParams(searchParams.title, (v) => v);

Then update the usage on line 119:

-          name={title}
+          name={productTitle}
apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx (1)

49-50: ESLint disable comment.

The // eslint-disable-next-line no-restricted-syntax suggests defineChain usage is restricted. If this is intentional for the widget context, the comment should briefly explain why the exception is needed.

-  // eslint-disable-next-line no-restricted-syntax
+  // eslint-disable-next-line no-restricted-syntax -- defineChain needed for dynamic chain resolution from query params
   const chain = useMemo(() => defineChain(chainId), [chainId]);
📜 Review details

Configuration used: Organization 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 56a1c0a and e730eb5.

📒 Files selected for processing (10)
  • .changeset/short-wasps-show.md (1 hunks)
  • apps/dashboard/next.config.ts (1 hunks)
  • apps/dashboard/src/@/constants/public-envs.ts (1 hunks)
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts (1 hunks)
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts (1 hunks)
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/checkout-widget/layout.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/widget/page.tsx (2 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (12)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each TypeScript 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 in TypeScript
Avoid any and unknown in TypeScript unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.) in TypeScript

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity and testability
Re-use shared types from @/types or local types.ts barrel exports
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics whenever possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic in TypeScript files; avoid restating TypeScript types and signatures in prose

Files:

  • apps/dashboard/src/app/bridge/checkout-widget/layout.tsx
  • apps/dashboard/src/@/constants/public-envs.ts
  • apps/dashboard/next.config.ts
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • apps/dashboard/src/app/bridge/widget/page.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/{dashboard,playground-web}/src/**/*.{ts,tsx}: Import UI component primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground
Use Tailwind CSS only – no inline styles or CSS modules in dashboard and playground
Use cn() from @/lib/utils for conditional Tailwind class merging
Use design system tokens for styling (backgrounds: bg-card, borders: border-border, muted text: text-muted-foreground)
Expose className prop on root element for component overrides

Files:

  • apps/dashboard/src/app/bridge/checkout-widget/layout.tsx
  • apps/dashboard/src/@/constants/public-envs.ts
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • apps/dashboard/src/app/bridge/widget/page.tsx
apps/dashboard/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/dashboard/src/**/*.{ts,tsx}: Use NavLink for internal navigation with automatic active states in dashboard
Start server component files with import "server-only"; in Next.js
Read cookies/headers with next/headers in server components
Access server-only environment variables in server components
Perform heavy data fetching in server components
Implement redirect logic with redirect() from next/navigation in server components
Begin client component files with 'use client'; directive in Next.js
Handle interactive UI with React hooks (useState, useEffect, React Query, wallet hooks) in client components
Access browser APIs (localStorage, window, IntersectionObserver) in client components
Support fast transitions with prefetched data in client components
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header for API calls – never embed tokens in URLs
Return typed results (Project[], User[]) from server-side data fetches – avoid any
Wrap client-side API calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys in React Query for 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 – only use analytics client-side

Files:

  • apps/dashboard/src/app/bridge/checkout-widget/layout.tsx
  • apps/dashboard/src/@/constants/public-envs.ts
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • apps/dashboard/src/app/bridge/widget/page.tsx
apps/dashboard/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)

apps/dashboard/**/*.{ts,tsx}: Always import from the central UI library under @/components/ui/* for reusable core UI components like Button, Input, Select, Tabs, Card, Sidebar, Separator, Badge
Use NavLink from @/components/ui/NavLink for internal navigation to ensure active states are handled automatically
For notices and skeletons, rely on AnnouncementBanner, GenericLoadingPage, and EmptyStateCard components
Import icons from lucide-react or the project-specific …/icons exports; never embed raw SVG
Keep components pure; fetch data outside using server components or hooks and pass it down via props
Use Tailwind CSS as the styling system; avoid inline styles or CSS modules
Merge class names with cn from @/lib/utils to keep conditional logic readable
Stick to design tokens: use bg-card, border-border, text-muted-foreground and other Tailwind variables instead of hard-coded colors
Use spacing utilities (px-*, py-*, gap-*) instead of custom margins
Follow mobile-first responsive design with Tailwind helpers (max-sm, md, lg, xl)
Never hard-code colors; always use Tailwind variables
Combine class names via cn, and expose className prop if useful in components
Use React Query (@tanstack/react-query) for all client-side data fetching with typed hooks

Files:

  • apps/dashboard/src/app/bridge/checkout-widget/layout.tsx
  • apps/dashboard/src/@/constants/public-envs.ts
  • apps/dashboard/next.config.ts
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • apps/dashboard/src/app/bridge/widget/page.tsx
apps/dashboard/**/layout.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)

apps/dashboard/**/layout.{ts,tsx}: Reuse SidebarLayout or FullWidthSidebarLayout from @/components/blocks/SidebarLayout for all layouts
Export default async functions without 'use client'; in server components; they run on the Node edge

Files:

  • apps/dashboard/src/app/bridge/checkout-widget/layout.tsx
**/*.{js,jsx,ts,tsx,json}

📄 CodeRabbit inference engine (AGENTS.md)

Biome governs formatting and linting; its rules live in biome.json. Run pnpm fix & pnpm lint before committing, ensure there are no linting errors

Files:

  • apps/dashboard/src/app/bridge/checkout-widget/layout.tsx
  • apps/dashboard/src/@/constants/public-envs.ts
  • apps/dashboard/next.config.ts
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • apps/dashboard/src/app/bridge/widget/page.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
apps/{dashboard,playground}/**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/**/*.{tsx,ts}: Import UI primitives from @/components/ui/_ (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in Dashboard and Playground apps
Use NavLink for internal navigation so active states are handled automatically
Use Tailwind CSS for styling – no inline styles or CSS modules
Merge class names with cn() from @/lib/utils to keep conditional logic readable
Stick to design tokens for styling: backgrounds (bg-card), borders (border-border), muted text (text-muted-foreground), etc.
Server Components: Read cookies/headers with next/headers, access server-only environment variables or secrets, perform heavy data fetching, implement redirect logic with redirect() from next/navigation, and start files with import 'server-only'; to prevent client bundling
Client Components: Begin files with 'use client'; before imports, handle interactive UI relying on React hooks (useState, useEffect, React Query, wallet hooks), access browser APIs (localStorage, window, IntersectionObserver, etc.), and support fast transitions with client-side data prefetching
For client-side data fetching: Wrap calls in React Query (@tanstack/react-query), use descriptive and stable queryKeys for cache hits, configure staleTime / cacheTime based on freshness requirements (default ≥ 60 s), and keep tokens secret by calling internal API routes or server actions

Files:

  • apps/dashboard/src/app/bridge/checkout-widget/layout.tsx
  • apps/dashboard/src/@/constants/public-envs.ts
  • apps/dashboard/next.config.ts
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • apps/dashboard/src/app/bridge/widget/page.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/**/*.{ts,tsx}: For server-side data fetching: Always call getAuthToken() to retrieve the JWT from cookies and inject the token as an Authorization: Bearer header – never embed it in the URL. Return typed results (Project[], User[], …) – avoid any
Never import posthog-js in server components; analytics reporting is client-side only

Files:

  • apps/dashboard/src/app/bridge/checkout-widget/layout.tsx
  • apps/dashboard/src/@/constants/public-envs.ts
  • apps/dashboard/next.config.ts
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • apps/dashboard/src/app/bridge/widget/page.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Lazy-import optional features; avoid top-level side-effects

Files:

  • apps/dashboard/src/app/bridge/checkout-widget/layout.tsx
  • apps/dashboard/src/@/constants/public-envs.ts
  • apps/dashboard/next.config.ts
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • apps/dashboard/src/app/bridge/widget/page.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
apps/dashboard/**/page.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)

Use the container class with a max-w-7xl cap for consistent page width

Files:

  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
  • apps/dashboard/src/app/bridge/widget/page.tsx
apps/dashboard/**/*.client.tsx

📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)

apps/dashboard/**/*.client.tsx: Name component files after the component in PascalCase; append .client.tsx when the component is interactive
Client components must start with 'use client'; directive before imports

Files:

  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
packages/thirdweb/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

packages/thirdweb/src/**/*.{ts,tsx}: Comment only ambiguous logic in SDK code; avoid restating TypeScript in prose
Load heavy dependencies inside async paths to keep initial bundle lean (e.g. const { jsPDF } = await import("jspdf");)

Lazy-load heavy dependencies inside async paths to keep the initial bundle lean (e.g., const { jsPDF } = await import('jspdf');)

Files:

  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
🧬 Code graph analysis (3)
apps/dashboard/src/app/bridge/checkout-widget/page.tsx (5)
apps/dashboard/src/app/bridge/_common/parseQueryParams.ts (3)
  • parseQueryParams (3-11)
  • onlyNumber (14-15)
  • onlyAddress (13-13)
apps/dashboard/src/app/bridge/_common/isValidCurrency.ts (1)
  • isValidCurrency (3-10)
apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx (1)
  • CheckoutWidgetEmbed (10-71)
apps/dashboard/src/@/constants/public-envs.ts (1)
  • NEXT_PUBLIC_CHECKOUT_IFRAME_CLIENT_ID (48-49)
apps/dashboard/src/app/bridge/(general)/components/client/Providers.client.tsx (1)
  • BridgeProviders (9-42)
apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx (2)
apps/dashboard/src/@/constants/thirdweb.server.ts (1)
  • getConfiguredThirdwebClient (26-97)
apps/dashboard/src/@/constants/public-envs.ts (1)
  • NEXT_PUBLIC_CHECKOUT_IFRAME_CLIENT_ID (48-49)
apps/dashboard/src/app/bridge/widget/page.tsx (2)
apps/dashboard/src/app/bridge/_common/parseQueryParams.ts (3)
  • parseQueryParams (3-11)
  • onlyNumber (14-15)
  • onlyAddress (13-13)
apps/dashboard/src/app/bridge/_common/isValidCurrency.ts (1)
  • isValidCurrency (3-10)
⏰ 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: E2E Tests (pnpm, webpack)
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: Build Packages
  • GitHub Check: Lint Packages
  • GitHub Check: Unit Tests
  • GitHub Check: Size
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (15)
apps/dashboard/next.config.ts (1)

164-181: LGTM! CSP headers correctly extend to checkout widget routes.

The configuration mirrors the existing /bridge/widget routes and properly applies EmbedContentSecurityPolicy with frame-ancestors * for iframe embedding support.

packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx (1)

164-166: LGTM! Clean simplification of button label rendering.

The change removes the redundant fiat price display from the button, which aligns with the changeset description. The price is already displayed prominently in the FiatValue component above (lines 82-91).

.changeset/short-wasps-show.md (1)

1-5: LGTM! Changeset correctly documents the UI change.

apps/dashboard/src/@/constants/public-envs.ts (1)

47-49: LGTM! New environment constant follows existing patterns.

The constant mirrors NEXT_PUBLIC_BRIDGE_IFRAME_CLIENT_ID without a default value, which is appropriate since the consuming code will throw if the value is missing.

apps/dashboard/src/app/bridge/widget/page.tsx (2)

37-74: LGTM! Clean refactor to centralized query parameter utilities.

The migration to parseQueryParams with onlyNumber, onlyAddress, and isValidCurrency validators improves consistency and type safety across the bridge widget configuration. The pattern is reusable for the new checkout widget flow.


120-138: LGTM! Proper guard for required environment variable.

Throwing early when NEXT_PUBLIC_BRIDGE_IFRAME_CLIENT_ID is missing provides clear feedback during development/deployment rather than failing silently.

apps/dashboard/src/app/bridge/_common/parseQueryParams.ts (2)

3-11: LGTM!

Clean, well-typed generic utility function with proper handling of the union type. The function correctly processes only string values and returns undefined for arrays and undefined inputs.


13-15: LGTM!

Both validators are concise and correctly implemented. onlyAddress leverages thirdweb's isAddress check, and onlyNumber properly handles NaN cases.

apps/dashboard/src/app/bridge/checkout-widget/page.tsx (4)

57-60: showThirdwebBranding defaults to true when param is missing.

When searchParams.showThirdwebBranding is undefined, parseQueryParams returns undefined without calling the callback. However, when the param is present but not "false", the callback returns true. This means the prop will be undefined when the param is absent, not true.

If the intent is to default to true when not specified, add a fallback:

🔎 Proposed fix if defaulting to true is intended
   const showThirdwebBranding = parseQueryParams(
     searchParams.showThirdwebBranding,
     (v) => v !== "false",
-  );
+  ) ?? true;

134-152: Runtime error if env var is missing.

The Providers function throws at runtime if NEXT_PUBLIC_CHECKOUT_IFRAME_CLIENT_ID is not set. This will crash the page for users rather than showing an error. Consider handling this more gracefully or validating at build time.

Also, this function is defined inside the same file as a server component but doesn't have "use client" directive. Since it uses BridgeProviders (a client component), React will handle this via the component boundary, but the throw will happen server-side during render.

Is the intention to fail hard here, or should this show a user-friendly error similar to the invalid configuration block?


71-109: LGTM on validation and error UI.

Good use of design tokens (bg-background, bg-card, text-destructive-text, text-muted-foreground) and clear error messaging for missing required parameters.


111-131: LGTM on widget rendering.

Props are correctly passed through to CheckoutWidgetEmbed, and the layout follows the project's Tailwind-based styling conventions.

apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx (3)

39-47: NEXT_PUBLIC_CHECKOUT_IFRAME_CLIENT_ID may be undefined.

Unlike the Providers wrapper in page.tsx which throws if the env var is missing, this component passes it directly to getConfiguredThirdwebClient. Looking at the snippet from thirdweb.server.ts, the function falls back to NEXT_PUBLIC_DASHBOARD_CLIENT_ID or "dummy-build-client", which may not be the intended behavior for this widget.

Consider adding validation or leveraging the parent's guarantee that the env var exists.


52-70: LGTM on CheckoutWidget rendering.

All props are correctly passed through to the widget with appropriate types.


7-8: No issues found. The import of getConfiguredThirdwebClient from @/constants/thirdweb.server in this client component is safe—the module contains no import "server-only" directive, uses no Node.js-specific APIs, and handles environment variables with proper fallbacks for client-side execution.

@github-actions
Copy link
Contributor

github-actions bot commented Dec 19, 2025

size-limit report 📦

Path Size
@thirdweb-dev/nexus (esm) 105.66 KB (0%)
@thirdweb-dev/nexus (cjs) 319.47 KB (0%)

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

🧹 Nitpick comments (5)
apps/dashboard/src/app/bridge/checkout-widget/page.tsx (3)

67-69: Remove unnecessary type assertion.

Since isValidCurrency is a type guard that returns currency is SupportedFiatCurrency, the explicit as SupportedFiatCurrency cast is redundant. TypeScript already narrows the type within the ternary's true branch.

🔎 Suggested simplification
  const currency = parseQueryParams(searchParams.currency, (v) =>
-   isValidCurrency(v) ? (v as SupportedFiatCurrency) : undefined,
+   isValidCurrency(v) ? v : undefined,
  );

40-40: Consider validating the amount parameter format.

The amount parameter accepts any string value without numeric validation. While downstream components may handle invalid formats, validating it here (e.g., checking for valid decimal format) would provide earlier feedback and a clearer error message to users.

🔎 Optional validation approach
- const amount = parseQueryParams(searchParams.amount, (v) => v);
+ const amount = parseQueryParams(searchParams.amount, (v) => {
+   // Allow numbers with optional decimals
+   return /^\d+\.?\d*$/.test(v) ? v : undefined;
+ });

Then update the error message on line 94-96 to clarify the expected format:

  {!amount && (
    <li>
-     • <InlineCode code="amount" /> - Amount to charge (e.g., "0.01")
+     • <InlineCode code="amount" /> - Amount to charge as a valid number (e.g., "0.01", "100")
    </li>
  )}

141-143: Review error handling: throwing during render may cause poor UX.

Throwing an error during component render will trigger an error boundary (or crash the app if none exists). For a missing environment variable, consider one of these patterns:

  • Show a graceful error UI instead of throwing
  • Perform the check at build time or during initialization
  • Use Next.js environment variable validation

This ensures users see a helpful message rather than a blank page or generic error boundary.

🔎 Alternative: graceful error UI
  if (!NEXT_PUBLIC_CHECKOUT_IFRAME_CLIENT_ID) {
-   throw new Error("NEXT_PUBLIC_CHECKOUT_IFRAME_CLIENT_ID is not set");
+   return (
+     <div className="flex min-h-screen items-center justify-center bg-background px-4">
+       <div className="max-w-md rounded-xl border bg-card p-6 text-center">
+         <h2 className="mb-2 font-semibold text-destructive-text">Configuration Error</h2>
+         <p className="text-muted-foreground text-sm">
+           Missing required environment variable: NEXT_PUBLIC_CHECKOUT_IFRAME_CLIENT_ID
+         </p>
+       </div>
+     </div>
+   );
  }
apps/dashboard/src/app/bridge/_common/parseQueryParams.ts (2)

3-11: Document the string[] handling behavior.

The function silently returns undefined for string[] values without processing them. While this may be intentional (Next.js query params can be arrays when the same key appears multiple times), documenting this behavior would help future maintainers understand the design choice.

🔎 Suggested documentation
+/**
+ * Parse and transform a query parameter value.
+ * 
+ * @param value - Query parameter from Next.js searchParams (string, string[], or undefined)
+ * @param fn - Transformation function to apply to string values
+ * @returns Transformed value, or undefined if value is not a string or transformation fails
+ * 
+ * @remarks
+ * Only processes single string values. Arrays (multiple values for same key) return undefined.
+ */
  export function parseQueryParams<T>(
    value: string | string[] | undefined,
    fn: (value: string) => T | undefined,
  ): T | undefined {

14-15: Consider clarifying the number validation logic.

While Number.isNaN(Number(v)) works correctly, the double Number() call can be unclear. Consider extracting to a const or adding a comment for readability.

🔎 Slightly clearer alternative
-export const onlyNumber = (v: string) =>
-  Number.isNaN(Number(v)) ? undefined : Number(v);
+export const onlyNumber = (v: string) => {
+  const num = Number(v);
+  return Number.isNaN(num) ? undefined : num;
+};
📜 Review details

Configuration used: Organization 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 e730eb5 and d528393.

📒 Files selected for processing (12)
  • .changeset/short-wasps-show.md (1 hunks)
  • apps/dashboard/next.config.ts (1 hunks)
  • apps/dashboard/src/@/constants/public-envs.ts (1 hunks)
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts (1 hunks)
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts (1 hunks)
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/checkout-widget/layout.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/widget/page.tsx (2 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx (1 hunks)
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration-v07.test.ts (1 hunks)
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts
  • apps/dashboard/next.config.ts
  • .changeset/short-wasps-show.md
  • apps/dashboard/src/@/constants/public-envs.ts
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/layout.tsx
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each TypeScript 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 in TypeScript
Avoid any and unknown in TypeScript unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.) in TypeScript

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity and testability
Re-use shared types from @/types or local types.ts barrel exports
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics whenever possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic in TypeScript files; avoid restating TypeScript types and signatures in prose

Files:

  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration-v07.test.ts
  • apps/dashboard/src/app/bridge/widget/page.tsx
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
packages/thirdweb/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

packages/thirdweb/src/**/*.{ts,tsx}: Comment only ambiguous logic in SDK code; avoid restating TypeScript in prose
Load heavy dependencies inside async paths to keep initial bundle lean (e.g. const { jsPDF } = await import("jspdf");)

Lazy-load heavy dependencies inside async paths to keep the initial bundle lean (e.g., const { jsPDF } = await import('jspdf');)

Files:

  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration-v07.test.ts
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts
**/*.{js,jsx,ts,tsx,json}

📄 CodeRabbit inference engine (AGENTS.md)

Biome governs formatting and linting; its rules live in biome.json. Run pnpm fix & pnpm lint before committing, ensure there are no linting errors

Files:

  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration-v07.test.ts
  • apps/dashboard/src/app/bridge/widget/page.tsx
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Lazy-import optional features; avoid top-level side-effects

Files:

  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration-v07.test.ts
  • apps/dashboard/src/app/bridge/widget/page.tsx
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.test.{ts,tsx}: Place tests alongside code: foo.tsfoo.test.ts in the same directory
Use real function invocations with stub data in tests; avoid brittle mocks
Use Mock Service Worker (MSW) for fetch/HTTP call interception in tests
Keep tests deterministic and side-effect free
Use predefined test accounts from test/src/test-wallets.ts in tests
Use FORKED_ETHEREUM_CHAIN for mainnet interactions and ANVIL_CHAIN for isolated tests

**/*.test.{ts,tsx}: Co-locate tests with source files using the pattern foo.ts ↔ foo.test.ts
Use real function invocations with stub data in tests; avoid brittle mocks
For network interactions in tests, use Mock Service Worker (MSW) to intercept fetch/HTTP calls, mocking only scenarios that are hard to reproduce
Keep tests deterministic and side-effect free; Vitest is pre-configured

Files:

  • packages/thirdweb/src/wallets/smart/smart-wallet-integration-v07.test.ts
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/{dashboard,playground-web}/src/**/*.{ts,tsx}: Import UI component primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground
Use Tailwind CSS only – no inline styles or CSS modules in dashboard and playground
Use cn() from @/lib/utils for conditional Tailwind class merging
Use design system tokens for styling (backgrounds: bg-card, borders: border-border, muted text: text-muted-foreground)
Expose className prop on root element for component overrides

Files:

  • apps/dashboard/src/app/bridge/widget/page.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
apps/dashboard/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/dashboard/src/**/*.{ts,tsx}: Use NavLink for internal navigation with automatic active states in dashboard
Start server component files with import "server-only"; in Next.js
Read cookies/headers with next/headers in server components
Access server-only environment variables in server components
Perform heavy data fetching in server components
Implement redirect logic with redirect() from next/navigation in server components
Begin client component files with 'use client'; directive in Next.js
Handle interactive UI with React hooks (useState, useEffect, React Query, wallet hooks) in client components
Access browser APIs (localStorage, window, IntersectionObserver) in client components
Support fast transitions with prefetched data in client components
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header for API calls – never embed tokens in URLs
Return typed results (Project[], User[]) from server-side data fetches – avoid any
Wrap client-side API calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys in React Query for 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 – only use analytics client-side

Files:

  • apps/dashboard/src/app/bridge/widget/page.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
apps/dashboard/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)

apps/dashboard/**/*.{ts,tsx}: Always import from the central UI library under @/components/ui/* for reusable core UI components like Button, Input, Select, Tabs, Card, Sidebar, Separator, Badge
Use NavLink from @/components/ui/NavLink for internal navigation to ensure active states are handled automatically
For notices and skeletons, rely on AnnouncementBanner, GenericLoadingPage, and EmptyStateCard components
Import icons from lucide-react or the project-specific …/icons exports; never embed raw SVG
Keep components pure; fetch data outside using server components or hooks and pass it down via props
Use Tailwind CSS as the styling system; avoid inline styles or CSS modules
Merge class names with cn from @/lib/utils to keep conditional logic readable
Stick to design tokens: use bg-card, border-border, text-muted-foreground and other Tailwind variables instead of hard-coded colors
Use spacing utilities (px-*, py-*, gap-*) instead of custom margins
Follow mobile-first responsive design with Tailwind helpers (max-sm, md, lg, xl)
Never hard-code colors; always use Tailwind variables
Combine class names via cn, and expose className prop if useful in components
Use React Query (@tanstack/react-query) for all client-side data fetching with typed hooks

Files:

  • apps/dashboard/src/app/bridge/widget/page.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
apps/dashboard/**/page.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)

Use the container class with a max-w-7xl cap for consistent page width

Files:

  • apps/dashboard/src/app/bridge/widget/page.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
apps/{dashboard,playground}/**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/**/*.{tsx,ts}: Import UI primitives from @/components/ui/_ (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in Dashboard and Playground apps
Use NavLink for internal navigation so active states are handled automatically
Use Tailwind CSS for styling – no inline styles or CSS modules
Merge class names with cn() from @/lib/utils to keep conditional logic readable
Stick to design tokens for styling: backgrounds (bg-card), borders (border-border), muted text (text-muted-foreground), etc.
Server Components: Read cookies/headers with next/headers, access server-only environment variables or secrets, perform heavy data fetching, implement redirect logic with redirect() from next/navigation, and start files with import 'server-only'; to prevent client bundling
Client Components: Begin files with 'use client'; before imports, handle interactive UI relying on React hooks (useState, useEffect, React Query, wallet hooks), access browser APIs (localStorage, window, IntersectionObserver, etc.), and support fast transitions with client-side data prefetching
For client-side data fetching: Wrap calls in React Query (@tanstack/react-query), use descriptive and stable queryKeys for cache hits, configure staleTime / cacheTime based on freshness requirements (default ≥ 60 s), and keep tokens secret by calling internal API routes or server actions

Files:

  • apps/dashboard/src/app/bridge/widget/page.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
apps/{dashboard,playground}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/**/*.{ts,tsx}: For server-side data fetching: Always call getAuthToken() to retrieve the JWT from cookies and inject the token as an Authorization: Bearer header – never embed it in the URL. Return typed results (Project[], User[], …) – avoid any
Never import posthog-js in server components; analytics reporting is client-side only

Files:

  • apps/dashboard/src/app/bridge/widget/page.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
🧬 Code graph analysis (2)
apps/dashboard/src/app/bridge/widget/page.tsx (2)
apps/dashboard/src/app/bridge/_common/parseQueryParams.ts (3)
  • parseQueryParams (3-11)
  • onlyNumber (14-15)
  • onlyAddress (13-13)
apps/dashboard/src/app/bridge/_common/isValidCurrency.ts (1)
  • isValidCurrency (3-10)
apps/dashboard/src/app/bridge/checkout-widget/page.tsx (6)
apps/dashboard/src/app/bridge/widget/page.tsx (2)
  • metadata (18-25)
  • Page (31-118)
apps/dashboard/src/app/bridge/_common/parseQueryParams.ts (3)
  • parseQueryParams (3-11)
  • onlyNumber (14-15)
  • onlyAddress (13-13)
apps/dashboard/src/app/bridge/_common/isValidCurrency.ts (1)
  • isValidCurrency (3-10)
apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx (1)
  • CheckoutWidgetEmbed (10-71)
apps/dashboard/src/@/constants/public-envs.ts (1)
  • NEXT_PUBLIC_CHECKOUT_IFRAME_CLIENT_ID (48-49)
apps/dashboard/src/app/bridge/(general)/components/client/Providers.client.tsx (1)
  • BridgeProviders (9-42)
⏰ 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: Unit Tests
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Size
  • GitHub Check: Lint Packages
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (4)
packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx (1)

165-165: LGTM! Simplified button content.

The change removes the duplicate fiat price display from the button while keeping it visible in the price section above (lines 82-91). The button now shows the custom label or "Buy Now" fallback, which is clearer and less redundant.

apps/dashboard/src/app/bridge/widget/page.tsx (1)

37-74: LGTM! Clean refactoring to centralized parsing utilities.

The migration to parseQueryParams with onlyAddress, onlyNumber, and isValidCurrency validators consolidates the query parameter parsing logic and improves maintainability. The behavior remains equivalent while eliminating code duplication.

apps/dashboard/src/app/bridge/checkout-widget/page.tsx (1)

72-109: Well-structured validation and error handling.

The parameter validation logic correctly identifies missing required fields and provides a clear, user-friendly error message with specific guidance. The UI uses design tokens appropriately and lists exactly which parameters are missing.

apps/dashboard/src/app/bridge/_common/parseQueryParams.ts (1)

13-13: Clean address validation helper.

The onlyAddress validator correctly leverages thirdweb's isAddress utility for validation, providing a clear and type-safe way to parse address query parameters.

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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts (2)

155-174: Add explanation for skipped ERC-1271 typed data signature test.

Like the test at line 122, this ERC-1271 test is skipped without explanation. If both tests share the same root cause (e.g., infrastructure requirements, known bug), consider adding a shared comment or referencing a tracking issue.


322-378: Remove FIXME or skip the test: fix the contradiction between "always fails" comment and enabled test.

Line 322 contains // FIXME: this test always fails, yet the test is enabled and will run. This creates a contradiction:

  • If the test truly fails, it should be skipped with it.skip(...) and tracked in an issue
  • If the test has been fixed, remove the FIXME comment

Running a test known to fail blocks CI and reduces confidence in the test suite. Resolve this by either skipping the test with documentation or removing the outdated comment if the test now passes reliably.

♻️ Duplicate comments (1)
packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts (1)

122-141: Add explanation for skipped ERC-1271 signature test.

This test is skipped without an inline comment explaining why. While the PR objectives mention "skipped certain ERC-1271 signature cases," future maintainers need context directly in the code.

Please add a brief comment above line 122 indicating the reason (e.g., // TODO: ERC-1271 verification fails post-deployment - tracking in issue #XXXX or // Skipped: requires bundler infrastructure changes).

Based on past review comments flagging the same concern.

🧹 Nitpick comments (6)
apps/dashboard/src/app/bridge/_common/isValidCurrency.ts (1)

3-10: Consider simplifying to a single return statement.

The function logic is correct, but it can be more concise.

🔎 Proposed simplification
 export function isValidCurrency(
   currency: string,
 ): currency is SupportedFiatCurrency {
-  if (currency in VALID_CURRENCIES) {
-    return true;
-  }
-  return false;
+  return currency in VALID_CURRENCIES;
 }
apps/dashboard/src/app/bridge/widget/page.tsx (2)

31-118: Add explicit return type to Page component.

The coding guidelines require explicit function return types for TypeScript files. Consider adding : Promise<JSX.Element> to the Page function signature.

🔎 Proposed fix
-export default async function Page(props: {
+export default async function Page(props: {
   searchParams: Promise<SearchParams>;
-}) {
+}): Promise<JSX.Element> {

Based on coding guidelines: "Write idiomatic TypeScript with explicit function declarations and return types"


120-138: Add explicit return type to Providers component.

Consider adding : JSX.Element to the Providers function signature for consistency with coding guidelines.

🔎 Proposed fix
 function Providers({
   children,
   theme,
 }: {
   children: React.ReactNode;
   theme: string;
-}) {
+}): JSX.Element {

Based on coding guidelines: "Write idiomatic TypeScript with explicit function declarations and return types"

apps/dashboard/src/app/bridge/checkout-widget/page.tsx (3)

33-132: Add explicit return type to Page component.

The coding guidelines require explicit function return types for TypeScript files. Consider adding : Promise<JSX.Element> to the Page function signature.

🔎 Proposed fix
-export default async function Page(props: {
+export default async function Page(props: {
   searchParams: Promise<SearchParams>;
-}) {
+}): Promise<JSX.Element> {

Based on coding guidelines: "Write idiomatic TypeScript with explicit function declarations and return types"


67-69: Remove redundant type assertion.

The as SupportedFiatCurrency cast is unnecessary because the isValidCurrency type guard already narrows the type to SupportedFiatCurrency when it returns true.

🔎 Proposed fix
   const currency = parseQueryParams(searchParams.currency, (v) =>
-    isValidCurrency(v) ? (v as SupportedFiatCurrency) : undefined,
+    isValidCurrency(v) ? v : undefined,
   );

134-152: Add explicit return type to Providers component.

Consider adding : JSX.Element to the Providers function signature for consistency with coding guidelines.

🔎 Proposed fix
 function Providers({
   children,
   theme,
 }: {
   children: React.ReactNode;
   theme: string;
-}) {
+}): JSX.Element {

Based on coding guidelines: "Write idiomatic TypeScript with explicit function declarations and return types"

📜 Review details

Configuration used: Organization 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 8d312df and 3bbc7ee.

📒 Files selected for processing (12)
  • .changeset/short-wasps-show.md (1 hunks)
  • apps/dashboard/next.config.ts (1 hunks)
  • apps/dashboard/src/@/constants/public-envs.ts (1 hunks)
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts (1 hunks)
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts (1 hunks)
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/checkout-widget/layout.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/widget/page.tsx (2 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx (1 hunks)
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration-v07.test.ts (3 hunks)
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • apps/dashboard/src/@/constants/public-envs.ts
  • apps/dashboard/src/app/bridge/checkout-widget/layout.tsx
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration-v07.test.ts
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • .changeset/short-wasps-show.md
  • apps/dashboard/next.config.ts
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each TypeScript 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 in TypeScript
Avoid any and unknown in TypeScript unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.) in TypeScript

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity and testability
Re-use shared types from @/types or local types.ts barrel exports
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics whenever possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic in TypeScript files; avoid restating TypeScript types and signatures in prose

Files:

  • apps/dashboard/src/app/bridge/widget/page.tsx
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/{dashboard,playground-web}/src/**/*.{ts,tsx}: Import UI component primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground
Use Tailwind CSS only – no inline styles or CSS modules in dashboard and playground
Use cn() from @/lib/utils for conditional Tailwind class merging
Use design system tokens for styling (backgrounds: bg-card, borders: border-border, muted text: text-muted-foreground)
Expose className prop on root element for component overrides

Files:

  • apps/dashboard/src/app/bridge/widget/page.tsx
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
apps/dashboard/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/dashboard/src/**/*.{ts,tsx}: Use NavLink for internal navigation with automatic active states in dashboard
Start server component files with import "server-only"; in Next.js
Read cookies/headers with next/headers in server components
Access server-only environment variables in server components
Perform heavy data fetching in server components
Implement redirect logic with redirect() from next/navigation in server components
Begin client component files with 'use client'; directive in Next.js
Handle interactive UI with React hooks (useState, useEffect, React Query, wallet hooks) in client components
Access browser APIs (localStorage, window, IntersectionObserver) in client components
Support fast transitions with prefetched data in client components
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header for API calls – never embed tokens in URLs
Return typed results (Project[], User[]) from server-side data fetches – avoid any
Wrap client-side API calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys in React Query for 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 – only use analytics client-side

Files:

  • apps/dashboard/src/app/bridge/widget/page.tsx
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
apps/dashboard/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)

apps/dashboard/**/*.{ts,tsx}: Always import from the central UI library under @/components/ui/* for reusable core UI components like Button, Input, Select, Tabs, Card, Sidebar, Separator, Badge
Use NavLink from @/components/ui/NavLink for internal navigation to ensure active states are handled automatically
For notices and skeletons, rely on AnnouncementBanner, GenericLoadingPage, and EmptyStateCard components
Import icons from lucide-react or the project-specific …/icons exports; never embed raw SVG
Keep components pure; fetch data outside using server components or hooks and pass it down via props
Use Tailwind CSS as the styling system; avoid inline styles or CSS modules
Merge class names with cn from @/lib/utils to keep conditional logic readable
Stick to design tokens: use bg-card, border-border, text-muted-foreground and other Tailwind variables instead of hard-coded colors
Use spacing utilities (px-*, py-*, gap-*) instead of custom margins
Follow mobile-first responsive design with Tailwind helpers (max-sm, md, lg, xl)
Never hard-code colors; always use Tailwind variables
Combine class names via cn, and expose className prop if useful in components
Use React Query (@tanstack/react-query) for all client-side data fetching with typed hooks

Files:

  • apps/dashboard/src/app/bridge/widget/page.tsx
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
apps/dashboard/**/page.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)

Use the container class with a max-w-7xl cap for consistent page width

Files:

  • apps/dashboard/src/app/bridge/widget/page.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
**/*.{js,jsx,ts,tsx,json}

📄 CodeRabbit inference engine (AGENTS.md)

Biome governs formatting and linting; its rules live in biome.json. Run pnpm fix & pnpm lint before committing, ensure there are no linting errors

Files:

  • apps/dashboard/src/app/bridge/widget/page.tsx
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
apps/{dashboard,playground}/**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/**/*.{tsx,ts}: Import UI primitives from @/components/ui/_ (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in Dashboard and Playground apps
Use NavLink for internal navigation so active states are handled automatically
Use Tailwind CSS for styling – no inline styles or CSS modules
Merge class names with cn() from @/lib/utils to keep conditional logic readable
Stick to design tokens for styling: backgrounds (bg-card), borders (border-border), muted text (text-muted-foreground), etc.
Server Components: Read cookies/headers with next/headers, access server-only environment variables or secrets, perform heavy data fetching, implement redirect logic with redirect() from next/navigation, and start files with import 'server-only'; to prevent client bundling
Client Components: Begin files with 'use client'; before imports, handle interactive UI relying on React hooks (useState, useEffect, React Query, wallet hooks), access browser APIs (localStorage, window, IntersectionObserver, etc.), and support fast transitions with client-side data prefetching
For client-side data fetching: Wrap calls in React Query (@tanstack/react-query), use descriptive and stable queryKeys for cache hits, configure staleTime / cacheTime based on freshness requirements (default ≥ 60 s), and keep tokens secret by calling internal API routes or server actions

Files:

  • apps/dashboard/src/app/bridge/widget/page.tsx
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/**/*.{ts,tsx}: For server-side data fetching: Always call getAuthToken() to retrieve the JWT from cookies and inject the token as an Authorization: Bearer header – never embed it in the URL. Return typed results (Project[], User[], …) – avoid any
Never import posthog-js in server components; analytics reporting is client-side only

Files:

  • apps/dashboard/src/app/bridge/widget/page.tsx
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Lazy-import optional features; avoid top-level side-effects

Files:

  • apps/dashboard/src/app/bridge/widget/page.tsx
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.test.{ts,tsx}: Place tests alongside code: foo.tsfoo.test.ts in the same directory
Use real function invocations with stub data in tests; avoid brittle mocks
Use Mock Service Worker (MSW) for fetch/HTTP call interception in tests
Keep tests deterministic and side-effect free
Use predefined test accounts from test/src/test-wallets.ts in tests
Use FORKED_ETHEREUM_CHAIN for mainnet interactions and ANVIL_CHAIN for isolated tests

**/*.test.{ts,tsx}: Co-locate tests with source files using the pattern foo.ts ↔ foo.test.ts
Use real function invocations with stub data in tests; avoid brittle mocks
For network interactions in tests, use Mock Service Worker (MSW) to intercept fetch/HTTP calls, mocking only scenarios that are hard to reproduce
Keep tests deterministic and side-effect free; Vitest is pre-configured

Files:

  • packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts
packages/thirdweb/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

packages/thirdweb/src/**/*.{ts,tsx}: Comment only ambiguous logic in SDK code; avoid restating TypeScript in prose
Load heavy dependencies inside async paths to keep initial bundle lean (e.g. const { jsPDF } = await import("jspdf");)

Lazy-load heavy dependencies inside async paths to keep the initial bundle lean (e.g., const { jsPDF } = await import('jspdf');)

Files:

  • packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
⏰ 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: Unit Tests
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: Lint Packages
  • GitHub Check: Build Packages
  • GitHub Check: Size
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (4)
packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx (1)

165-165: LGTM! Clean simplification.

The button label rendering is now more straightforward, removing the duplicate fiat price display while maintaining fallback behavior.

apps/dashboard/src/app/bridge/widget/page.tsx (1)

37-74: Excellent refactoring to centralized utilities!

The migration to parseQueryParams and isValidCurrency improves code maintainability and eliminates duplication. The parameter parsing logic is now consistent and type-safe.

apps/dashboard/src/app/bridge/checkout-widget/page.tsx (1)

72-109: Excellent validation and error handling!

The required parameter validation with informative error UI provides a great user experience. The error message clearly lists missing parameters with examples, making it easy for integrators to fix configuration issues.

apps/dashboard/src/app/bridge/_common/isValidCurrency.ts (1)

12-36: The currency list is accurate and complete. Verified that all 23 currencies in VALID_CURRENCIES match the SupportedFiatCurrency type from the thirdweb SDK exactly.

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: 5

♻️ Duplicate comments (3)
packages/thirdweb/src/wallets/smart/smart-wallet-integration-v07.test.ts (1)

161-161: Add explanation for skipping ERC-1271 typed data signature test.

The typed data variant of the ERC-1271 signature test after deployment is now skipped, while the message signing variant (line 126) remains active. This inconsistency suggests a specific issue with typed data signing rather than a general ERC-1271 problem.

Given the existing FIXME comment pattern in this file and the past review concern about similar skipped tests, please:

  1. Add a comment explaining why typed data ERC-1271 verification is skipped (e.g., // FIXME: ERC-1271 typed data verification fails after deployment)
  2. Create or reference a tracking issue for this known limitation
  3. Clarify if this is specific to v0.7 or affects other smart wallet versions
apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx (1)

98-115: Security: postMessage with wildcard origin.

The sendMessageToParent function uses "*" as the targetOrigin, which allows any parent window to receive these messages. If the messages contain sensitive data, this could be a security risk.

Consider one of the following approaches:

  1. If the parent origin is known at runtime, retrieve it from query params or environment and validate it:

    const allowedOrigin = process.env.NEXT_PUBLIC_PARENT_ORIGIN || window.location.origin;
    window.parent.postMessage({ ... }, allowedOrigin);
  2. If multiple trusted origins exist, maintain an allowlist and validate:

    const ALLOWED_ORIGINS = ['https://example.com', 'https://app.example.com'];
    const parentOrigin = new URL(document.referrer).origin;
    if (ALLOWED_ORIGINS.includes(parentOrigin)) {
      window.parent.postMessage({ ... }, parentOrigin);
    }
  3. If truly any origin should receive these messages, document this decision and ensure the payload contains no sensitive information beyond transaction status.

Based on the current implementation, the messages appear to contain only transaction status and error messages, which may be acceptable. However, please verify this is intentional and document the security decision.

apps/dashboard/src/app/bridge/checkout-widget/page.tsx (1)

1-14: Add "server-only" import to prevent client bundling.

According to the coding guidelines for Next.js dashboard server components, the file should start with import "server-only"; to ensure this component isn't accidentally bundled for the client.

🔎 Proposed fix
+import "server-only";
 import type { Metadata } from "next";
 import "@workspace/ui/global.css";

Based on coding guidelines: "Start server component files with import "server-only"; in Next.js"

🧹 Nitpick comments (3)
apps/dashboard/next.config.ts (1)

164-181: LGTM! CSP headers correctly configured for checkout widget embedding.

The implementation properly extends the embed CSP policy to the new checkout widget routes, following the same pattern as the existing bridge widget. This will allow the checkout widget to be embedded in iframes as intended.

💡 Optional: Consider reducing duplication

The header configuration is now repeated for four routes (widget × 2, checkout-widget × 2). You could reduce duplication by extracting the repeated paths into an array:

  async headers() {
+   const embedRoutes = [
+     "/bridge/widget",
+     "/bridge/widget/:path*",
+     "/bridge/checkout-widget",
+     "/bridge/checkout-widget/:path*",
+   ];
+
    return [
      {
        headers: [
          ...securityHeaders,
          {
            key: "accept-ch",
            value: "sec-ch-viewport-width",
          },
        ],
        // Apply these headers to all routes in your application.
        source: "/(.*)",
      },
-     {
-       headers: [
-         {
-           key: "Content-Security-Policy",
-           value: EmbedContentSecurityPolicy.replace(/\s{2,}/g, " ").trim(),
-         },
-       ],
-       source: "/bridge/widget",
-     },
-     {
-       headers: [
-         {
-           key: "Content-Security-Policy",
-           value: EmbedContentSecurityPolicy.replace(/\s{2,}/g, " ").trim(),
-         },
-       ],
-       source: "/bridge/widget/:path*",
-     },
-     {
-       headers: [
-         {
-           key: "Content-Security-Policy",
-           value: EmbedContentSecurityPolicy.replace(/\s{2,}/g, " ").trim(),
-         },
-       ],
-       source: "/bridge/checkout-widget",
-     },
-     {
-       headers: [
-         {
-           key: "Content-Security-Policy",
-           value: EmbedContentSecurityPolicy.replace(/\s{2,}/g, " ").trim(),
-         },
-       ],
-       source: "/bridge/checkout-widget/:path*",
-     },
+     ...embedRoutes.map((source) => ({
+       headers: [
+         {
+           key: "Content-Security-Policy",
+           value: EmbedContentSecurityPolicy.replace(/\s{2,}/g, " ").trim(),
+         },
+       ],
+       source,
+     })),
    ];
  },

This keeps the configuration DRY and makes future additions easier.

apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx (1)

52-60: Consider validating the client ID at the component level.

While page.tsx validates NEXT_PUBLIC_CHECKOUT_IFRAME_CLIENT_ID in the Providers wrapper, this component uses it directly without validation. If this component is reused elsewhere without that wrapper, it could create a client with an undefined clientId, potentially causing runtime errors.

🔎 Proposed defensive check
 const client = useMemo(
   () =>
+    {
+      if (!NEXT_PUBLIC_CHECKOUT_IFRAME_CLIENT_ID) {
+        throw new Error("NEXT_PUBLIC_CHECKOUT_IFRAME_CLIENT_ID is not configured");
+      }
+      return 
       getConfiguredThirdwebClient({
         clientId: NEXT_PUBLIC_CHECKOUT_IFRAME_CLIENT_ID,
         secretKey: undefined,
         teamId: undefined,
-      }),
+      });
+    },
   [],
 );
apps/dashboard/src/app/bridge/checkout-widget/page.tsx (1)

45-45: Variable name shadows constant.

The local variable title on line 45 shadows the constant title defined on line 16. Consider renaming the local variable to avoid confusion.

🔎 Proposed fix
- const title = parseQueryParams(searchParams.title, (v) => v);
+ const productTitle = parseQueryParams(searchParams.title, (v) => v);

And update the usage on line 119:

       <CheckoutWidgetEmbed
         chainId={chainId}
         amount={amount}
         seller={seller}
         tokenAddress={tokenAddress}
-        name={title}
+        name={productTitle}
         description={productDescription}
📜 Review details

Configuration used: Organization 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 3bbc7ee and 116c326.

📒 Files selected for processing (13)
  • .changeset/short-wasps-show.md (1 hunks)
  • apps/dashboard/next.config.ts (1 hunks)
  • apps/dashboard/src/@/constants/public-envs.ts (1 hunks)
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts (1 hunks)
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts (1 hunks)
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/checkout-widget/layout.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/widget/page.tsx (2 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx (1 hunks)
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration-v07.test.ts (3 hunks)
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts (4 hunks)
  • packages/thirdweb/src/wallets/smart/smart-wallet-modular.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (8)
  • .changeset/short-wasps-show.md
  • apps/dashboard/src/app/bridge/checkout-widget/layout.tsx
  • apps/dashboard/src/@/constants/public-envs.ts
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
  • apps/dashboard/src/app/bridge/widget/page.tsx
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts
🧰 Additional context used
📓 Path-based instructions (12)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each TypeScript 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 in TypeScript
Avoid any and unknown in TypeScript unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.) in TypeScript

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity and testability
Re-use shared types from @/types or local types.ts barrel exports
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics whenever possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic in TypeScript files; avoid restating TypeScript types and signatures in prose

Files:

  • apps/dashboard/next.config.ts
  • packages/thirdweb/src/wallets/smart/smart-wallet-modular.test.ts
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration-v07.test.ts
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
apps/dashboard/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)

apps/dashboard/**/*.{ts,tsx}: Always import from the central UI library under @/components/ui/* for reusable core UI components like Button, Input, Select, Tabs, Card, Sidebar, Separator, Badge
Use NavLink from @/components/ui/NavLink for internal navigation to ensure active states are handled automatically
For notices and skeletons, rely on AnnouncementBanner, GenericLoadingPage, and EmptyStateCard components
Import icons from lucide-react or the project-specific …/icons exports; never embed raw SVG
Keep components pure; fetch data outside using server components or hooks and pass it down via props
Use Tailwind CSS as the styling system; avoid inline styles or CSS modules
Merge class names with cn from @/lib/utils to keep conditional logic readable
Stick to design tokens: use bg-card, border-border, text-muted-foreground and other Tailwind variables instead of hard-coded colors
Use spacing utilities (px-*, py-*, gap-*) instead of custom margins
Follow mobile-first responsive design with Tailwind helpers (max-sm, md, lg, xl)
Never hard-code colors; always use Tailwind variables
Combine class names via cn, and expose className prop if useful in components
Use React Query (@tanstack/react-query) for all client-side data fetching with typed hooks

Files:

  • apps/dashboard/next.config.ts
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
**/*.{js,jsx,ts,tsx,json}

📄 CodeRabbit inference engine (AGENTS.md)

Biome governs formatting and linting; its rules live in biome.json. Run pnpm fix & pnpm lint before committing, ensure there are no linting errors

Files:

  • apps/dashboard/next.config.ts
  • packages/thirdweb/src/wallets/smart/smart-wallet-modular.test.ts
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration-v07.test.ts
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
apps/{dashboard,playground}/**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/**/*.{tsx,ts}: Import UI primitives from @/components/ui/_ (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in Dashboard and Playground apps
Use NavLink for internal navigation so active states are handled automatically
Use Tailwind CSS for styling – no inline styles or CSS modules
Merge class names with cn() from @/lib/utils to keep conditional logic readable
Stick to design tokens for styling: backgrounds (bg-card), borders (border-border), muted text (text-muted-foreground), etc.
Server Components: Read cookies/headers with next/headers, access server-only environment variables or secrets, perform heavy data fetching, implement redirect logic with redirect() from next/navigation, and start files with import 'server-only'; to prevent client bundling
Client Components: Begin files with 'use client'; before imports, handle interactive UI relying on React hooks (useState, useEffect, React Query, wallet hooks), access browser APIs (localStorage, window, IntersectionObserver, etc.), and support fast transitions with client-side data prefetching
For client-side data fetching: Wrap calls in React Query (@tanstack/react-query), use descriptive and stable queryKeys for cache hits, configure staleTime / cacheTime based on freshness requirements (default ≥ 60 s), and keep tokens secret by calling internal API routes or server actions

Files:

  • apps/dashboard/next.config.ts
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/**/*.{ts,tsx}: For server-side data fetching: Always call getAuthToken() to retrieve the JWT from cookies and inject the token as an Authorization: Bearer header – never embed it in the URL. Return typed results (Project[], User[], …) – avoid any
Never import posthog-js in server components; analytics reporting is client-side only

Files:

  • apps/dashboard/next.config.ts
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Lazy-import optional features; avoid top-level side-effects

Files:

  • apps/dashboard/next.config.ts
  • packages/thirdweb/src/wallets/smart/smart-wallet-modular.test.ts
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration-v07.test.ts
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.test.{ts,tsx}: Place tests alongside code: foo.tsfoo.test.ts in the same directory
Use real function invocations with stub data in tests; avoid brittle mocks
Use Mock Service Worker (MSW) for fetch/HTTP call interception in tests
Keep tests deterministic and side-effect free
Use predefined test accounts from test/src/test-wallets.ts in tests
Use FORKED_ETHEREUM_CHAIN for mainnet interactions and ANVIL_CHAIN for isolated tests

**/*.test.{ts,tsx}: Co-locate tests with source files using the pattern foo.ts ↔ foo.test.ts
Use real function invocations with stub data in tests; avoid brittle mocks
For network interactions in tests, use Mock Service Worker (MSW) to intercept fetch/HTTP calls, mocking only scenarios that are hard to reproduce
Keep tests deterministic and side-effect free; Vitest is pre-configured

Files:

  • packages/thirdweb/src/wallets/smart/smart-wallet-modular.test.ts
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration-v07.test.ts
packages/thirdweb/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

packages/thirdweb/src/**/*.{ts,tsx}: Comment only ambiguous logic in SDK code; avoid restating TypeScript in prose
Load heavy dependencies inside async paths to keep initial bundle lean (e.g. const { jsPDF } = await import("jspdf");)

Lazy-load heavy dependencies inside async paths to keep the initial bundle lean (e.g., const { jsPDF } = await import('jspdf');)

Files:

  • packages/thirdweb/src/wallets/smart/smart-wallet-modular.test.ts
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration-v07.test.ts
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/{dashboard,playground-web}/src/**/*.{ts,tsx}: Import UI component primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground
Use Tailwind CSS only – no inline styles or CSS modules in dashboard and playground
Use cn() from @/lib/utils for conditional Tailwind class merging
Use design system tokens for styling (backgrounds: bg-card, borders: border-border, muted text: text-muted-foreground)
Expose className prop on root element for component overrides

Files:

  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
apps/dashboard/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/dashboard/src/**/*.{ts,tsx}: Use NavLink for internal navigation with automatic active states in dashboard
Start server component files with import "server-only"; in Next.js
Read cookies/headers with next/headers in server components
Access server-only environment variables in server components
Perform heavy data fetching in server components
Implement redirect logic with redirect() from next/navigation in server components
Begin client component files with 'use client'; directive in Next.js
Handle interactive UI with React hooks (useState, useEffect, React Query, wallet hooks) in client components
Access browser APIs (localStorage, window, IntersectionObserver) in client components
Support fast transitions with prefetched data in client components
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header for API calls – never embed tokens in URLs
Return typed results (Project[], User[]) from server-side data fetches – avoid any
Wrap client-side API calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys in React Query for 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 – only use analytics client-side

Files:

  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
apps/dashboard/**/*.client.tsx

📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)

apps/dashboard/**/*.client.tsx: Name component files after the component in PascalCase; append .client.tsx when the component is interactive
Client components must start with 'use client'; directive before imports

Files:

  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
apps/dashboard/**/page.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)

Use the container class with a max-w-7xl cap for consistent page width

Files:

  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
🧬 Code graph analysis (2)
apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx (3)
apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsx (1)
  • bridgeWallets (11-20)
apps/dashboard/src/@/constants/thirdweb.server.ts (1)
  • getConfiguredThirdwebClient (26-97)
apps/dashboard/src/@/constants/public-envs.ts (1)
  • NEXT_PUBLIC_CHECKOUT_IFRAME_CLIENT_ID (48-49)
apps/dashboard/src/app/bridge/checkout-widget/page.tsx (6)
apps/dashboard/src/app/bridge/widget/page.tsx (1)
  • metadata (18-25)
apps/dashboard/src/app/bridge/_common/parseQueryParams.ts (3)
  • parseQueryParams (3-11)
  • onlyNumber (14-15)
  • onlyAddress (13-13)
apps/dashboard/src/app/bridge/_common/isValidCurrency.ts (1)
  • isValidCurrency (3-10)
apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx (1)
  • CheckoutWidgetEmbed (23-96)
apps/dashboard/src/@/constants/public-envs.ts (1)
  • NEXT_PUBLIC_CHECKOUT_IFRAME_CLIENT_ID (48-49)
apps/dashboard/src/app/bridge/(general)/components/client/Providers.client.tsx (1)
  • BridgeProviders (9-42)
⏰ 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: E2E Tests (pnpm, webpack)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: Lint Packages
  • GitHub Check: Unit Tests
  • GitHub Check: Size
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (2)
apps/dashboard/src/app/bridge/checkout-widget/page.tsx (2)

72-109: LGTM: Clear error messaging for missing parameters.

The validation logic correctly checks required parameters and provides a user-friendly error UI with specific guidance on what's missing. The error message clearly lists each missing parameter with examples.


141-143: LGTM: Environment validation in Providers wrapper.

Good defensive practice to validate the required environment variable and fail fast with a clear error message if it's not configured.

@codecov
Copy link

codecov bot commented Dec 19, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 53.26%. Comparing base (56a1c0a) to head (fdd2557).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8578      +/-   ##
==========================================
- Coverage   54.50%   53.26%   -1.25%     
==========================================
  Files         922      922              
  Lines       61386    61386              
  Branches     4171     4026     -145     
==========================================
- Hits        33459    32696     -763     
- Misses      27826    28593     +767     
+ Partials      101       97       -4     
Flag Coverage Δ
packages 53.26% <ø> (-1.25%) ⬇️
see 19 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.

@graphite-app
Copy link
Contributor

graphite-app bot commented Dec 19, 2025

Merge activity

<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing the `CheckoutWidget` and related components in the `thirdweb` application, including the removal of duplicate fiat price displays, adding new environment constants, and refining query parameter parsing for improved functionality and usability.

### Detailed summary
- Removed duplicate fiat price display in `CheckoutWidget`.
- Added `NEXT_PUBLIC_CHECKOUT_IFRAME_CLIENT_ID` constant.
- Introduced `parseQueryParams` utility for better query handling.
- Updated `CheckoutWidgetEmbed` to utilize new constants and improved query parsing.
- Added validation for required parameters in the checkout page.
- Refactored currency validation to use `isValidCurrency`.
- Modified tests to skip certain cases based on environment variables.

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

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Embeddable checkout widget with a dedicated checkout page/layout and a new public env var for iframe client ID.
  * Content-Security-Policy headers applied to checkout widget routes.

* **Bug Fixes**
  * Removed duplicate fiat price display in the checkout button.

* **Chores / Refactor**
  * Centralized query-parameter parsing and currency validation; added input sanitization utilities.
  * Added a patch-level changeset entry.

* **Tests**
  * Marked several integration tests as skipped by default; enabled one parallel-execution test.

<sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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: 1

♻️ Duplicate comments (9)
packages/thirdweb/src/wallets/smart/smart-wallet-modular.test.ts (1)

31-31: Tests are permanently disabled without explanation.

The entire smart wallet modular test suite is now unconditionally skipped, removing test coverage for critical functionality. This issue has already been raised in previous reviews.

packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts (3)

51-51: Remove the suite-level skip or add detailed explanation for why integration tests are disabled.

The entire SmartWallet integration test suite is unconditionally skipped, eliminating test coverage for 14 core integration scenarios. This issue has already been raised in previous reviews.


122-122: Add a comment explaining why this test is skipped.

This test for ERC-1271 signatures after deployment is skipped without explanation. This issue has already been raised in previous reviews.


322-323: Test enabled despite FIXME comment claiming it always fails.

The FIXME comment at line 322 explicitly states "this test always fails," yet the test is now active (not skipped). This creates a contradiction:

  • If the test genuinely always fails, it should be it.skip to prevent CI failures
  • If the test has been fixed, remove the FIXME comment
🔎 Recommended fix

Either skip the test:

-    // FIXME: this test always fails
-    it("can execute 2 tx in parallel", async () => {
+    it.skip("can execute 2 tx in parallel", async () => {

Or remove the outdated FIXME if the test now passes:

-    // FIXME: this test always fails
     it("can execute 2 tx in parallel", async () => {
apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx (3)

12-21: Extract duplicated wallet configuration to a shared module.

As noted in the previous review, the bridgeWallets array is duplicated from UniversalBridgeEmbed.tsx. Extract this to a shared location like @/constants/wallets.ts to follow DRY principles.


98-115: Security: postMessage with wildcard origin.

As noted in the previous review, using "*" as the targetOrigin in postMessage allows any parent window to receive these messages. If the messages contain sensitive data, this could be a security risk.

Consider restricting the target origin to known trusted origins or document that the payload contains only non-sensitive transaction status information.


10-10: Add 'server-only' guard to thirdweb.server.ts or create a client-safe wrapper.

As noted in the previous review, importing from thirdweb.server.ts in a client component is fragile. While the current usage with secretKey: undefined is safe, the pattern could lead to accidental exposure of server-only code.

Based on coding guidelines.

apps/dashboard/src/app/bridge/widget/page.tsx (1)

1-13: Add "server-only" import to prevent client bundling.

As noted in the previous review, this server component should start with import "server-only"; to ensure it isn't accidentally bundled for the client.

Based on coding guidelines.

apps/dashboard/src/app/bridge/checkout-widget/page.tsx (1)

1-14: Add "server-only" import to prevent client bundling.

As noted in the previous review, this server component should start with import "server-only"; to ensure it isn't accidentally bundled for the client.

Based on coding guidelines.

📜 Review details

Configuration used: Organization 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 116c326 and fdd2557.

📒 Files selected for processing (13)
  • .changeset/short-wasps-show.md (1 hunks)
  • apps/dashboard/next.config.ts (1 hunks)
  • apps/dashboard/src/@/constants/public-envs.ts (1 hunks)
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts (1 hunks)
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts (1 hunks)
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/checkout-widget/layout.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx (1 hunks)
  • apps/dashboard/src/app/bridge/widget/page.tsx (2 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx (1 hunks)
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration-v07.test.ts (3 hunks)
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts (4 hunks)
  • packages/thirdweb/src/wallets/smart/smart-wallet-modular.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/dashboard/src/app/bridge/_common/isValidCurrency.ts
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration-v07.test.ts
  • apps/dashboard/src/@/constants/public-envs.ts
  • apps/dashboard/src/app/bridge/checkout-widget/layout.tsx
🧰 Additional context used
📓 Path-based instructions (12)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each TypeScript 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 in TypeScript
Avoid any and unknown in TypeScript unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.) in TypeScript

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity and testability
Re-use shared types from @/types or local types.ts barrel exports
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics whenever possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic in TypeScript files; avoid restating TypeScript types and signatures in prose

Files:

  • packages/thirdweb/src/wallets/smart/smart-wallet-modular.test.ts
  • apps/dashboard/next.config.ts
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts
  • apps/dashboard/src/app/bridge/widget/page.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.test.{ts,tsx}: Place tests alongside code: foo.tsfoo.test.ts in the same directory
Use real function invocations with stub data in tests; avoid brittle mocks
Use Mock Service Worker (MSW) for fetch/HTTP call interception in tests
Keep tests deterministic and side-effect free
Use predefined test accounts from test/src/test-wallets.ts in tests
Use FORKED_ETHEREUM_CHAIN for mainnet interactions and ANVIL_CHAIN for isolated tests

**/*.test.{ts,tsx}: Co-locate tests with source files using the pattern foo.ts ↔ foo.test.ts
Use real function invocations with stub data in tests; avoid brittle mocks
For network interactions in tests, use Mock Service Worker (MSW) to intercept fetch/HTTP calls, mocking only scenarios that are hard to reproduce
Keep tests deterministic and side-effect free; Vitest is pre-configured

Files:

  • packages/thirdweb/src/wallets/smart/smart-wallet-modular.test.ts
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts
packages/thirdweb/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

packages/thirdweb/src/**/*.{ts,tsx}: Comment only ambiguous logic in SDK code; avoid restating TypeScript in prose
Load heavy dependencies inside async paths to keep initial bundle lean (e.g. const { jsPDF } = await import("jspdf");)

Lazy-load heavy dependencies inside async paths to keep the initial bundle lean (e.g., const { jsPDF } = await import('jspdf');)

Files:

  • packages/thirdweb/src/wallets/smart/smart-wallet-modular.test.ts
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
**/*.{js,jsx,ts,tsx,json}

📄 CodeRabbit inference engine (AGENTS.md)

Biome governs formatting and linting; its rules live in biome.json. Run pnpm fix & pnpm lint before committing, ensure there are no linting errors

Files:

  • packages/thirdweb/src/wallets/smart/smart-wallet-modular.test.ts
  • apps/dashboard/next.config.ts
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts
  • apps/dashboard/src/app/bridge/widget/page.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Lazy-import optional features; avoid top-level side-effects

Files:

  • packages/thirdweb/src/wallets/smart/smart-wallet-modular.test.ts
  • apps/dashboard/next.config.ts
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
  • packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts
  • apps/dashboard/src/app/bridge/widget/page.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
apps/dashboard/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)

apps/dashboard/**/*.{ts,tsx}: Always import from the central UI library under @/components/ui/* for reusable core UI components like Button, Input, Select, Tabs, Card, Sidebar, Separator, Badge
Use NavLink from @/components/ui/NavLink for internal navigation to ensure active states are handled automatically
For notices and skeletons, rely on AnnouncementBanner, GenericLoadingPage, and EmptyStateCard components
Import icons from lucide-react or the project-specific …/icons exports; never embed raw SVG
Keep components pure; fetch data outside using server components or hooks and pass it down via props
Use Tailwind CSS as the styling system; avoid inline styles or CSS modules
Merge class names with cn from @/lib/utils to keep conditional logic readable
Stick to design tokens: use bg-card, border-border, text-muted-foreground and other Tailwind variables instead of hard-coded colors
Use spacing utilities (px-*, py-*, gap-*) instead of custom margins
Follow mobile-first responsive design with Tailwind helpers (max-sm, md, lg, xl)
Never hard-code colors; always use Tailwind variables
Combine class names via cn, and expose className prop if useful in components
Use React Query (@tanstack/react-query) for all client-side data fetching with typed hooks

Files:

  • apps/dashboard/next.config.ts
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
  • apps/dashboard/src/app/bridge/widget/page.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
apps/{dashboard,playground}/**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/**/*.{tsx,ts}: Import UI primitives from @/components/ui/_ (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in Dashboard and Playground apps
Use NavLink for internal navigation so active states are handled automatically
Use Tailwind CSS for styling – no inline styles or CSS modules
Merge class names with cn() from @/lib/utils to keep conditional logic readable
Stick to design tokens for styling: backgrounds (bg-card), borders (border-border), muted text (text-muted-foreground), etc.
Server Components: Read cookies/headers with next/headers, access server-only environment variables or secrets, perform heavy data fetching, implement redirect logic with redirect() from next/navigation, and start files with import 'server-only'; to prevent client bundling
Client Components: Begin files with 'use client'; before imports, handle interactive UI relying on React hooks (useState, useEffect, React Query, wallet hooks), access browser APIs (localStorage, window, IntersectionObserver, etc.), and support fast transitions with client-side data prefetching
For client-side data fetching: Wrap calls in React Query (@tanstack/react-query), use descriptive and stable queryKeys for cache hits, configure staleTime / cacheTime based on freshness requirements (default ≥ 60 s), and keep tokens secret by calling internal API routes or server actions

Files:

  • apps/dashboard/next.config.ts
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
  • apps/dashboard/src/app/bridge/widget/page.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/**/*.{ts,tsx}: For server-side data fetching: Always call getAuthToken() to retrieve the JWT from cookies and inject the token as an Authorization: Bearer header – never embed it in the URL. Return typed results (Project[], User[], …) – avoid any
Never import posthog-js in server components; analytics reporting is client-side only

Files:

  • apps/dashboard/next.config.ts
  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
  • apps/dashboard/src/app/bridge/widget/page.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/{dashboard,playground-web}/src/**/*.{ts,tsx}: Import UI component primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground
Use Tailwind CSS only – no inline styles or CSS modules in dashboard and playground
Use cn() from @/lib/utils for conditional Tailwind class merging
Use design system tokens for styling (backgrounds: bg-card, borders: border-border, muted text: text-muted-foreground)
Expose className prop on root element for component overrides

Files:

  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
  • apps/dashboard/src/app/bridge/widget/page.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
apps/dashboard/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/dashboard/src/**/*.{ts,tsx}: Use NavLink for internal navigation with automatic active states in dashboard
Start server component files with import "server-only"; in Next.js
Read cookies/headers with next/headers in server components
Access server-only environment variables in server components
Perform heavy data fetching in server components
Implement redirect logic with redirect() from next/navigation in server components
Begin client component files with 'use client'; directive in Next.js
Handle interactive UI with React hooks (useState, useEffect, React Query, wallet hooks) in client components
Access browser APIs (localStorage, window, IntersectionObserver) in client components
Support fast transitions with prefetched data in client components
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header for API calls – never embed tokens in URLs
Return typed results (Project[], User[]) from server-side data fetches – avoid any
Wrap client-side API calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys in React Query for 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 – only use analytics client-side

Files:

  • apps/dashboard/src/app/bridge/_common/parseQueryParams.ts
  • apps/dashboard/src/app/bridge/widget/page.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
apps/dashboard/**/page.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)

Use the container class with a max-w-7xl cap for consistent page width

Files:

  • apps/dashboard/src/app/bridge/widget/page.tsx
  • apps/dashboard/src/app/bridge/checkout-widget/page.tsx
apps/dashboard/**/*.client.tsx

📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)

apps/dashboard/**/*.client.tsx: Name component files after the component in PascalCase; append .client.tsx when the component is interactive
Client components must start with 'use client'; directive before imports

Files:

  • apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx
🧬 Code graph analysis (2)
apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx (3)
apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsx (1)
  • bridgeWallets (11-20)
apps/dashboard/src/@/constants/thirdweb.server.ts (1)
  • getConfiguredThirdwebClient (26-97)
apps/dashboard/src/@/constants/public-envs.ts (1)
  • NEXT_PUBLIC_CHECKOUT_IFRAME_CLIENT_ID (48-49)
apps/dashboard/src/app/bridge/checkout-widget/page.tsx (5)
apps/dashboard/src/app/bridge/_common/parseQueryParams.ts (3)
  • parseQueryParams (3-11)
  • onlyNumber (14-15)
  • onlyAddress (13-13)
apps/dashboard/src/app/bridge/_common/isValidCurrency.ts (1)
  • isValidCurrency (3-10)
apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx (1)
  • CheckoutWidgetEmbed (23-96)
apps/dashboard/src/@/constants/public-envs.ts (1)
  • NEXT_PUBLIC_CHECKOUT_IFRAME_CLIENT_ID (48-49)
apps/dashboard/src/app/bridge/(general)/components/client/Providers.client.tsx (1)
  • BridgeProviders (9-42)
⏰ 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). (7)
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: Size
  • GitHub Check: Unit Tests
  • GitHub Check: Lint Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (11)
packages/thirdweb/src/react/web/ui/Bridge/DirectPayment.tsx (1)

165-165: LGTM! Clean simplification.

The direct fallback pattern is idiomatic and improves readability.

.changeset/short-wasps-show.md (1)

1-5: LGTM!

The changeset entry clearly documents the patch-level UI change to remove duplicate fiat price display.

apps/dashboard/next.config.ts (1)

164-181: LGTM!

The CSP headers for the checkout widget routes follow the established pattern used for the bridge widget routes. The configuration properly allows iframe embedding by using EmbedContentSecurityPolicy with frame-ancestors *.

apps/dashboard/src/app/bridge/_common/parseQueryParams.ts (3)

3-11: LGTM!

The parseQueryParams function provides clean, type-safe query parameter parsing with proper handling of string, array, and undefined values.


13-13: LGTM!

The onlyAddress validator correctly uses isAddress from the thirdweb library to validate addresses.


14-15: LGTM!

The onlyNumber validator correctly handles number conversion and returns undefined for invalid numbers.

apps/dashboard/src/app/bridge/widget/page.tsx (1)

37-74: LGTM!

The refactoring to use centralized parseQueryParams and isValidCurrency utilities improves code organization and maintainability while preserving the original behavior.

apps/dashboard/src/app/bridge/checkout-widget/CheckoutWidgetEmbed.client.tsx (1)

52-60: LGTM!

The client initialization correctly uses the public environment variable and explicitly passes undefined for server-only credentials.

apps/dashboard/src/app/bridge/checkout-widget/page.tsx (3)

16-27: LGTM!

The metadata export provides clear SEO-friendly title and description for the checkout widget page.


38-109: LGTM!

The query parameter parsing and validation logic is well-structured:

  • Clear separation between required and optional parameters
  • Proper validation using centralized utilities
  • User-friendly error UI that lists specific missing parameters with examples

134-152: LGTM!

The Providers wrapper correctly validates the required environment variable and provides a clear error message if it's missing.

});

it("should use ERC-1271 typed data signatures after deployment", async () => {
it.skip("should use ERC-1271 typed data signatures after deployment", async () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find and read the test file
FILE="packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts"
if [ -f "$FILE" ]; then
  # Show lines 110-170 to capture both line 122 and 155
  echo "=== File content from line 110 to 170 ==="
  sed -n '110,170p' "$FILE"
else
  echo "File not found"
fi

Repository: thirdweb-dev/js

Length of output: 1889


Add explanatory comments to skipped ERC-1271 tests.

Both it.skip tests on lines 122 and 155 lack documentation explaining why they're disabled. Add inline comments describing the issue (e.g., flaky behavior, race condition after deployment) and link to any tracking issue if one exists. This helps future maintainers understand whether these tests can be re-enabled and when.

🤖 Prompt for AI Agents
In packages/thirdweb/src/wallets/smart/smart-wallet-integration.test.ts around
lines 122 and 155, both it.skip tests are missing explanatory comments; add a
short inline comment above each skipped test that explains why it is disabled
(e.g., flaky, race condition after deployment, external dependency instability),
include a link to any existing tracking/GitHub issue or ticket (or reference "no
issue filed" if none), and note the date and owner/author who skipped it so
maintainers can reassess later.

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

Labels

Dashboard Involves changes to the Dashboard. packages SDK Involves changes to the thirdweb SDK

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants