-
Notifications
You must be signed in to change notification settings - Fork 619
[Docs] Replace custom API endpoint with OpenAPI component #7829
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Docs] Replace custom API endpoint with OpenAPI component #7829
Conversation
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
|
WalkthroughAdds an OpenAPI-driven documentation flow: introduces OpenApiEndpoint and DynamicRequestExample, extends ApiEndpoint/RequestExample types and rendering (multiple examples, query/path/header params, reference links), replaces many static HTTP examples across portal MDX pages, removes a local EndpointMetadata component, and tweaks dependencies and minor UI text/layout. Changes
Sequence Diagram(s)sequenceDiagram
participant Page as MDX Page
participant OpenApi as OpenApiEndpoint
participant Fetch as OpenAPI Spec
participant Transform as Transform Spec
participant ApiUI as ApiEndpoint
participant DynEx as DynamicRequestExample
participant ReqEx as RequestExample
Page->>OpenApi: render with { path, method, [specUrl], [overrides] }
OpenApi->>Fetch: fetch(specUrl)
Fetch-->>OpenApi: OpenAPI JSON
OpenApi->>Transform: build ApiEndpointMeta
Transform-->>OpenApi: ApiEndpointMeta
OpenApi->>ApiUI: <ApiEndpoint metadata />
alt multiple request examples
ApiUI->>DynEx: render dynamic examples + params
else single example
ApiUI->>ReqEx: render example
end
sequenceDiagram
participant DynEx as DynamicRequestExample
participant User as User
participant ReqEx as RequestExample
participant Params as Parameter Sections
DynEx->>ReqEx: provide code examples (fetch/curl, types)
DynEx->>Params: render headers/path/query/body sections
User->>DynEx: change format or example type
DynEx->>ReqEx: update selected example
DynEx->>Params: update shown body parameters
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7829 +/- ##
=======================================
Coverage 56.32% 56.32%
=======================================
Files 905 905
Lines 58820 58820
Branches 4148 4148
=======================================
Hits 33133 33133
Misses 25581 25581
Partials 106 106
🚀 New features to boost your workflow:
|
size-limit report 📦
|
Updated wallet and payments documentation to reflect new authentication and user management endpoints, including /v1/auth/initiate and /v1/auth/complete. Improved API reference sections, added OpenApiEndpoint usage, clarified pregeneration and user listing flows, and enhanced code samples for Unity and .NET SDKs. Refactored APIEndpoint component to show query parameters and examples, and updated AuthMethodsTabs to use new auth endpoints.
9014fb8 to
61a12fb
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 10
🔭 Outside diff range comments (2)
apps/portal/src/components/Document/AuthMethodsTabs.tsx (1)
125-146: Fix endpoint domain to match PR intent and OpenAPI migration (thirdweb-dev.com).The HTTP snippets still point to api.thirdweb.com, but PR objectives and the high-level summary indicate moving OTP/auth routes to api.thirdweb-dev.com. Update both initiate and complete endpoints for email and phone flows.
Apply this diff:
-POST https://api.thirdweb.com/v1/auth/initiate +POST https://api.thirdweb-dev.com/v1/auth/initiate-POST https://api.thirdweb.com/v1/auth/complete +POST https://api.thirdweb-dev.com/v1/auth/completeAlso applies to: 151-172
apps/portal/src/app/contracts/page.mdx (1)
23-23: Remove or fix lucide-react import to satisfy lint rulePer repository rule, icons must use the Icon suffix; also this symbol isn’t used. Remove it to avoid lint errors.
Apply this diff:
-import { ExternalLink } from "lucide-react";
🧹 Nitpick comments (22)
apps/portal/src/components/Document/AuthMethodsTabs.tsx (1)
120-177: Optional: DRY the base URL to prevent future drift.Both email and phone snippets duplicate the auth base URL. Centralizing it reduces the risk of future mismatches.
Add near the top-level (outside the snippet builders):
const AUTH_BASE = "https://api.thirdweb-dev.com/v1/auth";Then interpolate in the HTTP snippet strings:
- POST ${AUTH_BASE}/initiate
- POST ${AUTH_BASE}/complete
apps/portal/src/app/payments/page.mdx (1)
185-206: Update wording in “Complete Payment” sectionIn apps/portal/src/app/payments/page.mdx (around line 197), the description uses “product ID” but should reference the payment ID. Apply:
- Complete a payment using the product ID: + Complete a payment using the payment ID:Please also verify that the following
<OpenApiEndpoint>entries match your published OpenAPI spec:
- POST /v1/payments
- POST /v1/payments/{id}
- POST /v1/payments/swap
apps/portal/src/components/Document/Details.tsx (2)
6-17: Add an explicit return type to match TS guidelines.Be explicit about the component’s return type.
Apply this diff:
-export function Details(props: { +export function Details(props: { summary: React.ReactNode; children: React.ReactNode; level?: number; headingClassName?: string; anchorId?: string; tags?: string[]; noIndex?: boolean; startExpanded?: boolean; accordionItemClassName?: string; accordionTriggerClassName?: string; -}) { +}): React.ReactElement | null {
25-26: Confirm the named Tailwind group is intended; otherwise simplify.You have both a named group on the container (
group/details) and a defaultgroupon the trigger container. If the named group isn’t used by any variant (e.g.,group-hover/details:), you can simplify to justgroupto reduce class noise.Apply this diff if the named group is unused:
- "group/details border-b-0 border-l transition-colors hover:border-active-border my-2", + "group border-b-0 border-l transition-colors hover:border-active-border my-2",apps/portal/src/app/wallets/get-users/page.mdx (1)
31-47: Avoid duplicating params/headers; rely on OpenAPI rendering to prevent driftMaintaining manual “Query Parameters” and “Authentication” sections alongside OpenApiEndpoint invites inconsistencies. The OpenAPI-driven component should be the single source of truth.
Apply this diff to remove the duplicated sections:
-### Query Parameters - -You can query by any of these user identifiers: - -- `address`: The user's wallet address that thirdweb generated -- `email`: The user's email address -- `phone`: The user's phone number -- `externalWalletAddress`: The user's external wallet address (SIWE login) -- `id`: The user's ID (for custom auth) - -### Authentication - -Required headers: -- `x-secret-key`: Your secret key for authentication -- `x-ecosystem-id` (optional): Your ecosystem ID -- `x-ecosystem-partner-id` (optional): Your ecosystem partner IDapps/portal/src/app/wallets/server/page.mdx (1)
46-67: Minimize manual example overrides to avoid spec driftThe responseExampleOverride is helpful, but it can diverge from the actual schema over time (e.g., field names/types). Prefer relying on the spec’s examples unless there’s a temporary gap.
If not strictly needed, apply this diff to defer to OpenAPI examples:
-<OpenApiEndpoint path="/v1/wallets/server" method="GET" responseExampleOverride={{ - result: { - pagination: { - hasMore: false, - limit: 20, - page: 1, - }, - wallets: [ - { - address: "string", - profiles: [ - { - type: "server", - identifier: "string", - }, - ], - createdAt: "string", - smartWalletAddress: "string", - }, - ], - } -}} /> +<OpenApiEndpoint path="/v1/wallets/server" method="GET" />apps/portal/src/app/wallets/custom-auth/page.mdx (1)
33-33: Fix typo: OIDC (not OICD)Update the tab label.
Apply this diff:
- <TabsTrigger value="jwt">JWT (OICD)</TabsTrigger> + <TabsTrigger value="jwt">JWT (OIDC)</TabsTrigger>apps/portal/src/app/contracts/deploy/page.mdx (1)
37-47: Clarify the optional salt in SDK snippetUsing property shorthand for an undefined variable may confuse readers. Explicitly show the value or mark it optional inline.
Apply this diff:
- constructorParams: { - param1: "value1", - param2: 123, - }, - salt, // optional: salt enables deterministic deploys + constructorParams: { + param1: "value1", + param2: 123, + }, + // optional: salt enables deterministic deploys + salt: "0x...optional-salt",apps/portal/src/app/page.tsx (1)
28-39: Add explicit return types and consider extracting subcomponentsPer repository TypeScript guidelines, add explicit return types (e.g., JSX.Element) and consider extracting subcomponents to keep one stateless, single-responsibility function per file (especially for larger pages).
Example for one function:
-export default function Page() { +export default function Page(): JSX.Element {Repeat for Hero, AISection, ReferenceSection, LearningResourcesSection, SectionTitle, ArticleCardIndex, and SDKCard.
Also applies to: 41-77, 78-105, 106-171, 172-216, 218-224, 229-255, 257-285
apps/portal/src/app/wallets/pregenerate-wallets/page.mdx (1)
27-27: Consider specifying specUrl explicitly for consistency and resiliencyOther pages (e.g., AI Chat) pass specUrl to OpenApiEndpoint. Adding it here avoids relying on implicit defaults and protects against environment drift.
Apply this diff:
-<OpenApiEndpoint path="/v1/wallets/user" method="POST" /> +<OpenApiEndpoint path="/v1/wallets/user" method="POST" specUrl="https://api.thirdweb-dev.com/openapi.json" />apps/portal/src/components/Document/APIEndpointMeta/DynamicRequestExample.tsx (4)
28-70: Add explicit return types to align with TS guidelinesAnnotate component return types for clarity and safer refactors.
Apply this diff:
-function InlineParameterItem({ param }: { param: APIParameter }) { +function InlineParameterItem({ param }: { param: APIParameter }): React.ReactElement {-function ParameterSection(props: { +function ParameterSection(props: { title: string; parameters: APIParameter[]; -}) { +}): React.ReactElement | null {-export function DynamicRequestExample(props: DynamicRequestExampleProps) { +export function DynamicRequestExample(props: DynamicRequestExampleProps): React.ReactElement {
51-66: Improve readability of example JSON and handle objects robustlyPretty-print JSON for object/array examples to improve legibility.
Apply this diff:
- code={ - typeof param.example === "object" - ? JSON.stringify(param.example) - : String(param.example) - } + code={ + typeof param.example === "object" + ? JSON.stringify(param.example, null, 2) + : String(param.example) + }
10-26: Prefer a type alias over interface for props per project conventionsThis aligns with the repo guideline to favor type aliases except for nominal types.
Apply this diff:
-interface DynamicRequestExampleProps { +type DynamicRequestExampleProps = { requestExamples: Array<{ lang: "javascript" | "bash"; code: string; label: string; format: "fetch" | "curl"; exampleType?: string; bodyParameters?: APIParameter[]; }>; endpointUrl: string; referenceUrl: string; method: string; pathParameters: APIParameter[]; headers: APIParameter[]; queryParameters: APIParameter[]; hasMultipleExamples: boolean; -} +};
28-108: Optional: co-locate smaller components or split file to meet single-responsibility guidelineFile currently defines three components. Consider nesting InlineParameterItem and ParameterSection inside DynamicRequestExample or moving them to their own files for clearer separation.
apps/portal/src/app/contracts/page.mdx (1)
72-83: Consider specifying specUrl on OpenApiEndpoint (consistency with other pages)AI Chat page passes specUrl explicitly. Aligning here improves clarity and avoids relying on hidden defaults.
Apply this diff:
- <OpenApiEndpoint path="/v1/contracts/read" method="POST" /> + <OpenApiEndpoint path="/v1/contracts/read" method="POST" specUrl="https://api.thirdweb-dev.com/openapi.json" /> ... - <OpenApiEndpoint path="/v1/contracts/write" method="POST" /> + <OpenApiEndpoint path="/v1/contracts/write" method="POST" specUrl="https://api.thirdweb-dev.com/openapi.json" />apps/portal/src/components/Document/APIEndpointMeta/RequestExample.tsx (1)
14-31: Add explicit return type to RequestExampleAligns with the guideline to declare explicit return types for TS components.
Apply this diff:
-export function RequestExample(props: { +export function RequestExample(props: { codeExamples: Array<{ label: string; code: React.ReactElement; format?: "fetch" | "curl"; exampleType?: string; }>; method: string; endpointUrl: string; referenceUrl: string; onExampleChange?: (label: string) => void; onFormatChange?: (format: "fetch" | "curl") => void; onExampleTypeChange?: (exampleType: string) => void; hasSeparateDropdowns?: boolean; selectedExample?: (typeof props.codeExamples)[0]; selectedFormat?: "fetch" | "curl"; selectedExampleType?: string; -}) { +}): React.ReactElement {apps/portal/src/components/Document/APIEndpointMeta/OpenApiEndpoint.tsx (4)
32-192: Consider simplifying the circular reference detection logicThe current implementation adds and deletes from the
visitedset multiple times. You can simplify this by cloning the set for recursive calls instead of using try/finally blocks.Consider this simpler approach:
-function generateExampleFromSchema(schema: any, visited = new Set()): any { +function generateExampleFromSchema(schema: any, visited = new Set<any>()): any { // Prevent infinite recursion with circular references if (visited.has(schema)) { return {}; } if (!schema || typeof schema !== "object") { return null; } // If there's an explicit example, use it if (schema.example !== undefined) { return schema.example; } // If there are examples array, use the first one if ( schema.examples && Array.isArray(schema.examples) && schema.examples.length > 0 ) { return schema.examples[0]; } // If there's a default value, use it if (schema.default !== undefined) { return schema.default; } - visited.add(schema); + const newVisited = new Set(visited); + newVisited.add(schema); - try { switch (schema.type) { // ... rest of the switch cases, passing newVisited instead of visited case "array": if (schema.items) { - const itemExample = generateExampleFromSchema(schema.items, visited); + const itemExample = generateExampleFromSchema(schema.items, newVisited); return [itemExample]; } return []; // ... continue pattern for other recursive calls } - } finally { - visited.delete(schema); - }
246-276: Consider extracting hardcoded headers to a configuration objectThe hardcoded headers and their properties should be extracted to a configuration object for better maintainability and reusability across different parts of the application.
+const DEFAULT_HEADERS: APIParameter[] = [ + { + name: "x-secret-key", + type: "backend", + description: + "Project secret key - for backend usage only. Should not be used in frontend code.", + required: false, + example: undefined, + }, + { + name: "x-client-id", + type: "frontend", + description: + "Project client ID - for frontend usage on authorized domains.", + required: false, + example: undefined, + }, + { + name: "x-ecosystem-id", + type: "optional", + description: "Ecosystem ID - for ecosystem wallets.", + required: false, + example: undefined, + }, + { + name: "x-ecosystem-partner-id", + type: "optional", + description: "Ecosystem partner ID - for ecosystem wallets.", + required: false, + example: undefined, + }, +]; function transformOpenApiToApiEndpointMeta( spec: OpenApiSpec, path: string, method: string, requestBodyOverride?: Record<string, any>, responseExampleOverride?: Record<string, string>, ): ApiEndpointMeta { // ... existing code ... // push default headers hardcoded for now - headers.push({ - name: "x-secret-key", - type: "backend", - description: - "Project secret key - for backend usage only. Should not be used in frontend code.", - required: false, - example: undefined, - }); - headers.push({ - name: "x-client-id", - type: "frontend", - description: - "Project client ID - for frontend usage on authorized domains.", - required: false, - example: undefined, - }); - headers.push({ - name: "x-ecosystem-id", - type: "optional", - description: "Ecosystem ID - for ecosystem wallets.", - required: false, - example: undefined, - }); - headers.push({ - name: "x-ecosystem-partner-id", - type: "optional", - description: "Ecosystem partner ID - for ecosystem wallets.", - required: false, - example: undefined, - }); + headers.push(...DEFAULT_HEADERS);
278-290: Extract authentication logic to improve maintainabilityThe authentication header logic should be extracted to make it clearer and easier to maintain when authentication requirements change.
+function shouldAddAuthorizationHeader(method: string, path: string): boolean { + return ( + method === "POST" && + !path.includes("/v1/contracts/read") && + !path.includes("/v1/auth") + ); +} // In transformOpenApiToApiEndpointMeta function: - if ( - method === "POST" && - !path.includes("/v1/contracts/read") && - !path.includes("/v1/auth") - ) { + if (shouldAddAuthorizationHeader(method, path)) { headers.push({ name: "Authorization", type: "frontend", description: "Bearer token (JWT) for user wallet authentication", required: false, example: undefined, }); }
474-501: Improve error handling specificityThe error message could be more helpful by including the specific path and method that failed to load.
async function OpenApiEndpointInner({ specUrl = "https://api.thirdweb.com/openapi.json", path, method = "GET", requestBodyOverride, responseExampleOverride, }: OpenApiEndpointProps) { try { const spec = await fetchOpenApiSpec(specUrl); const metadata = transformOpenApiToApiEndpointMeta( spec, path, method, requestBodyOverride, responseExampleOverride, ); return <ApiEndpoint metadata={metadata} key={specUrl + path + method} />; } catch (error) { return ( <div className="rounded-lg border border-red-200 bg-red-50 p-4"> <div className="text-sm text-red-800"> - Failed to load OpenAPI specification:{" "} + Failed to load OpenAPI specification for {method} {path}:{" "} {error instanceof Error ? error.message : "Unknown error"} </div> </div> ); } }apps/portal/src/app/wallets/page.mdx (1)
443-447: Update code comment to match the actual implementationThe comment mentions "fetch the otp" but the
SendOTPmethod appears to send rather than fetch the OTP.```csharp var wallet = await InAppWallet.Create(client: client, email: "userEmail"); -await wallet.SendOTP(); // and fetch the otp +await wallet.SendOTP(); // sends OTP to the user's email var address = await wallet.LoginWithOtp("userEnteredOTP"); // try catch and retry if neededapps/portal/src/components/Document/APIEndpointMeta/ApiEndpoint.tsx (1)
407-409: Fallback value for body parameters without examples may cause confusionWhen a body parameter lacks an example, the code falls back to using the parameter type as the value (Line 409). This could generate confusing examples like
{"name": "string"}instead of realistic values.Consider providing more meaningful fallback values based on the parameter type:
for (const param of request.bodyParameters) { if (param.example !== undefined) { bodyObj[param.name] = param.example; } else { - bodyObj[param.name] = param.type || ""; + // Provide more meaningful fallback values + switch (param.type) { + case "string": + bodyObj[param.name] = `<${param.name}>`; + break; + case "number": + case "integer": + bodyObj[param.name] = 0; + break; + case "boolean": + bodyObj[param.name] = false; + break; + case "array": + bodyObj[param.name] = []; + break; + case "object": + bodyObj[param.name] = {}; + break; + default: + bodyObj[param.name] = `<${param.name}>`; + } } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (27)
apps/playground-web/package.json(1 hunks)apps/portal/package.json(1 hunks)apps/portal/src/app/ai/chat/EndpointMetadata.tsx(0 hunks)apps/portal/src/app/ai/chat/page.mdx(2 hunks)apps/portal/src/app/ai/sidebar.tsx(1 hunks)apps/portal/src/app/contracts/deploy/page.mdx(3 hunks)apps/portal/src/app/contracts/events/page.mdx(2 hunks)apps/portal/src/app/contracts/page.mdx(2 hunks)apps/portal/src/app/contracts/transactions/page.mdx(2 hunks)apps/portal/src/app/page.tsx(3 hunks)apps/portal/src/app/payments/page.mdx(2 hunks)apps/portal/src/app/transactions/monitor/page.mdx(2 hunks)apps/portal/src/app/transactions/page.mdx(2 hunks)apps/portal/src/app/transactions/sponsor/page.mdx(3 hunks)apps/portal/src/app/wallets/custom-auth/page.mdx(3 hunks)apps/portal/src/app/wallets/get-users/page.mdx(2 hunks)apps/portal/src/app/wallets/page.mdx(7 hunks)apps/portal/src/app/wallets/pregenerate-wallets/page.mdx(2 hunks)apps/portal/src/app/wallets/server/page.mdx(2 hunks)apps/portal/src/components/Document/APIEndpointMeta/ApiEndpoint.tsx(5 hunks)apps/portal/src/components/Document/APIEndpointMeta/DynamicRequestExample.tsx(1 hunks)apps/portal/src/components/Document/APIEndpointMeta/OpenApiEndpoint.tsx(1 hunks)apps/portal/src/components/Document/APIEndpointMeta/RequestExample.tsx(3 hunks)apps/portal/src/components/Document/APIEndpointMeta/common.tsx(0 hunks)apps/portal/src/components/Document/AuthMethodsTabs.tsx(4 hunks)apps/portal/src/components/Document/Details.tsx(2 hunks)apps/portal/src/components/Document/index.ts(1 hunks)
💤 Files with no reviewable changes (2)
- apps/portal/src/components/Document/APIEndpointMeta/common.tsx
- apps/portal/src/app/ai/chat/EndpointMetadata.tsx
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
Files:
apps/portal/src/app/ai/sidebar.tsxapps/portal/src/components/Document/Details.tsxapps/portal/src/components/Document/APIEndpointMeta/DynamicRequestExample.tsxapps/portal/src/components/Document/AuthMethodsTabs.tsxapps/portal/src/components/Document/APIEndpointMeta/OpenApiEndpoint.tsxapps/portal/src/components/Document/index.tsapps/portal/src/app/page.tsxapps/portal/src/components/Document/APIEndpointMeta/RequestExample.tsxapps/portal/src/components/Document/APIEndpointMeta/ApiEndpoint.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit Inference Engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
apps/portal/src/app/ai/sidebar.tsxapps/portal/src/components/Document/Details.tsxapps/portal/src/components/Document/APIEndpointMeta/DynamicRequestExample.tsxapps/portal/src/components/Document/AuthMethodsTabs.tsxapps/portal/src/components/Document/APIEndpointMeta/OpenApiEndpoint.tsxapps/portal/src/components/Document/index.tsapps/portal/src/app/page.tsxapps/portal/src/components/Document/APIEndpointMeta/RequestExample.tsxapps/portal/src/components/Document/APIEndpointMeta/ApiEndpoint.tsx
🧠 Learnings (9)
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Use React Query (`tanstack/react-query`) for all client data fetching.
Applied to files:
apps/portal/src/components/Document/APIEndpointMeta/DynamicRequestExample.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).
Applied to files:
apps/portal/src/components/Document/APIEndpointMeta/DynamicRequestExample.tsxapps/portal/src/components/Document/APIEndpointMeta/RequestExample.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Applied to files:
apps/portal/src/components/Document/index.ts
📚 Learning: 2025-07-07T21:21:47.488Z
Learnt from: saminacodes
PR: thirdweb-dev/js#7543
File: apps/portal/src/app/pay/page.mdx:4-4
Timestamp: 2025-07-07T21:21:47.488Z
Learning: In the thirdweb-dev/js repository, lucide-react icons must be imported with the "Icon" suffix (e.g., ExternalLinkIcon, RocketIcon) as required by the new linting rule, contrary to the typical lucide-react convention of importing without the suffix.
Applied to files:
apps/portal/src/app/page.tsxapps/portal/src/components/Document/APIEndpointMeta/RequestExample.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Icons come from `lucide-react` or the project-specific `…/icons` exports – never embed raw SVG.
Applied to files:
apps/portal/src/app/page.tsxapps/portal/src/components/Document/APIEndpointMeta/RequestExample.tsx
📚 Learning: 2025-07-31T16:17:42.753Z
Learnt from: MananTank
PR: thirdweb-dev/js#7768
File: apps/playground-web/src/app/navLinks.ts:1-1
Timestamp: 2025-07-31T16:17:42.753Z
Learning: Configuration files that import and reference React components (like icon components from lucide-react) need the "use client" directive, even if they primarily export static data, because the referenced components need to be executed in a client context when used by other client components.
Applied to files:
apps/portal/src/components/Document/APIEndpointMeta/RequestExample.tsx
📚 Learning: 2025-06-18T04:27:16.172Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7365
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.tsx:16-17
Timestamp: 2025-06-18T04:27:16.172Z
Learning: Next.js Link component supports external URLs without throwing errors. When used with absolute URLs (like https://...), it behaves like a regular anchor tag without client-side routing, but does not cause runtime crashes or errors as previously believed.
Applied to files:
apps/portal/src/components/Document/APIEndpointMeta/RequestExample.tsx
📚 Learning: 2025-06-18T04:30:04.326Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7365
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.tsx:16-17
Timestamp: 2025-06-18T04:30:04.326Z
Learning: Next.js Link component fully supports both internal and external URLs and works appropriately with all standard anchor attributes including target="_blank", rel="noopener noreferrer", etc. Using Link for external URLs is completely appropriate and recommended.
Applied to files:
apps/portal/src/components/Document/APIEndpointMeta/RequestExample.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to packages/thirdweb/src/wallets/** : Support for in-app wallets (social/email login)
Applied to files:
apps/portal/src/app/wallets/page.mdx
🧬 Code Graph Analysis (5)
apps/portal/src/components/Document/Details.tsx (1)
apps/playground-web/src/lib/utils.ts (1)
cn(5-7)
apps/portal/src/components/Document/APIEndpointMeta/DynamicRequestExample.tsx (4)
apps/portal/src/components/Document/APIEndpointMeta/ApiEndpoint.tsx (1)
APIParameter(9-20)apps/portal/src/components/code/code.client.tsx (2)
CodeClient(27-54)CodeLoading(19-25)apps/portal/src/components/Document/Details.tsx (1)
Details(6-64)apps/portal/src/components/Document/APIEndpointMeta/RequestExample.tsx (1)
RequestExample(14-188)
apps/portal/src/components/Document/APIEndpointMeta/OpenApiEndpoint.tsx (2)
apps/portal/src/components/Document/APIEndpointMeta/ApiEndpoint.tsx (3)
ApiEndpointMeta(27-43)APIParameter(9-20)ApiEndpoint(45-229)apps/portal/src/components/Document/index.ts (1)
OpenApiEndpoint(6-6)
apps/portal/src/components/Document/APIEndpointMeta/RequestExample.tsx (1)
apps/portal/src/icons/index.ts (1)
ExternalLinkIcon(4-4)
apps/portal/src/components/Document/APIEndpointMeta/ApiEndpoint.tsx (3)
apps/portal/src/components/Document/APIEndpointMeta/DynamicRequestExample.tsx (1)
DynamicRequestExample(112-209)apps/portal/src/components/Document/APIEndpointMeta/RequestExample.tsx (1)
RequestExample(14-188)apps/portal/src/components/Document/Details.tsx (1)
Details(6-64)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Size
- GitHub Check: Analyze (javascript)
🔇 Additional comments (22)
apps/portal/src/components/Document/AuthMethodsTabs.tsx (1)
120-177: No lingering auth endpoint references outside AuthMethodsTabs.tsxA global search for
/v1/auth/initiateand/v1/auth/completematches only in
apps/portal/src/components/Document/AuthMethodsTabs.tsx(lines 125, 134, 151, 160).
No occurrences found in MDX pages,ApiEndpoint.tsx, orOpenApiEndpoint.tsx.apps/portal/src/components/Document/index.ts (1)
6-6: OpenApiEndpoint named export verifiedThe
OpenApiEndpointexport inapps/portal/src/components/Document/index.tscorrectly surfaces the namedOpenApiEndpointfunction fromAPIEndpointMeta/OpenApiEndpoint.tsx(line 466). MDX pages can now import it via@doc. LGTM.apps/portal/src/app/transactions/monitor/page.mdx (3)
9-10: ImportingOpenApiEndpointinto this page matches the new docs architecture.
48-53: Nice addition of “List transactions” endpoint for completeness.
42-47: OpenApiEndpoint “GET” support and spec path confirmed
OpenApiEndpointProps.methodunion type includes"GET".- The OpenAPI spec at https://api.thirdweb.com/openapi.json contains a
/v1/transactions/{transactionId}GET operation.No changes required.
apps/portal/src/app/contracts/events/page.mdx (2)
6-7: ImportingOpenApiEndpointaligns this page with OpenAPI-driven rendering.
35-35: No stale query-param references remain in docs
Searches for/v1/contracts/{address}/events?chainId=across apps/portal returned no matches—all links now use the{chainId}path parameter.apps/portal/src/app/contracts/transactions/page.mdx (1)
6-7: Verify OpenAPI path and parameter rendering for contracts transactionsSwapping to OpenApiEndpoint looks good. Please confirm the OpenAPI spec exposes path params (chainId, address) and any relevant query params (e.g., decode/filters) so we don’t lose detail that the old inline docs provided.
Also applies to: 25-25
apps/portal/src/app/wallets/get-users/page.mdx (1)
56-83: Confirm the correct endpoint for “Get All Users”Both “Single” and “All” tabs point to GET /v1/wallets/user. If listing is served by a separate endpoint (e.g., /v1/wallets/users or a different path), update the All Users tab accordingly. If the same endpoint lists when no identifier is provided, consider clarifying that behavior in the text.
apps/portal/src/app/wallets/server/page.mdx (1)
36-41: LGTM on switching to OpenApiEndpoint for server wallet creationThis succinctly replaces the static docs and centralizes details in the OpenAPI spec.
apps/portal/src/app/wallets/custom-auth/page.mdx (1)
71-75: Confirm /v1/auth/complete request shapesBoth examples target POST /v1/auth/complete with requestBodyOverride types "jwt" and "auth-payload". Please verify these discriminator values and the payload structure align with the OpenAPI schema, and that any required headers are rendered by OpenApiEndpoint.
Also applies to: 194-198
apps/portal/src/app/contracts/deploy/page.mdx (2)
1-10: Metadata export and OpenAPI-powered sections look goodConsistent with the overall migration to OpenApiEndpoint.
68-79: LGTM on adding API sections via OpenApiEndpointEndpoints for creating and listing contracts are now driven by the spec, reducing duplication.
apps/portal/src/app/page.tsx (1)
1-7: Icon import style complies with repo conventionlucide-react icons are imported with the Icon suffix, matching the enforced lint rule.
apps/portal/src/app/transactions/page.mdx (1)
72-82: Good move to OpenApiEndpoint for raw transaction sendingCentralizes request/response details and keeps the docs consistent with the API spec.
apps/portal/src/app/transactions/sponsor/page.mdx (1)
134-156: Engine (ERC-4337) example reads clearlyUsing the Engine write endpoint with executionOptions is appropriate for ERC-4337 and clearly differentiated from the high-level API.
apps/portal/src/app/wallets/pregenerate-wallets/page.mdx (1)
27-27: No action needed: endpoint confirmed
The POST/v1/wallets/useroperation is present in the OpenAPI spec, so this component can be merged as is.apps/portal/src/components/Document/APIEndpointMeta/DynamicRequestExample.tsx (1)
140-189: No additional guard needed for empty requestExamples in DynamicRequestExampleThe
ApiEndpointcomponent already only rendersDynamicRequestExamplewhenrequest.requestExamples.length > 0, so insideDynamicRequestExampleyou’re guaranteed a non-empty array. Adding{props.requestExamples.length > 0 && ...}is therefore unnecessary.Likely an incorrect or invalid review comment.
apps/portal/src/app/contracts/page.mdx (1)
72-83: Endpoints Verified in OpenAPI SpecBoth
/v1/contracts/readand/v1/contracts/writePOST operations are present in the published OpenAPI spec, so no further action is needed here.apps/portal/src/app/ai/chat/page.mdx (2)
25-25: LGTM on OpenAPI integrationUsing OpenApiEndpoint with an explicit specUrl is clear and consistent. Nice.
36-45: Verified production API base URL consistencyI’ve confirmed that both the dev (
https://api.thirdweb-dev.com/openapi.json) and prod (https://api.thirdweb.com/openapi.json) OpenAPI specs include the/ai/chatendpoint. Usinghttps://api.thirdweb.com/aias thebase_urlis correct for targeting the production API. No changes required.apps/portal/src/components/Document/APIEndpointMeta/RequestExample.tsx (1)
82-91: Nice touch: link to external reference with iconClear affordance and correct rel/target usage. Looks good.
| "next-themes": "^0.4.6", | ||
| "nextjs-toploader": "^1.6.12", | ||
| "openapi-types": "^12.1.3", | ||
| "openapi-types": "12.1.3", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Pinning openapi-types is fine; verify if it should be a devDependency and align versions workspace-wide.
If openapi-types is only used for TypeScript types, prefer moving it to devDependencies to keep production/runtime deps lean. Also ensure all packages pin the same version to avoid duplication.
Run this script to (a) find all imports/usages of openapi-types and (b) report every package.json that declares it and where (dependencies vs devDependencies):
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Usages of 'openapi-types' across the repo =="
rg -n --hidden --no-ignore -g '!**/node_modules/**' -e "from ['\"]openapi-types['\"]|require\(['\"]openapi-types['\"]\)" || true
echo
echo "== package.json declarations of 'openapi-types' =="
fd -H -t f package.json | while read -r f; do
dep_ver=$(jq -r '.dependencies["openapi-types"] // empty' "$f")
dev_ver=$(jq -r '.devDependencies["openapi-types"] // empty' "$f")
if [[ -n "$dep_ver" || -n "$dev_ver" ]]; then
echo "$f"
if [[ -n "$dep_ver" ]]; then echo " dependencies: $dep_ver"; fi
if [[ -n "$dev_ver" ]]; then echo " devDependencies: $dev_ver"; fi
fi
doneLength of output: 4572
Move openapi-types to devDependencies and align versions
All imports of openapi-types in the repo are type‐only (import type { OpenAPIV3[_1] }…), so it does not need to ship at runtime. Currently it’s declared in dependencies in two spots:
• apps/playground-web/package.json (v12.1.3)
• apps/portal/package.json (v12.1.3)
Please:
- Remove
"openapi-types": "12.1.3"from dependencies in both package.json files - Add
"openapi-types": "12.1.3"under devDependencies in both - Confirm no other packages declare it (all should use v12.1.3)
🤖 Prompt for AI Agents
In apps/playground-web/package.json (around line 25) and
apps/portal/package.json (search for the same dependency), move "openapi-types":
"12.1.3" out of "dependencies" and add it under "devDependencies" with the same
version string; remove the entry from dependencies in both files, add it to
devDependencies in both, and run a quick repo-wide search to confirm no other
package.json declares "openapi-types" at a different version (update any found
to 12.1.3 or remove if unnecessary).
| "nextjs-toploader": "^1.6.12", | ||
| "node-html-markdown": "^1.3.0", | ||
| "node-html-parser": "^6.1.13", | ||
| "openapi-types": "12.1.3", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Confirm openapi-types needs to be a runtime dependency; otherwise move to devDependencies.
If only used for typing, keep it in devDependencies to avoid bloating prod lockfiles and potential client bundles.
Run the same verification script from the playground package review or this package-local check:
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Usages of 'openapi-types' in portal =="
rg -n --hidden --no-ignore -g 'apps/portal/**' -e "from ['\"]openapi-types['\"]|require\(['\"]openapi-types['\"]\)" || true
echo
echo "== portal/package.json declaration =="
jq '{dependencies: .dependencies["openapi-types"], devDependencies: .devDependencies["openapi-types"]}' apps/portal/package.jsonLength of output: 650
Move openapi-types to devDependencies
openapi-types is only imported as a TypeScript type in apps/portal/src/components/Document/APIEndpointMeta/OpenApiEndpoint.tsx and isn’t used at runtime. Keeping it in dependencies bloats production installs and client bundles.
Please update apps/portal/package.json:
• Remove from dependencies
• Add under devDependencies
Example diff:
--- apps/portal/package.json
@@ dependencies:
- "openapi-types": "12.1.3",
@@ devDependencies:
+ "openapi-types": "12.1.3",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "openapi-types": "12.1.3", | |
| --- apps/portal/package.json | |
| @@ "dependencies": { | |
| - "openapi-types": "12.1.3", | |
| @@ "devDependencies": { | |
| + "openapi-types": "12.1.3", |
🤖 Prompt for AI Agents
In apps/portal/package.json around line 27, move "openapi-types": "12.1.3" out
of dependencies and add the same entry under devDependencies; remove the
key/value from the dependencies object, insert it into devDependencies, then run
your package manager (npm/yarn/pnpm) to update lockfiles so production installs
no longer include this type-only package.
| name: "Streaming Responses", | ||
| href: "/ai/chat/streaming", | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Rename to “Streaming Responses” looks good; verify route exists and unify API reference domain.
- Ensure
/ai/chat/streamingpage exists to avoid dead links. - The API Reference link below uses
api.thirdweb-dev.comwhile other pages in this PR useapi.thirdweb.com. Consider switching to the canonical domain or centralizing as a constant.
Script to check the page exists and to find any lingering api.thirdweb-dev.com references:
Apply this diff to normalize the API Reference domain in this file:
- href: "https://api.thirdweb-dev.com/reference#tag/ai/post/ai/chat",
+ href: "https://api.thirdweb.com/reference#tag/ai/post/ai/chat",🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Verify streaming page exists (any of TSX/MDX)
if test -d "apps/portal/src/app/ai/chat/streaming"; then
fd -t f . apps/portal/src/app/ai/chat/streaming
else
echo "Missing: apps/portal/src/app/ai/chat/streaming"
exit 1
fi
# Find dev-domain API references across repo
echo
echo "Occurrences of api.thirdweb-dev.com/reference:"
rg -n --hidden --no-ignore -e "api\.thirdweb-dev\.com/reference" || trueLength of output: 581
Confirm /ai/chat/streaming route exists and normalize API Reference domain
- Verified that
apps/portal/src/app/ai/chat/streaming/page.mdximplements the/ai/chat/streamingroute. - Update all remaining
api.thirdweb-dev.comreferences to the canonicalapi.thirdweb.com:
• apps/portal/src/app/ai/sidebar.tsx (around line 21):
- href: "https://api.thirdweb-dev.com/reference#tag/ai/post/ai/chat",
+ href: "https://api.thirdweb.com/reference#tag/ai/post/ai/chat",• apps/portal/src/app/ai/chat/page.mdx (around line 55):
- [Full API Reference](https://api.thirdweb-dev.com/reference#tag/ai/post/ai/chat)
+ [Full API Reference](https://api.thirdweb.com/reference#tag/ai/post/ai/chat)Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In apps/portal/src/app/ai/sidebar.tsx around lines 16 to 18, the sidebar link
points to /ai/chat/streaming (confirming the route exists is already done) and
you must also normalize the API domain across the project: replace any remaining
occurrences of api.thirdweb-dev.com with api.thirdweb.com (specifically update
apps/portal/src/app/ai/sidebar.tsx near line 21 and
apps/portal/src/app/ai/chat/page.mdx near line 55) so all references use the
canonical api.thirdweb.com domain.
| Example sponsored contract write request: | ||
|
|
||
| { | ||
| "from": "0x...", // your user or server wallet **EOA address** address | ||
| "chainId": "1", // your chain id | ||
| "calls": [{ | ||
| "contractAddress": "0x...", | ||
| "method": "function transfer(address to, uint256 amount)", | ||
| "params": ["0x...", "1000000000000000000"], | ||
| }], | ||
| } | ||
| ``` | ||
| <OpenApiEndpoint path="/v1/contracts/write" method="POST" /> | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Align EIP-7702 example with the standard transactions endpoint
Other docs use POST /v1/transactions for thirdweb API. Using /v1/contracts/write here may be legacy/inconsistent and could confuse readers.
Apply this diff to align the endpoint:
-Example sponsored contract write request:
-
-<OpenApiEndpoint path="/v1/contracts/write" method="POST" />
+Example sponsored transaction request:
+
+<OpenApiEndpoint path="/v1/transactions" method="POST" />📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Example sponsored contract write request: | |
| { | |
| "from": "0x...", // your user or server wallet **EOA address** address | |
| "chainId": "1", // your chain id | |
| "calls": [{ | |
| "contractAddress": "0x...", | |
| "method": "function transfer(address to, uint256 amount)", | |
| "params": ["0x...", "1000000000000000000"], | |
| }], | |
| } | |
| ``` | |
| <OpenApiEndpoint path="/v1/contracts/write" method="POST" /> | |
| Example sponsored transaction request: | |
| <OpenApiEndpoint path="/v1/transactions" method="POST" /> |
🤖 Prompt for AI Agents
In apps/portal/src/app/transactions/sponsor/page.mdx around lines 60 to 63, the
example uses the legacy/incorrect endpoint POST /v1/contracts/write; update it
to use the standard thirdweb transactions endpoint POST /v1/transactions so it
matches other docs. Replace the OpenApiEndpoint path value from
"/v1/contracts/write" to "/v1/transactions" (keeping method="POST") and verify
any surrounding text or examples reference the transactions endpoint
consistently.
|
|
||
| import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; | ||
| import { useEffect, useState } from "react"; | ||
| import CodeClient, { CodeLoading } from "../../code/code.client"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix incorrect import: CodeClient is a named export, not default
code.client.tsx exports CodeClient as a named export. The default import will be undefined at runtime.
Apply this diff:
-import CodeClient, { CodeLoading } from "../../code/code.client";
+import { CodeClient, CodeLoading } from "../../code/code.client";📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import CodeClient, { CodeLoading } from "../../code/code.client"; | |
| import { CodeClient, CodeLoading } from "../../code/code.client"; |
🤖 Prompt for AI Agents
In apps/portal/src/components/Document/APIEndpointMeta/DynamicRequestExample.tsx
around line 5, the file currently does a default import of CodeClient which is
actually exported as a named export; replace the default import with a named
import so both symbols are imported correctly (e.g. import { CodeClient,
CodeLoading } from "../../code/code.client";), then save and run the app to
verify the runtime error is resolved.
| .sort((a, b) => { | ||
| if (a.required === b.required) { | ||
| return 0; | ||
| } | ||
| return a.required ? -1 : 1; | ||
| }) | ||
| .map((param) => ( | ||
| <InlineParameterItem key={param.name} param={param} /> | ||
| ))} | ||
| </div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid mutating props when sorting parameters
Array.prototype.sort mutates in place; this mutates props.parameters. Copy before sorting.
Apply this diff:
- {props.parameters
- .sort((a, b) => {
+ {[...props.parameters]
+ .sort((a, b) => {
if (a.required === b.required) {
return 0;
}
return a.required ? -1 : 1;
})
.map((param) => (
<InlineParameterItem key={param.name} param={param} />
))}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| .sort((a, b) => { | |
| if (a.required === b.required) { | |
| return 0; | |
| } | |
| return a.required ? -1 : 1; | |
| }) | |
| .map((param) => ( | |
| <InlineParameterItem key={param.name} param={param} /> | |
| ))} | |
| </div> | |
| {[...props.parameters] | |
| .sort((a, b) => { | |
| if (a.required === b.required) { | |
| return 0; | |
| } | |
| return a.required ? -1 : 1; | |
| }) | |
| .map((param) => ( | |
| <InlineParameterItem key={param.name} param={param} /> | |
| ))} | |
| </div> |
🤖 Prompt for AI Agents
In apps/portal/src/components/Document/APIEndpointMeta/DynamicRequestExample.tsx
around lines 95 to 104, the code calls .sort() directly on props.parameters
which mutates the original array; create a non-mutating copy (e.g., spread or
slice) of the parameters before sorting and then map over that sorted copy so
props.parameters are not mutated.
| const [selectedFormat, setSelectedFormat] = useState<"fetch" | "curl">( | ||
| "fetch", | ||
| ); | ||
| const [selectedExampleType, setSelectedExampleType] = useState<string>(""); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Initialize selectedFormat based on available examples to avoid mismatched UI
Defaulting to "fetch" when no fetch example exists causes a mismatch (dropdown shows Fetch but code shows Curl). Initialize from props.requestExamples.
Apply this diff:
- const [selectedFormat, setSelectedFormat] = useState<"fetch" | "curl">(
- "fetch",
- );
+ const [selectedFormat, setSelectedFormat] = useState<"fetch" | "curl">(() => {
+ if (props.requestExamples.some((ex) => ex.format === "fetch")) {
+ return "fetch";
+ }
+ return (props.requestExamples[0]?.format as "fetch" | "curl") ?? "fetch";
+ });📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const [selectedFormat, setSelectedFormat] = useState<"fetch" | "curl">( | |
| "fetch", | |
| ); | |
| const [selectedExampleType, setSelectedExampleType] = useState<string>(""); | |
| const [selectedFormat, setSelectedFormat] = useState<"fetch" | "curl">(() => { | |
| if (props.requestExamples.some((ex) => ex.format === "fetch")) { | |
| return "fetch"; | |
| } | |
| return (props.requestExamples[0]?.format as "fetch" | "curl") ?? "fetch"; | |
| }); | |
| const [selectedExampleType, setSelectedExampleType] = useState<string>(""); |
🤖 Prompt for AI Agents
In apps/portal/src/components/Document/APIEndpointMeta/DynamicRequestExample.tsx
around lines 113 to 116, the state initializes selectedFormat to "fetch" and
selectedExampleType to an empty string which can mismatch UI when a fetch
example is not provided. Change the initialization to derive selectedFormat from
props.requestExamples (pick "fetch" if a fetch example exists, otherwise "curl"
or the first available format) and initialize selectedExampleType to a valid key
from requestExamples (e.g., first example type) so the dropdown and displayed
code always match the available examples.
| // Initialize selected example type from first available example | ||
| useEffect(() => { | ||
| if (props.requestExamples.length > 0) { | ||
| const firstExampleType = | ||
| props.requestExamples.find((ex) => ex.format === "fetch") | ||
| ?.exampleType || ""; | ||
| setSelectedExampleType(firstExampleType); | ||
| } | ||
| }, [props.requestExamples]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Initialize exampleType using the currently selected format, not hardcoded "fetch"
This avoids empty selections when fetch isn’t available.
Apply this diff:
- const firstExampleType =
- props.requestExamples.find((ex) => ex.format === "fetch")
- ?.exampleType || "";
+ const firstExampleType =
+ props.requestExamples.find((ex) => ex.format === selectedFormat)
+ ?.exampleType || props.requestExamples[0]?.exampleType || "";📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Initialize selected example type from first available example | |
| useEffect(() => { | |
| if (props.requestExamples.length > 0) { | |
| const firstExampleType = | |
| props.requestExamples.find((ex) => ex.format === "fetch") | |
| ?.exampleType || ""; | |
| setSelectedExampleType(firstExampleType); | |
| } | |
| }, [props.requestExamples]); | |
| // Initialize selected example type from first available example | |
| useEffect(() => { | |
| if (props.requestExamples.length > 0) { | |
| const firstExampleType = | |
| props.requestExamples.find((ex) => ex.format === selectedFormat) | |
| ?.exampleType || props.requestExamples[0]?.exampleType || ""; | |
| setSelectedExampleType(firstExampleType); | |
| } | |
| }, [props.requestExamples]); |
🤖 Prompt for AI Agents
In apps/portal/src/components/Document/APIEndpointMeta/DynamicRequestExample.tsx
around lines 118-126, the useEffect initializes the selected exampleType by
searching for an example with format === "fetch"; change it to search for the
example whose format matches the currently selected format (props.selectedFormat
or the component's selectedFormat prop/state) instead of the hardcoded "fetch",
and if no example matches that format fall back to the first available example's
exampleType (or empty string if none), then call setSelectedExampleType with
that resolved value.
| const [internalSelectedExample, setInternalSelectedExample] = useState( | ||
| props.codeExamples[0], | ||
| ); | ||
| const [internalSelectedFormat, setInternalSelectedFormat] = useState< | ||
| "fetch" | "curl" | ||
| >("fetch"); | ||
| const [internalSelectedExampleType, setInternalSelectedExampleType] = | ||
| useState<string>(""); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Initialize internal state safely when codeExamples updates
If codeExamples changes (or initially loads), ensure the internal state tracks the first available example to prevent undefined selection.
Apply this diff:
const [internalSelectedExample, setInternalSelectedExample] = useState(
props.codeExamples[0],
);
@@
const [internalSelectedExampleType, setInternalSelectedExampleType] =
useState<string>("");
+
+ // Keep internal selection in sync if codeExamples change (uncontrolled mode)
+ useEffect(() => {
+ if (!props.selectedExample && props.codeExamples[0]) {
+ setInternalSelectedExample((prev) => prev ?? props.codeExamples[0]);
+ }
+ }, [props.codeExamples, props.selectedExample]);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const [internalSelectedExample, setInternalSelectedExample] = useState( | |
| props.codeExamples[0], | |
| ); | |
| const [internalSelectedFormat, setInternalSelectedFormat] = useState< | |
| "fetch" | "curl" | |
| >("fetch"); | |
| const [internalSelectedExampleType, setInternalSelectedExampleType] = | |
| useState<string>(""); | |
| const [internalSelectedExample, setInternalSelectedExample] = useState( | |
| props.codeExamples[0], | |
| ); | |
| const [internalSelectedFormat, setInternalSelectedFormat] = useState< | |
| "fetch" | "curl" | |
| >("fetch"); | |
| const [internalSelectedExampleType, setInternalSelectedExampleType] = | |
| useState<string>(""); | |
| // Keep internal selection in sync if codeExamples change (uncontrolled mode) | |
| useEffect(() => { | |
| if (!props.selectedExample && props.codeExamples[0]) { | |
| setInternalSelectedExample((prev) => prev ?? props.codeExamples[0]); | |
| } | |
| }, [props.codeExamples, props.selectedExample]); |
🤖 Prompt for AI Agents
In apps/portal/src/components/Document/APIEndpointMeta/RequestExample.tsx around
lines 32-40, the initial internal state is set from props.codeExamples but it
won't update when codeExamples loads/changes; add a useEffect that watches
props.codeExamples and, if the array has at least one element, sets
internalSelectedExample to props.codeExamples[0] and sets
internalSelectedExampleType to the first example's type (or "" if missing),
otherwise clear internalSelectedExample and internalSelectedExampleType; keep
internalSelectedFormat default as "fetch".
| <span | ||
| className={cn( | ||
| "break-all font-bold text-foreground text-lg tracking-tight", | ||
| "break-all font-bold text-foreground text-sm tracking-tight", | ||
| "flex w-full gap-3 text-left font-semibold text-foreground group-hover:underline", | ||
| props.headingClassName, | ||
| )} | ||
| > | ||
| {props.summary} | ||
| </h4> | ||
| </span> | ||
| {props.tags && props.tags.length > 0 && ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Restore heading semantics for accessibility (role/level) after switching from h4 to span.
Using a span drops heading semantics. Either use a heading tag or add ARIA attributes.
Apply this diff to add a11y attributes without changing layout:
- <span
+ <span
+ role="heading"
+ aria-level={props.level ?? 4}
className={cn(
"break-all font-bold text-foreground text-sm tracking-tight",
"flex w-full gap-3 text-left font-semibold text-foreground group-hover:underline",
props.headingClassName,
)}
>
{props.summary}
</span>Additionally, consider reinstating an actual heading tag (e.g., h4) if possible to improve document outline.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <span | |
| className={cn( | |
| "break-all font-bold text-foreground text-lg tracking-tight", | |
| "break-all font-bold text-foreground text-sm tracking-tight", | |
| "flex w-full gap-3 text-left font-semibold text-foreground group-hover:underline", | |
| props.headingClassName, | |
| )} | |
| > | |
| {props.summary} | |
| </h4> | |
| </span> | |
| {props.tags && props.tags.length > 0 && ( | |
| <span | |
| role="heading" | |
| aria-level={props.level ?? 4} | |
| className={cn( | |
| "break-all font-bold text-foreground text-sm tracking-tight", | |
| "flex w-full gap-3 text-left font-semibold text-foreground group-hover:underline", | |
| props.headingClassName, | |
| )} | |
| > | |
| {props.summary} | |
| </span> | |
| {props.tags && props.tags.length > 0 && ( |
🤖 Prompt for AI Agents
In apps/portal/src/components/Document/Details.tsx around lines 31 to 40, the
span that was used for the document heading removed native heading semantics;
update the element to restore accessibility by adding role="heading" and
aria-level="4" (or another appropriate level) to the span so it acts as a
heading without changing layout, keeping the existing className and content;
alternatively, replace the span with an actual heading tag (e.g., h4) if that
does not break styling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (7)
apps/portal/src/app/nebula/api-reference/execute/EndpointMetadata.tsx (1)
39-39: Same verification and nit as noted in update-session EndpointMetadata
- Verify ApiEndpoint type compatibility for referenceUrl (Line 39) and request.queryParameters (Line 41).
- Consider centralizing the docs base URL to avoid drift.
- Nit: add explicit return type to EndpointMetadata().
Also applies to: 41-41
apps/portal/src/app/nebula/api-reference/get-session/EndpointMetadata.tsx (1)
18-19: Same verification and nit as noted in update-session EndpointMetadata
- Verify ApiEndpoint type compatibility for referenceUrl (Lines 18-19) and request.queryParameters (Line 24).
- Consider centralizing the docs base URL to avoid drift.
- Nit: add explicit return type to EndpointMetadata().
Also applies to: 24-24
apps/portal/src/app/nebula/api-reference/chat/EndpointMetadata.tsx (1)
33-33: Same verification and nit as noted in update-session EndpointMetadata
- Verify ApiEndpoint type compatibility for referenceUrl (Line 33) and request.queryParameters (Line 35).
- Consider centralizing the docs base URL to avoid drift.
- Nit: add explicit return type to EndpointMetadata().
Also applies to: 35-35
apps/portal/src/app/nebula/api-reference/list-session/EndpointMetadata.tsx (1)
27-28: Same verification and nit as noted in update-session EndpointMetadata
- Verify ApiEndpoint type compatibility for referenceUrl (Lines 27-28) and request.queryParameters (Line 33).
- Consider centralizing the docs base URL to avoid drift.
- Nit: add explicit return type to EndpointMetadata().
Also applies to: 33-33
apps/portal/src/app/nebula/api-reference/create-session/EndpointMetadata.tsx (1)
18-19: Same verification and nit as noted in update-session EndpointMetadata
- Verify ApiEndpoint type compatibility for referenceUrl (Lines 18-19) and request.queryParameters (Line 21).
- Consider centralizing the docs base URL to avoid drift.
- Nit: add explicit return type to EndpointMetadata().
Also applies to: 21-21
apps/portal/src/app/nebula/api-reference/delete-session/EndpointMetadata.tsx (1)
25-26: Same verification and nit as noted in update-session EndpointMetadata
- Verify ApiEndpoint type compatibility for referenceUrl (Lines 25-26) and request.queryParameters (Line 28).
- Consider centralizing the docs base URL to avoid drift.
- Nit: add explicit return type to EndpointMetadata().
Also applies to: 28-28
apps/portal/src/app/nebula/api-reference/clear-session/EndpointMetadata.tsx (1)
18-19: Same verification and nit as noted in update-session EndpointMetadata
- Verify ApiEndpoint type compatibility for referenceUrl (Lines 18-19) and request.queryParameters (Line 21).
- Consider centralizing the docs base URL to avoid drift.
- Nit: add explicit return type to EndpointMetadata().
Also applies to: 21-21
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
apps/portal/src/app/nebula/api-reference/chat/EndpointMetadata.tsx(1 hunks)apps/portal/src/app/nebula/api-reference/clear-session/EndpointMetadata.tsx(1 hunks)apps/portal/src/app/nebula/api-reference/create-session/EndpointMetadata.tsx(1 hunks)apps/portal/src/app/nebula/api-reference/delete-session/EndpointMetadata.tsx(1 hunks)apps/portal/src/app/nebula/api-reference/execute/EndpointMetadata.tsx(1 hunks)apps/portal/src/app/nebula/api-reference/get-session/EndpointMetadata.tsx(1 hunks)apps/portal/src/app/nebula/api-reference/list-session/EndpointMetadata.tsx(1 hunks)apps/portal/src/app/nebula/api-reference/update-session/EndpointMetadata.tsx(2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
Files:
apps/portal/src/app/nebula/api-reference/update-session/EndpointMetadata.tsxapps/portal/src/app/nebula/api-reference/execute/EndpointMetadata.tsxapps/portal/src/app/nebula/api-reference/list-session/EndpointMetadata.tsxapps/portal/src/app/nebula/api-reference/get-session/EndpointMetadata.tsxapps/portal/src/app/nebula/api-reference/clear-session/EndpointMetadata.tsxapps/portal/src/app/nebula/api-reference/chat/EndpointMetadata.tsxapps/portal/src/app/nebula/api-reference/delete-session/EndpointMetadata.tsxapps/portal/src/app/nebula/api-reference/create-session/EndpointMetadata.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit Inference Engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
apps/portal/src/app/nebula/api-reference/update-session/EndpointMetadata.tsxapps/portal/src/app/nebula/api-reference/execute/EndpointMetadata.tsxapps/portal/src/app/nebula/api-reference/list-session/EndpointMetadata.tsxapps/portal/src/app/nebula/api-reference/get-session/EndpointMetadata.tsxapps/portal/src/app/nebula/api-reference/clear-session/EndpointMetadata.tsxapps/portal/src/app/nebula/api-reference/chat/EndpointMetadata.tsxapps/portal/src/app/nebula/api-reference/delete-session/EndpointMetadata.tsxapps/portal/src/app/nebula/api-reference/create-session/EndpointMetadata.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). (4)
- GitHub Check: Size
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Build Packages
- GitHub Check: Analyze (javascript)
| referenceUrl: | ||
| "https://api.thirdweb.com/reference#tag/ai/ai/update-session", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Reference URL anchor and empty queryParameters: verify compatibility and consider centralizing
- Good call adding a direct referenceUrl (Lines 19-20) and explicit request.queryParameters: [] (Line 33) for consistency across endpoints.
- Please verify that ApiEndpoint’s prop/types accept these new fields (referenceUrl, request.queryParameters) to avoid TS breakage in the skipped component files.
- Suggest centralizing the docs base URL to avoid drift/typos across files. Example: const NEBULA_REF_BASE = "https://api.thirdweb.com/reference#tag/ai/ai"; then use
${NEBULA_REF_BASE}/update-session.
Nit (applies to all EndpointMetadata.* files in this PR): add an explicit return type to comply with our TS guideline.
Outside-selected-range change example:
export function EndpointMetadata(): JSX.Element {
return (
<ApiEndpoint
metadata={{ /* ... */ }}
/>
);
}Run this to confirm type support and spot any mismatches:
Also applies to: 33-33
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Searching ApiEndpoint component/type for 'referenceUrl' and 'queryParameters'..."
fd -a 'ApiEndpoint.tsx' | while read -r f; do
echo "== $f =="
rg -n -A 5 -B 5 -e 'referenceUrl' -e 'queryParameters' -e 'ApiEndpoint' "$f" || true
done
echo
echo "Searching for metadata type definitions possibly used by ApiEndpoint..."
rg -n -A 5 -B 5 -S -e 'ApiEndpoint.*Props' -e 'ApiEndpointMetadata' -e 'OpenApiEndpoint'
echo
echo "Verifying all Nebula EndpointMetadata files set referenceUrl and queryParameters consistently..."
fd -a 'EndpointMetadata.tsx' apps/portal/src/app/nebula/api-reference | while read -r f; do
echo "--- $f ---"
rg -n 'referenceUrl|queryParameters' "$f" || true
doneLength of output: 42194
ApiEndpointMeta supports referenceUrl and queryParameters — centralize URL and add return types
- We’ve confirmed in
src/components/Document/APIEndpointMeta/ApiEndpoint.tsxthatso addingexport type ApiEndpointMeta = { referenceUrl: string; request: { queryParameters: APIParameter[]; … } … }
referenceUrland an emptyqueryParameters: []will not break TS. - Extract the common docs base URL to avoid drift/typos. For example, in
apps/portal/src/app/nebula/api-reference:then in each// nebulaConstants.ts export const NEBULA_REF_BASE = "https://api.thirdweb.com/reference#tag/ai/ai";
EndpointMetadata.tsx:referenceUrl: `${NEBULA_REF_BASE}/update-session`,
- Nit: add explicit return types to all
EndpointMetadatafunctions:
-export function EndpointMetadata() {
+export function EndpointMetadata(): JSX.Element {
return (
<ApiEndpoint metadata={{ /* … */ }} />
);
}
- Affected files:
• apps/portal/src/app/nebula/api-reference/**/EndpointMetadata.tsx
(chat, clear-session, create-session, delete-session, execute, get-session, list-session, update-session)
<!-- fingerprinting:phantom:poseidon:chinchilla -->
<!-- This is an auto-generated comment by CodeRabbit -->

PR-Codex overview
This PR focuses on updating the API documentation and examples for various endpoints related to wallet management and AI chat functionalities, enhancing clarity and usability for developers.
Detailed summary
OpenApiEndpointcomponents for better documentation.Summary by CodeRabbit
New Features
Documentation
Style
Chores