Skip to content

Alchemy failover backend proxy#1651

Merged
prxt6529 merged 18 commits intomainfrom
alchemy-failover-backend-proxy
Dec 16, 2025
Merged

Alchemy failover backend proxy#1651
prxt6529 merged 18 commits intomainfrom
alchemy-failover-backend-proxy

Conversation

@prxt6529
Copy link
Copy Markdown
Collaborator

@prxt6529 prxt6529 commented Dec 15, 2025

Summary by CodeRabbit

  • New Features

    • More reliable owner-NFT lookup with backend failover and standardized owner-NFT results.
  • Bug Fixes

    • Improved failover, retry/abort handling, and error responses across NFT, collection, contract, and token-metadata endpoints.
    • Batched token-metadata requests to reduce failures and improve consistency.
    • Stronger API input validation and clearer error payloads.
  • Tests

    • Expanded tests for owner-NFT fetch paths, API routes, and related components; improved test environment guards and mocks.

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

Signed-off-by: prxt6529 <prxt@6529.io>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 15, 2025

Walkthrough

Adds a backend failover path for Alchemy requests, centralizes Alchemy response processing into new utility functions, introduces an exported fetchOwnerNfts helper and OwnerNft type, updates API routes to proxy/validate Alchemy calls (including batching for token metadata), and updates components/tests to the new shapes and helpers.

Changes

Cohort / File(s) Summary
Tests
__tests__/hooks/useAlchemyNftQueries.test.ts, __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx, __tests__/services/alchemy-api.test.ts, __tests__/services/6529api.test.ts, __tests__/components/header/HeaderSearchModalItem.test.tsx, __tests__/components/user/layout/UserPageTabs.test.tsx
Adds/updates tests for fetchOwnerNfts and failover behavior, adapts component tests to new OwnerNft shapes and mocks, tweaks jest setup and mocks (node env directive, alchemyEnv mock, helper mocks, useParams).
Hook & failover
hooks/useAlchemyNftQueries.ts
Adds fetchJsonWithFailover, isAbortError, getBackendAlchemyProxyUrl, TokenMetadataParams, uses failover for multiple fetches, and exports fetchOwnerNfts(chainId, contract, owner, signal): Promise<OwnerNft[]>.
API routes (Alchemy proxy & batching)
app/api/alchemy/collections/route.ts, app/api/alchemy/contract/route.ts, app/api/alchemy/owner-nfts/route.ts, app/api/alchemy/token-metadata/route.ts
Replaces service calls with direct Alchemy HTTP calls (including batch handling for token metadata), adds network/chain resolution, input validation, standardized error responses, and no-store headers.
Service layer — delegate processing
services/alchemy/collections.ts, services/alchemy/owner-nfts.ts, services/alchemy/tokens.ts
Delegates payload normalization to new processors, updates getNftsForContractAndOwner to return OwnerNft[], integrates abort/retry helpers, and removes inlined mapping/normalization.
Processing utilities & types
services/alchemy/utils.ts, services/alchemy/types.ts
Adds processSearchResponse, processContractMetadataResponse, processOwnerNftsResponse, processTokenMetadataResponse; introduces OwnerNft type and extends AlchemyTokenMetadataEntry with name/description.
Component updates & test environment guards
components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx, jest.setup.js
Replaces direct fetches with fetchOwnerNfts, changes tokensOwnedForBurnAddress typing to OwnerNft[], refactors token filtering to numeric checks, and guards window mocks behind environment checks.
6529 API tweak
services/6529api.ts
handleResponseError now returns early on 401 after removing auth cookie, preventing a thrown error for that status.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Component as ClientComponent
  participant Hook as fetchOwnerNfts
  participant Alchemy as AlchemyAPI
  participant Backend as BackendProxy
  Note over Component,Hook: fetchOwnerNfts(chainId, contract, owner, signal)
  Component->>Hook: call with signal
  Hook->>Alchemy: HTTP GET primary (owner NFTs)
  alt primary OK (200)
    Alchemy-->>Hook: 200 + payload
    Hook->>Hook: processOwnerNftsResponse
    Hook-->>Component: OwnerNft[] (processed)
  else primary non-OK or network error
    Alchemy-->>Hook: non-OK / network error
    Hook->>Backend: POST failover proxy (params, signal)
    alt backend OK (200)
      Backend-->>Hook: 200 + payload
      Hook->>Hook: processOwnerNftsResponse
      Hook-->>Component: OwnerNft[] (processed)
    else backend error
      Backend-->>Hook: error
      Hook-->>Component: throw / reject with error
    end
  end
  Note right of Hook: abort signal => early AbortError / no backend fallback when aborted
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas needing focused review:
    • Failover control flow, error/status mapping, and abort handling in hooks/useAlchemyNftQueries.ts.
    • Input validation, network resolution, and status handling in API routes (collections, contract, owner-nfts, token-metadata).
    • Normalization logic and type consistency in services/alchemy/utils.ts and use of OwnerNft.
    • Abort/retry semantics in getNftsForContractAndOwner.
    • Alignment of tests and mocks with new shapes and behaviors.

Suggested reviewers

  • ragnep
  • simo6529
  • kmk142789

Poem

🐰 I hopped through lines both old and new,
I stitched a fallback, tidy and true,
Tokens shaped, requests retried,
Signals listened, tests supplied,
A happy rabbit, code review view.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
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.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically identifies the main change: introducing a failover mechanism that routes failed Alchemy API requests through a backend proxy.
✨ 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 alchemy-failover-backend-proxy

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown

@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

Caution

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

⚠️ Outside diff range comments (2)
components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx (1)

111-137: Missing dependency in useEffect may cause stale closure issues.

The filterTokensOwnedForBurnAddress function references props.collection_merkle properties, but props.collection_merkle is not included in the dependency array. If props.collection_merkle changes while mintForAddress remains the same, the filtering logic will use stale values.

Consider adding props.collection_merkle to the dependency array or memoizing the filter function:

   return () => controller.abort();
-  }, [account.address, mintForAddress]);
+  }, [account.address, mintForAddress, props.collection_merkle]);
hooks/useAlchemyNftQueries.ts (1)

340-350: Duplicate entries in queryKey array.

QueryKey.NFT_TOKEN_METADATA, chain, and address?.toLowerCase() appear twice, likely from a copy-paste error. This creates unnecessarily long cache keys.

     queryKey: [
       QueryKey.NFT_TOKEN_METADATA,
       chain,
       address?.toLowerCase(),
-      QueryKey.NFT_TOKEN_METADATA,
-      chain,
-      address?.toLowerCase(),
       uniqueIds,
       tokens,
     ],
🧹 Nitpick comments (2)
__tests__/hooks/useAlchemyNftQueries.test.ts (2)

3-15: Remove duplicate mock configuration.

mockPublicEnv at lines 3-7 duplicates the values in jest.mock at lines 9-15. Either use the variable in the mock or remove the unused constant.

-const mockPublicEnv = {
-  API_ENDPOINT: "https://api.example.com",
-  BASE_ENDPOINT: "https://example.com",
-  ALLOWLIST_API_ENDPOINT: "https://allowlist.example.com",
-};
-
 jest.mock("@/config/env", () => ({
   publicEnv: {
     API_ENDPOINT: "https://api.example.com",
     BASE_ENDPOINT: "https://example.com",
     ALLOWLIST_API_ENDPOINT: "https://allowlist.example.com",
   },
 }));
+
+const mockPublicEnv = {
+  API_ENDPOINT: "https://api.example.com",
+};

Or reference the mock directly in assertions.


147-166: Test description is misleading - error body is never read.

The fetchJson function throws on !response.ok before calling response.json(). The mock's json() returning { error: "ALCHEMY_API_KEY..." } is never executed. This test effectively duplicates the "non-ok response" test at lines 55-81.

Consider either:

  1. Rename to clarify it's just another non-ok response case
  2. Remove as duplicate coverage
  3. If testing specific error parsing is needed, modify fetchJson to read and include error details
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b4c0be4 and a2deb9c.

📒 Files selected for processing (3)
  • __tests__/hooks/useAlchemyNftQueries.test.ts (1 hunks)
  • components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx (2 hunks)
  • hooks/useAlchemyNftQueries.ts (7 hunks)
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx,js,jsx}: Do not include any comments in the code; it should be self-explanatory
Write correct, up-to-date, bug-free, fully componentized, secure, and efficient code
Include all required imports and ensure proper naming of key components
Use NextJS features that match the current version

**/*.{ts,tsx,js,jsx}: Replace <img> elements with <Image /> from next/image to satisfy @next/next/no-img-element ESLint rule
Use <Link href="/path"> from Next.js for internal navigation instead of plain HTML links to satisfy @next/next/no-html-link-for-pages ESLint rule

Files:

  • components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx
  • hooks/useAlchemyNftQueries.ts
  • __tests__/hooks/useAlchemyNftQueries.test.ts
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{tsx,jsx}: Use FontAwesome for icons in React components
Use TailwindCSS for styling in React components
Use react-query for data fetching
Always add readonly before props in React components

Files:

  • components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks)
Use framework APIs: internal links should use <Link>, images should use next/image, and adopt Next's ESLint rules (Core Web Vitals)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks rules)
Follow existing code style and naming conventions; maintain clean code standards (measured by SonarQube)

Files:

  • components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx
  • hooks/useAlchemyNftQueries.ts
  • __tests__/hooks/useAlchemyNftQueries.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Must pass tsc --noEmit type checking
Prefer direct named imports for React hooks and types (import { useMemo, useRef, FC, etc. } from "react") over React. namespace usage (React.useMemo, React.useRef, etc.)
If the react-hooks/exhaustive-deps lint rule is triggered: if the Effect only derives state, remove the Effect and compute during render; if listening to an external system and needing fresh props/state, wrap non-reactive logic in useEffectEvent

**/*.{ts,tsx}: Must pass tsc --noEmit for TypeScript type checking
Prefer Server Components over Client Components; use Server Functions/Server Actions ('use server') for mutations
Remove unnecessary Effects; if Effect only derives state, compute during render instead
Use useEffectEvent for non-reactive logic inside Effects to avoid unnecessary re-runs
Use framework APIs: <Link> for internal links, next/image for images, adopt Next's ESLint rules
Use 'use cache' directive and Cache Components features for explicit opt-in caching in Next.js 16
Use TypeScript and React functional components with hooks
When parsing Seize URLs or similar, fail fast if base origin is unavailable; do not fall back to placeholder origins
Replace <img> elements with <Image /> from next/image
Use <Link href="/path"> for internal navigation instead of plain HTML links
Move data fetches to Server Components; handle mutations through Server Functions/Server Actions with 'use server' directive

Files:

  • components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx
  • hooks/useAlchemyNftQueries.ts
  • __tests__/hooks/useAlchemyNftQueries.test.ts
**/@(__tests__|*.test).{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Tests should live in __tests__/ or ComponentName.test.tsx; mock external dependencies and APIs in tests

Files:

  • __tests__/hooks/useAlchemyNftQueries.test.ts
**/__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Place tests in __tests__/ directory or as ComponentName.test.tsx alongside components

Files:

  • __tests__/hooks/useAlchemyNftQueries.test.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Mock external dependencies and APIs in tests

Files:

  • __tests__/hooks/useAlchemyNftQueries.test.ts
__tests__/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (tests/AGENTS.md)

Use Jest + ts-jest for TypeScript testing

Files:

  • __tests__/hooks/useAlchemyNftQueries.test.ts
__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (tests/AGENTS.md)

Functions must have ≤ 15 cognitive complexity; extract deep ternaries (>3 levels) and break down complex logic

Files:

  • __tests__/hooks/useAlchemyNftQueries.test.ts
__tests__/**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (tests/AGENTS.md)

__tests__/**/*.{ts,tsx,js}: Prefer for...of loops over forEach as it allows break/continue and works with async/await
Use array.at(-1) and array.at(-2) instead of index-based array access for negative indexing
Use String.prototype.replaceAll() instead of replace() for global string replacements
Use globalThis.fetch() instead of direct fetch() calls
Organize imports with one import per module in order: external → internal → types, with no duplicates
Use element.remove() instead of parent.removeChild(element) for DOM manipulation
Catch errors only when meaningful; no empty catch blocks; log errors with context
Avoid double negatives in code; prefer explicit logic and remove redundant annotations; use optional chaining (?.)

Files:

  • __tests__/hooks/useAlchemyNftQueries.test.ts
__tests__/**/{components,contexts,hooks}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (tests/AGENTS.md)

Use semantic HTML elements (<label>, <output>) over ARIA attributes when possible; every form control must have a label

Files:

  • __tests__/hooks/useAlchemyNftQueries.test.ts
🧠 Learnings (7)
📚 Learning: 2025-11-25T08:35:58.729Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T08:35:58.729Z
Learning: Applies to **/*.{tsx,jsx} : Use react-query for data fetching

Applied to files:

  • hooks/useAlchemyNftQueries.ts
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/__tests__/**/*.test.{ts,tsx,js} : Test high-risk areas including happy path workflows, invalid input errors, edge cases/boundaries, component & API interactions, and performance/security when relevant

Applied to files:

  • __tests__/hooks/useAlchemyNftQueries.test.ts
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/*.{ts,tsx,js} : Use `globalThis.fetch()` instead of direct `fetch()` calls

Applied to files:

  • __tests__/hooks/useAlchemyNftQueries.test.ts
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/*.{ts,tsx,js} : Avoid double negatives in code; prefer explicit logic and remove redundant annotations; use optional chaining (`?.`)

Applied to files:

  • __tests__/hooks/useAlchemyNftQueries.test.ts
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/__tests__/**/*.test.{ts,tsx,js} : Keep tests independent, deterministic, and fast with production-like data

Applied to files:

  • __tests__/hooks/useAlchemyNftQueries.test.ts
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/__tests__/**/*.test.{ts,tsx,js} : Write tests following Arrange – Act – Assert pattern with one behaviour per test and clear, descriptive names

Applied to files:

  • __tests__/hooks/useAlchemyNftQueries.test.ts
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.test.{ts,tsx} : Mock external dependencies and APIs in tests

Applied to files:

  • __tests__/hooks/useAlchemyNftQueries.test.ts
🧬 Code graph analysis (2)
components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx (2)
hooks/useAlchemyNftQueries.ts (1)
  • fetchOwnerNfts (391-415)
components/nextGen/nextgen_contracts.ts (2)
  • NEXTGEN_CHAIN_ID (29-29)
  • NEXTGEN_CORE (54-59)
__tests__/hooks/useAlchemyNftQueries.test.ts (1)
hooks/useAlchemyNftQueries.ts (1)
  • fetchOwnerNfts (391-415)
⏰ 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). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (4)
components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx (1)

118-134: Clean integration with the new failover utility.

The refactor properly uses fetchOwnerNfts with correct parameters and maintains proper abort handling. The error handling correctly checks controller.signal.aborted before updating state on failure.

__tests__/hooks/useAlchemyNftQueries.test.ts (1)

28-143: Solid test coverage for the failover mechanism.

Tests cover the critical paths: primary success, failover on error/network issues, dual failure, abort signal propagation, and varying chain IDs. The tests follow Arrange-Act-Assert pattern and are independent.

hooks/useAlchemyNftQueries.ts (2)

391-415: Clean implementation of the failover-enabled NFT fetch.

The function properly constructs query parameters and delegates to fetchJsonWithFailover. The return type accurately reflects the API response structure.


106-130: POST request properly adapted for failover.

The token metadata fetch correctly uses the failover mechanism while preserving POST semantics and the existing BigInt conversion for token IDs.

Comment thread hooks/useAlchemyNftQueries.ts
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
Copy link
Copy Markdown

@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 (2)
hooks/useAlchemyNftQueries.ts (2)

66-80: LGTM: Failover logic correctly prevents retry on abort.

The function now properly detects and re-throws AbortError, ensuring intentional cancellations don't trigger the backend fallback.

Consider adding observability for the failover path to aid production debugging:

 async function fetchJsonWithFailover<T>(
   primaryUrl: string,
   backendPath: string,
   init?: RequestInit
 ): Promise<T> {
   try {
     return await fetchJson<T>(primaryUrl, init);
   } catch (error) {
     if (isAbortError(error)) {
       throw error;
     }
+    console.warn(
+      `Primary endpoint failed (${primaryUrl}), falling back to backend proxy`,
+      error
+    );
     const backendUrl = getBackendAlchemyProxyUrl(backendPath);
     return fetchJson<T>(backendUrl, init);
   }
 }

401-425: LGTM: New public API follows established patterns.

The function correctly implements the failover mechanism and properly propagates the abort signal.

Consider tightening the image property type if its structure is known:

 export async function fetchOwnerNfts(
   chainId: number,
   contract: string,
   owner: string,
   signal?: AbortSignal
 ): Promise<
   {
     tokenId: string;
     tokenType: string;
     name: string | null;
     tokenUri: string | null;
-    image: unknown;
+    image: { url?: string } | string | null;
   }[]
 > {

Adjust the type based on the actual API response structure.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a2deb9c and 82531d1.

📒 Files selected for processing (2)
  • __tests__/hooks/useAlchemyNftQueries.test.ts (1 hunks)
  • hooks/useAlchemyNftQueries.ts (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/hooks/useAlchemyNftQueries.test.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx,js,jsx}: Do not include any comments in the code; it should be self-explanatory
Write correct, up-to-date, bug-free, fully componentized, secure, and efficient code
Include all required imports and ensure proper naming of key components
Use NextJS features that match the current version

**/*.{ts,tsx,js,jsx}: Replace <img> elements with <Image /> from next/image to satisfy @next/next/no-img-element ESLint rule
Use <Link href="/path"> from Next.js for internal navigation instead of plain HTML links to satisfy @next/next/no-html-link-for-pages ESLint rule

Files:

  • hooks/useAlchemyNftQueries.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks)
Use framework APIs: internal links should use <Link>, images should use next/image, and adopt Next's ESLint rules (Core Web Vitals)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks rules)
Follow existing code style and naming conventions; maintain clean code standards (measured by SonarQube)

Files:

  • hooks/useAlchemyNftQueries.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Must pass tsc --noEmit type checking
Prefer direct named imports for React hooks and types (import { useMemo, useRef, FC, etc. } from "react") over React. namespace usage (React.useMemo, React.useRef, etc.)
If the react-hooks/exhaustive-deps lint rule is triggered: if the Effect only derives state, remove the Effect and compute during render; if listening to an external system and needing fresh props/state, wrap non-reactive logic in useEffectEvent

**/*.{ts,tsx}: Must pass tsc --noEmit for TypeScript type checking
Prefer Server Components over Client Components; use Server Functions/Server Actions ('use server') for mutations
Remove unnecessary Effects; if Effect only derives state, compute during render instead
Use useEffectEvent for non-reactive logic inside Effects to avoid unnecessary re-runs
Use framework APIs: <Link> for internal links, next/image for images, adopt Next's ESLint rules
Use 'use cache' directive and Cache Components features for explicit opt-in caching in Next.js 16
Use TypeScript and React functional components with hooks
When parsing Seize URLs or similar, fail fast if base origin is unavailable; do not fall back to placeholder origins
Replace <img> elements with <Image /> from next/image
Use <Link href="/path"> for internal navigation instead of plain HTML links
Move data fetches to Server Components; handle mutations through Server Functions/Server Actions with 'use server' directive

Files:

  • hooks/useAlchemyNftQueries.ts
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/*.{ts,tsx,js} : Use `globalThis.fetch()` instead of direct `fetch()` calls
📚 Learning: 2025-11-25T08:37:44.688Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: app/api/AGENTS.md:0-0
Timestamp: 2025-11-25T08:37:44.688Z
Learning: Applies to app/api/**/*.{ts,tsx,js,jsx} : Catch `UrlGuardError` explicitly if returning a tailored response; otherwise let it bubble so the caller can surface the correct status code.

Applied to files:

  • hooks/useAlchemyNftQueries.ts
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.{ts,tsx} : When parsing Seize URLs or similar, fail fast if base origin is unavailable; do not fall back to placeholder origins

Applied to files:

  • hooks/useAlchemyNftQueries.ts
📚 Learning: 2025-11-25T08:37:44.688Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: app/api/AGENTS.md:0-0
Timestamp: 2025-11-25T08:37:44.688Z
Learning: Applies to app/api/**/*.{ts,tsx,js,jsx} : Never call `fetch` directly with user-controlled or scraped URLs. Use helpers from `@/lib/security/urlGuard` (`parsePublicUrl`, `assertPublicUrl`, `fetchPublicUrl`, `fetchPublicJson`) to validate URLs against host/IP allowlists and DNS checks before making network requests.

Applied to files:

  • hooks/useAlchemyNftQueries.ts
📚 Learning: 2025-11-25T08:35:58.729Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T08:35:58.729Z
Learning: Applies to **/*.{tsx,jsx} : Use react-query for data fetching

Applied to files:

  • hooks/useAlchemyNftQueries.ts
⏰ 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). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (4)
hooks/useAlchemyNftQueries.ts (4)

41-43: LGTM: Clean backend URL construction.

The helper correctly constructs the failover proxy URL using the configured API endpoint.


45-54: LGTM: Solid fetch wrapper with error handling.

The function properly checks response status and provides type-safe JSON parsing.


56-64: LGTM: Comprehensive abort detection.

Correctly handles AbortError across different browser implementations (both DOMException and Error instances).


90-95: LGTM: Consistent failover integration.

All fetch functions have been properly updated to use the failover mechanism while preserving signal propagation for abort support.

Also applies to: 108-113, 119-139

Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
Copy link
Copy Markdown

@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

Caution

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

⚠️ Outside diff range comments (2)
components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx (1)

107-133: Missing dependency filterTokensOwnedForBurnAddress in useEffect.

The filterTokensOwnedForBurnAddress function is called inside the effect but captures props.collection_merkle from the outer scope. If collection_merkle changes without mintForAddress changing, stale filter logic would be used. Consider moving the filter logic inline or adding the relevant props to dependencies.

   useEffect(() => {
     const burnAddress = mintForAddress;
     if (!burnAddress) {
       return;
     }
     const controller = new AbortController();

     fetchOwnerNfts(
       NEXTGEN_CHAIN_ID,
       NEXTGEN_CORE[NEXTGEN_CHAIN_ID],
       burnAddress,
       controller.signal
     )
       .then((r) => {
         setTokensOwnedForBurnAddressLoaded(true);
-        const filteredTokens = filterTokensOwnedForBurnAddress(r);
+        const filteredTokens = filterTokensOwnedForBurnAddress(r, props.collection_merkle);
         setTokensOwnedForBurnAddress(filteredTokens);
       })
       .catch(() => {
         if (!controller.signal.aborted) {
           setTokensOwnedForBurnAddressLoaded(true);
           setTokensOwnedForBurnAddress([]);
         }
       });

     return () => controller.abort();
-  }, [account.address, mintForAddress]);
+  }, [account.address, mintForAddress, props.collection_merkle]);

This requires refactoring filterTokensOwnedForBurnAddress to accept collection_merkle as a parameter.

hooks/useAlchemyNftQueries.ts (1)

383-393: Duplicate entries in query key array.

The query key contains duplicate entries (QueryKey.NFT_TOKEN_METADATA, chain, address?.toLowerCase() appear twice). This appears to be unintentional and could cause cache key issues.

     queryKey: [
       QueryKey.NFT_TOKEN_METADATA,
       chain,
       address?.toLowerCase(),
-      QueryKey.NFT_TOKEN_METADATA,
-      chain,
-      address?.toLowerCase(),
       uniqueIds,
       tokens,
     ],
♻️ Duplicate comments (1)
app/api/alchemy/collections/route.ts (1)

8-14: Same network resolution duplication as noted in contract/route.ts.

This reinforces the suggestion to extract the shared NETWORK_MAP and resolveNetwork logic to a common utility module.

🧹 Nitpick comments (9)
helpers/alchemy/response-processing.ts (2)

369-379: Consider returning title in addition to name for consistency.

The AlchemyTokenMetadataEntry type includes both title and name fields, and normaliseTokenMetadata (line 403-408) uses title as the primary source. However, processOwnerNftsResponse only maps name. If Alchemy returns title without name for owned NFTs, the name would incorrectly be null.

 export function processOwnerNftsResponse(
   ownedNfts: AlchemyOwnedNft[]
 ): OwnerNft[] {
   return ownedNfts.map((nft) => ({
     tokenId: nft.tokenId ?? "",
     tokenType: nft.tokenType ?? null,
-    name: nft.name ?? null,
+    name: nft.title ?? nft.name ?? null,
     tokenUri: nft.tokenUri ?? null,
     image: nft.image ?? null,
   }));
 }

381-387: Empty string passed to BigInt throws; error is caught but consider explicit validation.

parseTokenIdToBigint throws when tokenId is empty (line 382-384), but an empty string after trim() would still reach BigInt("") which throws a SyntaxError. The current flow works because the caller catches exceptions, but the error message "Token ID missing" would be misleading for whitespace-only input.

 function parseTokenIdToBigint(tokenId: string): bigint {
-  if (!tokenId) {
+  const trimmed = tokenId.trim();
+  if (!trimmed) {
     throw new Error("Token ID missing");
   }
-  const trimmed = tokenId.trim();
   return BigInt(trimmed);
 }
app/api/alchemy/owner-nfts/route.ts (2)

43-46: Consider adding a timeout to the Alchemy fetch request.

The fetch relies only on the incoming request's abort signal. If the client disconnects slowly or the Alchemy API hangs, this could tie up resources. Consider wrapping with AbortSignal.timeout() combined with the request signal.


7-11: Remove Goerli network support (chainId 5) — no longer active.

Goerli entered End-of-Life in April 2024 and is no longer maintained or supported as of 2025. Users are advised to migrate their tests to the Ephemery, Holesky, or Sepolia networks. For DApp testing, Sepolia is recommended for DApp testing.

components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx (1)

35-45: Add readonly before Props interface properties.

Per coding guidelines, always add readonly before props in React components.

-interface Props {
-  collection: NextGenCollection;
-  collection_merkle: CollectionWithMerkle;
-  available_supply: number;
-  mint_price: number;
-  mint_counts: TokensPerAddress;
-  delegators: string[];
-  mintForAddress: (mintForAddress: string) => void;
-  fetchingMintCounts: boolean;
-  refreshMintCounts: () => void;
-}
+interface Props {
+  readonly collection: NextGenCollection;
+  readonly collection_merkle: CollectionWithMerkle;
+  readonly available_supply: number;
+  readonly mint_price: number;
+  readonly mint_counts: TokensPerAddress;
+  readonly delegators: string[];
+  readonly mintForAddress: (mintForAddress: string) => void;
+  readonly fetchingMintCounts: boolean;
+  readonly refreshMintCounts: () => void;
+}
app/api/alchemy/contract/route.ts (1)

10-16: Consider extracting shared network resolution to a common module.

The NETWORK_MAP and resolveNetwork pattern is duplicated across contract/route.ts, collections/route.ts, and owner-nfts/route.ts (with slight variations). Extracting to a shared utility would reduce duplication and ensure consistency.

hooks/useAlchemyNftQueries.ts (1)

136-147: Type assertion on _checksum may mask upstream issues.

If the API response doesn't include _checksum, the code falls back to the locally computed checksum, which is fine. However, casting payload._checksum directly to `0x${string}` without validation could be problematic if the API returns a malformed value.

Consider using normaliseAddress on the response checksum for consistency:

-  const checksumFromResponse = (payload._checksum ?? checksum) as `0x${string}`;
+  const checksumFromResponse = normaliseAddress(payload._checksum) ?? checksum;
app/api/alchemy/token-metadata/route.ts (2)

76-99: Batch failure discards all results including successful batches.

If a later batch fails, all previously fetched tokens from successful batches are discarded. Consider whether partial results should be returned or if all-or-nothing semantics are intentional.

If partial results are acceptable, accumulate errors and return what was fetched:

     const allTokens: unknown[] = [];
+    let lastError: Response | null = null;

     for (let i = 0; i < tokensToFetch.length; i += MAX_BATCH_SIZE) {
       const slice = tokensToFetch.slice(i, i + MAX_BATCH_SIZE);

       const response = await fetch(url, {
         method: "POST",
         headers: {
           "Content-Type": "application/json",
           Accept: "application/json",
         },
         body: JSON.stringify({ tokens: slice }),
         signal: request.signal,
       });

       if (!response.ok) {
-        return NextResponse.json(
-          { error: "Failed to fetch token metadata" },
-          { status: response.status, headers: NO_STORE_HEADERS }
-        );
+        lastError = response;
+        continue;
       }

       const payload = await response.json();
       const tokens = payload.tokens ?? payload.nfts ?? [];
       allTokens.push(...tokens);
     }

-    return NextResponse.json({ tokens: allTokens }, { headers: NO_STORE_HEADERS });
+    if (allTokens.length === 0 && lastError) {
+      return NextResponse.json(
+        { error: "Failed to fetch token metadata" },
+        { status: lastError.status, headers: NO_STORE_HEADERS }
+      );
+    }
+    return NextResponse.json({ tokens: allTokens }, { headers: NO_STORE_HEADERS });

Alternatively, if all-or-nothing is intended, the current behavior is acceptable but should be documented.


102-109: Catch block returns 400 for all errors including network failures.

Network errors or timeouts would return a 400 status, which is typically reserved for client errors. Consider using 502 (Bad Gateway) or 500 for upstream failures.

   } catch (error) {
     const message =
       error instanceof Error ? error.message : "Failed to fetch token metadata";
     return NextResponse.json(
       { error: message },
-      { status: 400, headers: NO_STORE_HEADERS }
+      { status: 502, headers: NO_STORE_HEADERS }
     );
   }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e267d46 and f638c2b.

📒 Files selected for processing (8)
  • __tests__/hooks/useAlchemyNftQueries.test.ts (1 hunks)
  • app/api/alchemy/collections/route.ts (2 hunks)
  • app/api/alchemy/contract/route.ts (1 hunks)
  • app/api/alchemy/owner-nfts/route.ts (2 hunks)
  • app/api/alchemy/token-metadata/route.ts (2 hunks)
  • components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx (5 hunks)
  • helpers/alchemy/response-processing.ts (1 hunks)
  • hooks/useAlchemyNftQueries.ts (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/hooks/useAlchemyNftQueries.test.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx,js,jsx}: Do not include any comments in the code; it should be self-explanatory
Write correct, up-to-date, bug-free, fully componentized, secure, and efficient code
Include all required imports and ensure proper naming of key components
Use NextJS features that match the current version

**/*.{ts,tsx,js,jsx}: Replace <img> elements with <Image /> from next/image to satisfy @next/next/no-img-element ESLint rule
Use <Link href="/path"> from Next.js for internal navigation instead of plain HTML links to satisfy @next/next/no-html-link-for-pages ESLint rule

Files:

  • app/api/alchemy/owner-nfts/route.ts
  • components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx
  • app/api/alchemy/collections/route.ts
  • hooks/useAlchemyNftQueries.ts
  • app/api/alchemy/token-metadata/route.ts
  • helpers/alchemy/response-processing.ts
  • app/api/alchemy/contract/route.ts
app/api/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (app/api/AGENTS.md)

app/api/**/*.{ts,tsx,js,jsx}: Never call fetch directly with user-controlled or scraped URLs. Use helpers from @/lib/security/urlGuard (parsePublicUrl, assertPublicUrl, fetchPublicUrl, fetchPublicJson) to validate URLs against host/IP allowlists and DNS checks before making network requests.
When needing custom headers or timeouts for external requests, pass them via @/lib/security/urlGuard helper options rather than re-implementing your own wrapper.
Catch UrlGuardError explicitly if returning a tailored response; otherwise let it bubble so the caller can surface the correct status code.
Follow the project default responses (NextResponse.json) and reuse existing util modules instead of duplicating logic.

Files:

  • app/api/alchemy/owner-nfts/route.ts
  • app/api/alchemy/collections/route.ts
  • app/api/alchemy/token-metadata/route.ts
  • app/api/alchemy/contract/route.ts
app/api/**/route.ts

📄 CodeRabbit inference engine (app/api/AGENTS.md)

app/api/**/route.ts: Export HTTP verb handlers (e.g. GET, POST, etc.) from route.ts files, keeping logic in small internal functions when it grows beyond ~200 lines.
For edge caching behavior, prefer export const dynamic = "force-dynamic"; or revalidate constants rather than inline headers.

Files:

  • app/api/alchemy/owner-nfts/route.ts
  • app/api/alchemy/collections/route.ts
  • app/api/alchemy/token-metadata/route.ts
  • app/api/alchemy/contract/route.ts
app/api/**/*.{ts,tsx}

📄 CodeRabbit inference engine (app/api/AGENTS.md)

Use TypeScript types for request parameters and responses; avoid any unless a 3rd-party payload truly has no shape guarantees.

Files:

  • app/api/alchemy/owner-nfts/route.ts
  • app/api/alchemy/collections/route.ts
  • app/api/alchemy/token-metadata/route.ts
  • app/api/alchemy/contract/route.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks)
Use framework APIs: internal links should use <Link>, images should use next/image, and adopt Next's ESLint rules (Core Web Vitals)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks rules)
Follow existing code style and naming conventions; maintain clean code standards (measured by SonarQube)

Files:

  • app/api/alchemy/owner-nfts/route.ts
  • components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx
  • app/api/alchemy/collections/route.ts
  • hooks/useAlchemyNftQueries.ts
  • app/api/alchemy/token-metadata/route.ts
  • helpers/alchemy/response-processing.ts
  • app/api/alchemy/contract/route.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Must pass tsc --noEmit type checking
Prefer direct named imports for React hooks and types (import { useMemo, useRef, FC, etc. } from "react") over React. namespace usage (React.useMemo, React.useRef, etc.)
If the react-hooks/exhaustive-deps lint rule is triggered: if the Effect only derives state, remove the Effect and compute during render; if listening to an external system and needing fresh props/state, wrap non-reactive logic in useEffectEvent

**/*.{ts,tsx}: Must pass tsc --noEmit for TypeScript type checking
Prefer Server Components over Client Components; use Server Functions/Server Actions ('use server') for mutations
Remove unnecessary Effects; if Effect only derives state, compute during render instead
Use useEffectEvent for non-reactive logic inside Effects to avoid unnecessary re-runs
Use framework APIs: <Link> for internal links, next/image for images, adopt Next's ESLint rules
Use 'use cache' directive and Cache Components features for explicit opt-in caching in Next.js 16
Use TypeScript and React functional components with hooks
When parsing Seize URLs or similar, fail fast if base origin is unavailable; do not fall back to placeholder origins
Replace <img> elements with <Image /> from next/image
Use <Link href="/path"> for internal navigation instead of plain HTML links
Move data fetches to Server Components; handle mutations through Server Functions/Server Actions with 'use server' directive

Files:

  • app/api/alchemy/owner-nfts/route.ts
  • components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx
  • app/api/alchemy/collections/route.ts
  • hooks/useAlchemyNftQueries.ts
  • app/api/alchemy/token-metadata/route.ts
  • helpers/alchemy/response-processing.ts
  • app/api/alchemy/contract/route.ts
app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Routes in app/ should export generateMetadata using the helper getAppMetadata with a title property

All production routes must live under the App Router (app/) directory

Files:

  • app/api/alchemy/owner-nfts/route.ts
  • app/api/alchemy/collections/route.ts
  • app/api/alchemy/token-metadata/route.ts
  • app/api/alchemy/contract/route.ts
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{tsx,jsx}: Use FontAwesome for icons in React components
Use TailwindCSS for styling in React components
Use react-query for data fetching
Always add readonly before props in React components

Files:

  • components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx
🧠 Learnings (6)
📚 Learning: 2025-11-25T08:37:44.688Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: app/api/AGENTS.md:0-0
Timestamp: 2025-11-25T08:37:44.688Z
Learning: Applies to app/api/**/*.{ts,tsx,js,jsx} : Never call `fetch` directly with user-controlled or scraped URLs. Use helpers from `@/lib/security/urlGuard` (`parsePublicUrl`, `assertPublicUrl`, `fetchPublicUrl`, `fetchPublicJson`) to validate URLs against host/IP allowlists and DNS checks before making network requests.

Applied to files:

  • app/api/alchemy/owner-nfts/route.ts
  • hooks/useAlchemyNftQueries.ts
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Fix with modernization (no `// eslint-disable` unless explicitly instructed); prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions

Applied to files:

  • components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx
  • hooks/useAlchemyNftQueries.ts
📚 Learning: 2025-11-25T08:37:44.688Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: app/api/AGENTS.md:0-0
Timestamp: 2025-11-25T08:37:44.688Z
Learning: Applies to app/api/**/*.{ts,tsx,js,jsx} : Catch `UrlGuardError` explicitly if returning a tailored response; otherwise let it bubble so the caller can surface the correct status code.

Applied to files:

  • hooks/useAlchemyNftQueries.ts
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.{ts,tsx} : When parsing Seize URLs or similar, fail fast if base origin is unavailable; do not fall back to placeholder origins

Applied to files:

  • hooks/useAlchemyNftQueries.ts
📚 Learning: 2025-11-25T08:35:58.729Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T08:35:58.729Z
Learning: Applies to **/*.{tsx,jsx} : Use react-query for data fetching

Applied to files:

  • hooks/useAlchemyNftQueries.ts
📚 Learning: 2025-11-25T08:37:44.688Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: app/api/AGENTS.md:0-0
Timestamp: 2025-11-25T08:37:44.688Z
Learning: Applies to app/api/**/*.{ts,tsx,js,jsx} : Follow the project default responses (`NextResponse.json`) and reuse existing util modules instead of duplicating logic.

Applied to files:

  • helpers/alchemy/response-processing.ts
🧬 Code graph analysis (4)
components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx (3)
helpers/alchemy/response-processing.ts (1)
  • OwnerNft (361-367)
hooks/useAlchemyNftQueries.ts (2)
  • OwnerNft (33-33)
  • fetchOwnerNfts (434-453)
components/nextGen/nextgen_contracts.ts (2)
  • NEXTGEN_CHAIN_ID (29-29)
  • NEXTGEN_CORE (54-59)
hooks/useAlchemyNftQueries.ts (1)
helpers/alchemy/response-processing.ts (11)
  • OwnerNft (361-367)
  • SearchContractsResult (300-304)
  • AlchemySearchResponse (50-53)
  • processSearchResponse (306-325)
  • normaliseAddress (127-141)
  • AlchemyContractMetadataResponse (55-62)
  • processContractMetadataResponse (327-359)
  • AlchemyTokenMetadataResponse (104-107)
  • processTokenMetadataResponse (422-434)
  • AlchemyGetNftsForOwnerResponse (113-118)
  • processOwnerNftsResponse (369-379)
app/api/alchemy/token-metadata/route.ts (2)
helpers/Helpers.ts (1)
  • isValidEthAddress (234-235)
helpers/alchemy/response-processing.ts (1)
  • normaliseAddress (127-141)
app/api/alchemy/contract/route.ts (3)
app/api/alchemy/collections/route.ts (1)
  • GET (16-64)
helpers/Helpers.ts (1)
  • isValidEthAddress (234-235)
helpers/alchemy/response-processing.ts (1)
  • normaliseAddress (127-141)
⏰ 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). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (16)
helpers/alchemy/response-processing.ts (4)

10-126: LGTM! Well-structured type definitions for Alchemy API responses.

The types cover multiple variations of OpenSea metadata field naming (openSeaMetadata, openseaMetadata, openSea, opensea) which handles Alchemy API inconsistencies effectively. The index signature on AlchemyNftMetadata (line 79) appropriately allows for unknown additional properties.


127-141: Verify the fallback behavior when getAddress throws.

The catch block on line 138-139 returns the address cast as 0x${string} even though getAddress from viem threw. Since isValidEthAddress already passed (line 133), this fallback is safe, but it may mask checksum-related issues. Consider logging when this fallback is used in non-production environments.


162-213: LGTM! Robust image/thumbnail resolution with sensible fallback chains.

The pickImage and pickThumbnail functions correctly handle multiple potential sources with appropriate null checks.


255-298: LGTM! Contract extraction handles metadata from multiple sources correctly.

The extractContract function properly consolidates metadata from various possible locations and normalizes addresses consistently.

components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx (2)

141-143: Missing dependency warning: props.mintForAddress not in deps.

This effect calls props.mintForAddress(mintForAddress) but only depends on mintForAddress. If props.mintForAddress callback identity changes, this effect won't re-run. Either add it to dependencies or verify the callback is stable (e.g., memoized in parent).


114-130: LGTM! Good migration to the typed fetchOwnerNfts helper.

The component now uses the centralized fetchOwnerNfts helper with proper abort signal handling and typed OwnerNft[] responses, improving consistency with the rest of the codebase.

app/api/alchemy/contract/route.ts (2)

36-43: LGTM! URL construction uses validated checksum address.

Unlike the owner-nfts route, this route uses the validated/checksummed address from normaliseAddress, which is safe for direct URL interpolation.


45-54: LGTM! Good handling of 404 as a valid "not found" case.

Returning null with 200 status for 404 responses is appropriate since a missing contract is a valid query result, not an error.

app/api/alchemy/collections/route.ts (2)

30-43: LGTM! Proper URL construction using URL class and searchParams.

This is the preferred pattern for URL construction - using the URL class with searchParams ensures proper encoding. The other route files should follow this pattern.


16-64: LGTM! Clean implementation with consistent error handling.

The route properly validates input, constructs URLs safely, and handles errors consistently with the other Alchemy routes.

hooks/useAlchemyNftQueries.ts (5)

48-60: LGTM on the helper functions.

The getBackendAlchemyProxyUrl correctly constructs the proxy URL using publicEnv.API_ENDPOINT. The isAbortError helper properly handles both DOMException and generic Error with AbortError name, covering browser variations.


73-90: Failover logic now correctly handles abort errors.

The implementation properly re-throws AbortError to prevent unintended fallback requests when a request is intentionally cancelled. This addresses the concern from the previous review.


100-116: Consider logging or observability for failover events.

The failover mechanism logs a warning on fallback, which is appropriate. The implementation correctly passes query parameters to both primary and proxy endpoints.


150-173: Token metadata fetch correctly uses failover with POST.

The implementation properly constructs the request body and passes it through fetchJsonWithFailover. The init object correctly propagates the signal for abort handling.


434-453: New fetchOwnerNfts export is well-structured.

The function correctly uses fetchJsonWithFailover with proper query string construction and signal propagation. The response processing via processOwnerNftsResponse handles the ownedNfts array with a fallback to empty array.

app/api/alchemy/token-metadata/route.ts (1)

11-17: No changes needed. SupportedChain is a string literal type with only "ethereum" as its single possible value, so NETWORK_MAP correctly supports all chains defined by the type. There is no silent fallback issue since the type system enforces that only "ethereum" can be passed.

Likely an incorrect or invalid review comment.

Comment thread app/api/alchemy/owner-nfts/route.ts
Comment thread app/api/alchemy/token-metadata/route.ts
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
Copy link
Copy Markdown

@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 (1)
helpers/alchemy/response-processing.ts (1)

172-175: Consider validating tokenType before type assertion.

The type assertion assumes tokenType will only be ERC721, ERC1155, or undefined, but if the API returns other values (e.g., "ERC20"), the assertion bypasses type safety without runtime validation.

Consider adding validation:

-  const tokenType = baseMeta.tokenType?.toUpperCase() as
-    | "ERC721"
-    | "ERC1155"
-    | undefined;
+  const tokenTypeRaw = baseMeta.tokenType?.toUpperCase();
+  const tokenType: "ERC721" | "ERC1155" | undefined =
+    tokenTypeRaw === "ERC721" || tokenTypeRaw === "ERC1155"
+      ? tokenTypeRaw
+      : undefined;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aecf876 and c095aa6.

📒 Files selected for processing (1)
  • helpers/alchemy/response-processing.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx,js,jsx}: Do not include any comments in the code; it should be self-explanatory
Write correct, up-to-date, bug-free, fully componentized, secure, and efficient code
Include all required imports and ensure proper naming of key components
Use NextJS features that match the current version

**/*.{ts,tsx,js,jsx}: Replace <img> elements with <Image /> from next/image to satisfy @next/next/no-img-element ESLint rule
Use <Link href="/path"> from Next.js for internal navigation instead of plain HTML links to satisfy @next/next/no-html-link-for-pages ESLint rule

Files:

  • helpers/alchemy/response-processing.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks)
Use framework APIs: internal links should use <Link>, images should use next/image, and adopt Next's ESLint rules (Core Web Vitals)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks rules)
Follow existing code style and naming conventions; maintain clean code standards (measured by SonarQube)

Files:

  • helpers/alchemy/response-processing.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Must pass tsc --noEmit type checking
Prefer direct named imports for React hooks and types (import { useMemo, useRef, FC, etc. } from "react") over React. namespace usage (React.useMemo, React.useRef, etc.)
If the react-hooks/exhaustive-deps lint rule is triggered: if the Effect only derives state, remove the Effect and compute during render; if listening to an external system and needing fresh props/state, wrap non-reactive logic in useEffectEvent

**/*.{ts,tsx}: Must pass tsc --noEmit for TypeScript type checking
Prefer Server Components over Client Components; use Server Functions/Server Actions ('use server') for mutations
Remove unnecessary Effects; if Effect only derives state, compute during render instead
Use useEffectEvent for non-reactive logic inside Effects to avoid unnecessary re-runs
Use framework APIs: <Link> for internal links, next/image for images, adopt Next's ESLint rules
Use 'use cache' directive and Cache Components features for explicit opt-in caching in Next.js 16
Use TypeScript and React functional components with hooks
When parsing Seize URLs or similar, fail fast if base origin is unavailable; do not fall back to placeholder origins
Replace <img> elements with <Image /> from next/image
Use <Link href="/path"> for internal navigation instead of plain HTML links
Move data fetches to Server Components; handle mutations through Server Functions/Server Actions with 'use server' directive

Files:

  • helpers/alchemy/response-processing.ts
🧠 Learnings (1)
📚 Learning: 2025-11-25T08:37:44.688Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: app/api/AGENTS.md:0-0
Timestamp: 2025-11-25T08:37:44.688Z
Learning: Applies to app/api/**/*.{ts,tsx,js,jsx} : Follow the project default responses (`NextResponse.json`) and reuse existing util modules instead of duplicating logic.

Applied to files:

  • helpers/alchemy/response-processing.ts
🧬 Code graph analysis (1)
helpers/alchemy/response-processing.ts (2)
helpers/Helpers.ts (1)
  • isValidEthAddress (234-235)
hooks/useAlchemyNftQueries.ts (1)
  • OwnerNft (33-33)
⏰ 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). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (7)
helpers/alchemy/response-processing.ts (7)

1-23: LGTM: Clean imports and type re-exports.

The import structure follows best practices, and re-exporting the Alchemy response types provides a clean API surface for consumers of this module.


51-121: LGTM: Robust metadata resolution helpers.

The functions handle API inconsistencies well by checking multiple field name variations and gracefully falling back through prioritized sources. The null-safety and optional chaining are properly implemented.


123-159: LGTM: Solid parsing and validation logic.

Both toSafelist and parseFloorPrice demonstrate good defensive programming with proper type checking and safe fallbacks for invalid or missing data.


212-231: LGTM: Clean search response processing.

The function properly filters contracts, handles spam filtering, and maintains accurate counts. The type narrowing with the filter predicate is well-implemented.


233-263: LGTM: Effective contract metadata processing.

The function appropriately aggregates metadata from multiple sources and reuses the extractContract helper for consistency. The null handling is correct.


265-283: LGTM: Straightforward owner NFT processing.

The OwnerNft type is well-defined, and the processing function correctly maps the Alchemy response with appropriate null handling.


285-338: LGTM: Robust token metadata processing.

The error handling pattern is well-designed: parseTokenIdToBigint throws on invalid input, normaliseTokenMetadata catches and returns null, and processTokenMetadataResponse filters out failures. This ensures malformed token data doesn't break the entire batch.

Comment thread helpers/alchemy/response-processing.ts Outdated
Comment thread helpers/alchemy/response-processing.ts Outdated
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
Copy link
Copy Markdown

@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

Caution

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

⚠️ Outside diff range comments (2)
app/api/alchemy/contract/route.ts (1)

61-68: Return 500 for unexpected server-side errors instead of 400.

Returning 400 (Bad Request) for all caught errors conflates client errors with server errors. If fetch fails due to network issues or Alchemy outages, a 500 status would be more accurate and help clients distinguish between their mistakes and upstream failures.

   } catch (error) {
     const message =
       error instanceof Error ? error.message : "Failed to fetch contract metadata";
     return NextResponse.json(
       { error: message },
-      { status: 400, headers: NO_STORE_HEADERS }
+      { status: 500, headers: NO_STORE_HEADERS }
     );
   }
hooks/useAlchemyNftQueries.ts (1)

383-393: Duplicate entries in queryKey array.

The queryKey array contains duplicate entries: QueryKey.NFT_TOKEN_METADATA, chain, and address?.toLowerCase() appear twice at the beginning of the array. This is likely a copy-paste error.

     queryKey: [
       QueryKey.NFT_TOKEN_METADATA,
       chain,
       address?.toLowerCase(),
-      QueryKey.NFT_TOKEN_METADATA,
-      chain,
-      address?.toLowerCase(),
       uniqueIds,
       tokens,
     ],
🧹 Nitpick comments (5)
app/api/alchemy/contract/route.ts (1)

10-16: Consider importing resolveNetwork from @/services/alchemy/utils.

This NETWORK_MAP and resolveNetwork function duplicate the implementation in services/alchemy/utils.ts (lines 21-23). Unless there's a specific reason to avoid the dependency (e.g., bundle size concerns for edge runtime), consider importing from the shared utility to maintain DRY.

-const NETWORK_MAP: Record<SupportedChain, string> = {
-  ethereum: "eth-mainnet",
-};
-
-function resolveNetwork(chain: SupportedChain = "ethereum"): string {
-  return NETWORK_MAP[chain] ?? NETWORK_MAP.ethereum;
-}
+import { resolveNetwork } from "@/services/alchemy/utils";
components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx (2)

108-134: Missing dependencies in useEffect may cause stale closures.

The filterTokensOwnedForBurnAddress function references props.collection_merkle properties, but the useEffect dependency array only includes [account.address, mintForAddress]. If collection_merkle changes, the filter will use stale values.

Consider either:

  1. Adding props.collection_merkle to the dependency array
  2. Moving the filter logic inline within the useEffect
  3. Using useCallback for filterTokensOwnedForBurnAddress with proper dependencies
   useEffect(() => {
     const burnAddress = mintForAddress;
     if (!burnAddress) {
       return;
     }
     const controller = new AbortController();

     fetchOwnerNfts(
       NEXTGEN_CHAIN_ID,
       NEXTGEN_CORE[NEXTGEN_CHAIN_ID],
       burnAddress,
       controller.signal
     )
       .then((r) => {
         setTokensOwnedForBurnAddressLoaded(true);
         const filteredTokens = filterTokensOwnedForBurnAddress(r);
         setTokensOwnedForBurnAddress(filteredTokens);
       })
       .catch(() => {
         if (!controller.signal.aborted) {
           setTokensOwnedForBurnAddressLoaded(true);
           setTokensOwnedForBurnAddress([]);
         }
       });

     return () => controller.abort();
-  }, [account.address, mintForAddress]);
+  }, [account.address, mintForAddress, props.collection_merkle]);

142-144: Missing dependencies in useEffect.

This useEffect calls props.mintForAddress but doesn't include it in the dependency array. While ESLint may flag this, the function reference from props typically shouldn't change, but it's best practice to include it.

   useEffect(() => {
     props.mintForAddress(mintForAddress);
-  }, [mintForAddress]);
+  }, [mintForAddress, props.mintForAddress]);
app/api/alchemy/token-metadata/route.ts (2)

61-63: Inconsistent error handling between input paths.

When normaliseAddress returns null for the address + tokenIds path, the code returns an empty tokens array (line 63). However, for the tokens array path (line 45), there's a fallback to the original address. This inconsistency could confuse callers.

Consider returning a 400 error here to match the validation pattern used for the tokens array path:

    const checksum = normaliseAddress(address);
    if (!checksum) {
-      return NextResponse.json({ tokens: [] }, { headers: NO_STORE_HEADERS });
+      return NextResponse.json(
+        { error: "Invalid contract address" },
+        { status: 400, headers: NO_STORE_HEADERS }
+      );
    }

105-105: Defensive fallback may hide API contract changes.

The fallback payload.tokens ?? payload.nfts ?? [] attempts to handle multiple response structures. While defensive, this could silently mask breaking changes in the Alchemy API response format.

Consider logging when the fallback is used or being more explicit about expected response structure:

-      const tokens = payload.tokens ?? payload.nfts ?? [];
+      const tokens = payload.tokens ?? [];
+      if (!payload.tokens && payload.nfts) {
+        console.warn("Unexpected response structure: using nfts field instead of tokens");
+      }
       allTokens.push(...tokens);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c095aa6 and a2783ad.

📒 Files selected for processing (12)
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx (7 hunks)
  • __tests__/services/alchemy-api.test.ts (1 hunks)
  • app/api/alchemy/contract/route.ts (1 hunks)
  • app/api/alchemy/token-metadata/route.ts (2 hunks)
  • components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx (5 hunks)
  • hooks/useAlchemyNftQueries.ts (6 hunks)
  • jest.setup.js (2 hunks)
  • services/alchemy/collections.ts (3 hunks)
  • services/alchemy/owner-nfts.ts (4 hunks)
  • services/alchemy/tokens.ts (2 hunks)
  • services/alchemy/types.ts (3 hunks)
  • services/alchemy/utils.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (15)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx,js,jsx}: Do not include any comments in the code; it should be self-explanatory
Write correct, up-to-date, bug-free, fully componentized, secure, and efficient code
Include all required imports and ensure proper naming of key components
Use NextJS features that match the current version

**/*.{ts,tsx,js,jsx}: Replace <img> elements with <Image /> from next/image to satisfy @next/next/no-img-element ESLint rule
Use <Link href="/path"> from Next.js for internal navigation instead of plain HTML links to satisfy @next/next/no-html-link-for-pages ESLint rule

Files:

  • jest.setup.js
  • app/api/alchemy/token-metadata/route.ts
  • services/alchemy/tokens.ts
  • services/alchemy/utils.ts
  • services/alchemy/owner-nfts.ts
  • services/alchemy/collections.ts
  • __tests__/services/alchemy-api.test.ts
  • hooks/useAlchemyNftQueries.ts
  • components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx
  • services/alchemy/types.ts
  • app/api/alchemy/contract/route.ts
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks)
Use framework APIs: internal links should use <Link>, images should use next/image, and adopt Next's ESLint rules (Core Web Vitals)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks rules)
Follow existing code style and naming conventions; maintain clean code standards (measured by SonarQube)

Files:

  • jest.setup.js
  • app/api/alchemy/token-metadata/route.ts
  • services/alchemy/tokens.ts
  • services/alchemy/utils.ts
  • services/alchemy/owner-nfts.ts
  • services/alchemy/collections.ts
  • __tests__/services/alchemy-api.test.ts
  • hooks/useAlchemyNftQueries.ts
  • components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx
  • services/alchemy/types.ts
  • app/api/alchemy/contract/route.ts
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
app/api/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (app/api/AGENTS.md)

app/api/**/*.{ts,tsx,js,jsx}: Never call fetch directly with user-controlled or scraped URLs. Use helpers from @/lib/security/urlGuard (parsePublicUrl, assertPublicUrl, fetchPublicUrl, fetchPublicJson) to validate URLs against host/IP allowlists and DNS checks before making network requests.
When needing custom headers or timeouts for external requests, pass them via @/lib/security/urlGuard helper options rather than re-implementing your own wrapper.
Catch UrlGuardError explicitly if returning a tailored response; otherwise let it bubble so the caller can surface the correct status code.
Follow the project default responses (NextResponse.json) and reuse existing util modules instead of duplicating logic.

Files:

  • app/api/alchemy/token-metadata/route.ts
  • app/api/alchemy/contract/route.ts
app/api/**/route.ts

📄 CodeRabbit inference engine (app/api/AGENTS.md)

app/api/**/route.ts: Export HTTP verb handlers (e.g. GET, POST, etc.) from route.ts files, keeping logic in small internal functions when it grows beyond ~200 lines.
For edge caching behavior, prefer export const dynamic = "force-dynamic"; or revalidate constants rather than inline headers.

Files:

  • app/api/alchemy/token-metadata/route.ts
  • app/api/alchemy/contract/route.ts
app/api/**/*.{ts,tsx}

📄 CodeRabbit inference engine (app/api/AGENTS.md)

Use TypeScript types for request parameters and responses; avoid any unless a 3rd-party payload truly has no shape guarantees.

Files:

  • app/api/alchemy/token-metadata/route.ts
  • app/api/alchemy/contract/route.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Must pass tsc --noEmit type checking
Prefer direct named imports for React hooks and types (import { useMemo, useRef, FC, etc. } from "react") over React. namespace usage (React.useMemo, React.useRef, etc.)
If the react-hooks/exhaustive-deps lint rule is triggered: if the Effect only derives state, remove the Effect and compute during render; if listening to an external system and needing fresh props/state, wrap non-reactive logic in useEffectEvent

**/*.{ts,tsx}: Must pass tsc --noEmit for TypeScript type checking
Prefer Server Components over Client Components; use Server Functions/Server Actions ('use server') for mutations
Remove unnecessary Effects; if Effect only derives state, compute during render instead
Use useEffectEvent for non-reactive logic inside Effects to avoid unnecessary re-runs
Use framework APIs: <Link> for internal links, next/image for images, adopt Next's ESLint rules
Use 'use cache' directive and Cache Components features for explicit opt-in caching in Next.js 16
Use TypeScript and React functional components with hooks
When parsing Seize URLs or similar, fail fast if base origin is unavailable; do not fall back to placeholder origins
Replace <img> elements with <Image /> from next/image
Use <Link href="/path"> for internal navigation instead of plain HTML links
Move data fetches to Server Components; handle mutations through Server Functions/Server Actions with 'use server' directive

Files:

  • app/api/alchemy/token-metadata/route.ts
  • services/alchemy/tokens.ts
  • services/alchemy/utils.ts
  • services/alchemy/owner-nfts.ts
  • services/alchemy/collections.ts
  • __tests__/services/alchemy-api.test.ts
  • hooks/useAlchemyNftQueries.ts
  • components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx
  • services/alchemy/types.ts
  • app/api/alchemy/contract/route.ts
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Routes in app/ should export generateMetadata using the helper getAppMetadata with a title property

All production routes must live under the App Router (app/) directory

Files:

  • app/api/alchemy/token-metadata/route.ts
  • app/api/alchemy/contract/route.ts
**/@(__tests__|*.test).{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Tests should live in __tests__/ or ComponentName.test.tsx; mock external dependencies and APIs in tests

Files:

  • __tests__/services/alchemy-api.test.ts
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
**/__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Place tests in __tests__/ directory or as ComponentName.test.tsx alongside components

Files:

  • __tests__/services/alchemy-api.test.ts
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Mock external dependencies and APIs in tests

Files:

  • __tests__/services/alchemy-api.test.ts
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
__tests__/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (tests/AGENTS.md)

Use Jest + ts-jest for TypeScript testing

Files:

  • __tests__/services/alchemy-api.test.ts
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (tests/AGENTS.md)

Functions must have ≤ 15 cognitive complexity; extract deep ternaries (>3 levels) and break down complex logic

Files:

  • __tests__/services/alchemy-api.test.ts
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
__tests__/**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (tests/AGENTS.md)

__tests__/**/*.{ts,tsx,js}: Prefer for...of loops over forEach as it allows break/continue and works with async/await
Use array.at(-1) and array.at(-2) instead of index-based array access for negative indexing
Use String.prototype.replaceAll() instead of replace() for global string replacements
Use globalThis.fetch() instead of direct fetch() calls
Organize imports with one import per module in order: external → internal → types, with no duplicates
Use element.remove() instead of parent.removeChild(element) for DOM manipulation
Catch errors only when meaningful; no empty catch blocks; log errors with context
Avoid double negatives in code; prefer explicit logic and remove redundant annotations; use optional chaining (?.)

Files:

  • __tests__/services/alchemy-api.test.ts
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{tsx,jsx}: Use FontAwesome for icons in React components
Use TailwindCSS for styling in React components
Use react-query for data fetching
Always add readonly before props in React components

Files:

  • components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
__tests__/**/{components,contexts,hooks}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (tests/AGENTS.md)

Use semantic HTML elements (<label>, <output>) over ARIA attributes when possible; every form control must have a label

Files:

  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
🧠 Learnings (18)
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.test.{ts,tsx} : Mock external dependencies and APIs in tests

Applied to files:

  • jest.setup.js
  • __tests__/services/alchemy-api.test.ts
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/__tests__/**/components/**/*.test.{ts,tsx} : Use testing-library/react + user-event for React component tests

Applied to files:

  • jest.setup.js
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Applies to **/@(__tests__|*.test).{ts,tsx} : Tests should live in `__tests__/` or `ComponentName.test.tsx`; mock external dependencies and APIs in tests

Applied to files:

  • jest.setup.js
  • __tests__/services/alchemy-api.test.ts
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Fix with modernization (no `// eslint-disable` unless explicitly instructed); prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions

Applied to files:

  • jest.setup.js
  • components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/app/api/**/__tests__/**/*.test.{ts,tsx,js} : API integration tests should be located in `app/api`

Applied to files:

  • __tests__/services/alchemy-api.test.ts
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/__tests__/**/*.test.{ts,tsx,js} : Keep tests independent, deterministic, and fast with production-like data

Applied to files:

  • __tests__/services/alchemy-api.test.ts
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/*.test.{ts,tsx} : Use Jest + `ts-jest` for TypeScript testing

Applied to files:

  • __tests__/services/alchemy-api.test.ts
📚 Learning: 2025-11-25T08:37:44.688Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: app/api/AGENTS.md:0-0
Timestamp: 2025-11-25T08:37:44.688Z
Learning: All changes must pass the same commands listed in the top-level AGENTS.md: `npm run test`, `npm run lint`, and `npm run type-check` (or the targeted `test:cov:changed` when appropriate).

Applied to files:

  • __tests__/services/alchemy-api.test.ts
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Run `npm run test` to execute all Jest tests and enforce ≥ 80% line coverage for files changed since `main`

Applied to files:

  • __tests__/services/alchemy-api.test.ts
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/*.{ts,tsx,js} : Avoid double negatives in code; prefer explicit logic and remove redundant annotations; use optional chaining (`?.`)

Applied to files:

  • __tests__/services/alchemy-api.test.ts
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/__tests__/**/*.test.{ts,tsx,js} : Test high-risk areas including happy path workflows, invalid input errors, edge cases/boundaries, component & API interactions, and performance/security when relevant

Applied to files:

  • __tests__/services/alchemy-api.test.ts
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/__tests__/**/*.test.{ts,tsx,js} : Write tests following Arrange – Act – Assert pattern with one behaviour per test and clear, descriptive names

Applied to files:

  • __tests__/services/alchemy-api.test.ts
📚 Learning: 2025-11-25T08:37:44.688Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: app/api/AGENTS.md:0-0
Timestamp: 2025-11-25T08:37:44.688Z
Learning: Applies to app/api/**/*.{ts,tsx,js,jsx} : Catch `UrlGuardError` explicitly if returning a tailored response; otherwise let it bubble so the caller can surface the correct status code.

Applied to files:

  • hooks/useAlchemyNftQueries.ts
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.{ts,tsx} : When parsing Seize URLs or similar, fail fast if base origin is unavailable; do not fall back to placeholder origins

Applied to files:

  • hooks/useAlchemyNftQueries.ts
📚 Learning: 2025-11-25T08:37:44.688Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: app/api/AGENTS.md:0-0
Timestamp: 2025-11-25T08:37:44.688Z
Learning: Applies to app/api/**/*.{ts,tsx,js,jsx} : Never call `fetch` directly with user-controlled or scraped URLs. Use helpers from `@/lib/security/urlGuard` (`parsePublicUrl`, `assertPublicUrl`, `fetchPublicUrl`, `fetchPublicJson`) to validate URLs against host/IP allowlists and DNS checks before making network requests.

Applied to files:

  • hooks/useAlchemyNftQueries.ts
📚 Learning: 2025-11-25T08:35:58.729Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T08:35:58.729Z
Learning: Applies to **/*.{tsx,jsx} : Use react-query for data fetching

Applied to files:

  • hooks/useAlchemyNftQueries.ts
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: TypeScript + React functional components with hooks; follow existing code style and naming conventions; maintain clean code standards (measured by SonarQube)

Applied to files:

  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/*.{ts,tsx,js} : Use `globalThis.fetch()` instead of direct `fetch()` calls

Applied to files:

  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
🧬 Code graph analysis (6)
app/api/alchemy/token-metadata/route.ts (2)
services/alchemy/utils.ts (2)
  • resolveNetwork (22-24)
  • normaliseAddress (153-168)
helpers/Helpers.ts (1)
  • isValidEthAddress (234-235)
services/alchemy/utils.ts (1)
services/alchemy/types.ts (9)
  • AlchemySearchResponse (71-74)
  • SearchContractsResult (11-15)
  • AlchemyContractMetadataResponse (76-83)
  • AlchemyContractMetadata (31-48)
  • AlchemyContractResult (59-69)
  • AlchemyOwnedNft (156-158)
  • OwnerNft (160-166)
  • AlchemyTokenMetadataEntry (122-149)
  • AlchemyTokenMetadataResponse (151-154)
services/alchemy/owner-nfts.ts (2)
services/alchemy/types.ts (1)
  • OwnerNft (160-166)
services/alchemy/utils.ts (1)
  • processOwnerNftsResponse (270-278)
services/alchemy/collections.ts (2)
services/alchemy/types.ts (3)
  • SearchContractsParams (3-9)
  • SearchContractsResult (11-15)
  • AlchemySearchResponse (71-74)
services/alchemy/utils.ts (2)
  • processSearchResponse (217-236)
  • processContractMetadataResponse (238-268)
components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx (3)
services/alchemy/types.ts (1)
  • OwnerNft (160-166)
hooks/useAlchemyNftQueries.ts (1)
  • fetchOwnerNfts (434-453)
components/nextGen/nextgen_contracts.ts (2)
  • NEXTGEN_CHAIN_ID (29-29)
  • NEXTGEN_CORE (54-59)
app/api/alchemy/contract/route.ts (2)
services/alchemy/utils.ts (2)
  • resolveNetwork (22-24)
  • normaliseAddress (153-168)
helpers/Helpers.ts (1)
  • isValidEthAddress (234-235)
⏰ 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). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (39)
__tests__/services/alchemy-api.test.ts (4)

1-7: LGTM!

The Jest environment directive and mock setup are correctly configured. The @jest-environment node directive is appropriate for testing server-side Alchemy API code, and the mock for @/config/alchemyEnv properly returns a test API key.


35-66: LGTM!

The test properly verifies spam filtering behavior and follows the Arrange-Act-Assert pattern. The mock response structure accurately reflects the Alchemy API response format.


68-98: LGTM!

Good coverage of both the error case (invalid address) and the happy path with proper metadata normalization verification.


100-124: LGTM!

The test verifies batch token metadata fetching and proper response transformation, including image URL extraction from the cached URL field.

app/api/alchemy/contract/route.ts (1)

40-43: Verify compliance with urlGuard coding guidelines for external API calls.

Per the coding guidelines for app/api/**/*.{ts,tsx,js,jsx}, external fetches should use helpers from @/lib/security/urlGuard to validate URLs. While the Alchemy URL is constructed from a trusted template and config, please verify if urlGuard helpers are required here or if this pattern is an approved exception.

services/alchemy/tokens.ts (2)

77-78: LGTM!

Clean refactor delegating token metadata normalization to processTokenMetadataResponse. This centralizes the transformation logic and improves maintainability.


9-13: LGTM!

Good consolidation of imports from the centralized ./utils module, aligning with the PR's goal of extracting response processing into dedicated utilities.

jest.setup.js (2)

35-71: LGTM!

Wrapping window-specific mocks in a typeof window !== "undefined" guard is a good practice. This allows tests with @jest-environment node (like the new Alchemy API tests) to run without errors from attempting to mock undefined window properties.


106-111: LGTM!

Minor formatting improvements to the ResizeObserver mock methods.

services/alchemy/collections.ts (3)

49-50: LGTM!

Clean delegation to processSearchResponse with proper passing of the hideSpam parameter. This centralizes the contract-to-suggestion mapping logic.


79-82: LGTM!

Good refactor delegating contract metadata processing to processContractMetadataResponse. The checksum is correctly passed to ensure address consistency in the response.


23-29: LGTM!

Improved parameter destructuring with cleaner default values for chain and hideSpam.

services/alchemy/types.ts (3)

1-1: LGTM!

Import consolidation to a single line is cleaner.


122-149: LGTM!

The contract type extension with spamClassifications aligns with AlchemyContractResult definition at line 65, maintaining consistency across type definitions.


160-167: LGTM!

The OwnerNft type is well-structured with a required tokenId and appropriately nullable optional fields. This provides a clean, minimal interface for consumer components.

__tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx (6)

1-63: LGTM!

Updated imports and mocks properly use path aliases consistent with the codebase conventions. The react-bootstrap mock structure adequately simulates form components for testing. Based on learnings, external dependencies and APIs are correctly mocked.


67-84: LGTM!

The createMintState helper is expanded to include all fields from the actual useMintSharedState hook, providing a complete mock state for tests.


86-136: LGTM!

The baseProps and renderWidget helper are well-structured. The merkle_root changed from a number to string aligns with typical merkle root representations, and the added status field enables burn-state testing.


148-181: LGTM!

Test data structure updated to wrap NFTs in ownedNfts object, matching the AlchemyGetNftsForOwnerResponse type. The filter test correctly verifies that only tokens within the specified range (100-200) and with the correct prefix are displayed.


199-206: LGTM!

The burn-not-active test correctly verifies that when status: false, the button is disabled and shows "Burn Not Active" text.


193-197: The test correctly expects the <output> element to be present when isMinting is true. The Spinner component in ./components/nextGen/collections/collectionParts/mint/NextGenMint.tsx (lines 48-53) renders <output className={spinner-border ${styles.loader}}></output>, which the test assertion properly queries. This aligns with semantic HTML best practices.

hooks/useAlchemyNftQueries.ts (6)

48-60: LGTM!

The isAbortError helper correctly handles both DOMException and generic Error with AbortError name, ensuring compatibility across different environments.


73-90: LGTM!

The failover implementation correctly re-throws AbortError to prevent unintended fallback requests when a request is intentionally cancelled. This addresses the concern from the previous review.


100-116: LGTM!

The fetchCollectionsFromApi function properly constructs query strings and delegates to fetchJsonWithFailover with appropriate primary and fallback paths.


118-148: LGTM!

The fetchContractOverviewFromApi function properly validates the address with normaliseAddress before making the request, and correctly extracts the checksum from the response or uses the validated one.


150-173: LGTM!

The fetchTokenMetadataFromApi function correctly uses POST method with JSON body for batch token metadata requests, aligning with API expectations.


434-453: LGTM!

The fetchOwnerNfts function is well-implemented with proper query string construction and failover support. The ?? [] fallback for ownedNfts ensures safe handling of missing data.

components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx (2)

3-34: LGTM!

Import reorganization is clean, bringing in the new fetchOwnerNfts helper and OwnerNft type while maintaining proper grouping of external and internal dependencies.


79-106: LGTM!

The state typing and filter function are correctly updated to use OwnerNft[]. The numeric conversion with Number(t.tokenId) for range comparison and startsWith for prefix matching are appropriate.

services/alchemy/utils.ts (6)

1-16: LGTM!

Import updates properly bring in all required types for the new processing functions.


217-236: LGTM!

The processSearchResponse function cleanly separates concerns: extraction, spam filtering, and result shaping. The hidden count logic correctly tracks filtered spam items.


238-268: LGTM!

The processContractMetadataResponse function properly resolves OpenSea metadata from multiple sources and delegates to extractContract for consistent suggestion creation.


270-278: LGTM!

The processOwnerNftsResponse function provides clean mapping from AlchemyOwnedNft to OwnerNft with appropriate defaults for missing fields.


280-317: LGTM!

The parseTokenIdToBigint and normaliseTokenMetadata functions handle edge cases appropriately. The silent catch at line 314 is acceptable since invalid token IDs are filtered out rather than causing failures.


319-329: LGTM!

The processTokenMetadataResponse function correctly handles both tokens and nfts response formats with fallback to empty array, and filters out invalid entries.

services/alchemy/owner-nfts.ts (3)

3-9: LGTM!

Import updates properly bring in the OwnerNft type and processOwnerNftsResponse utility, enabling consistent response processing.


17-57: LGTM!

The createAbortError and delayWithAbort helpers are well-implemented:

  • createAbortError handles both modern DOMException and legacy Error environments
  • delayWithAbort properly cleans up event listeners in both completion and abort paths, preventing memory leaks

67-122: LGTM!

The getNftsForContractAndOwner function is well-structured with:

  • Proper input validation
  • Retry logic with backoff for transient errors
  • Pagination support via pageKey
  • AbortSignal propagation for cancellation
  • Clean delegation to processOwnerNftsResponse for result transformation

Note: Goerli testnet is deprecated but keeping support is reasonable for backwards compatibility with existing deployments.

app/api/alchemy/token-metadata/route.ts (1)

78-109: No changes needed. The route correctly returns raw Alchemy responses as expected by its callers. The hook in useAlchemyNftQueries.ts explicitly expects AlchemyTokenMetadataResponse (the raw format) and applies normalization through processTokenMetadataResponse() after receiving it. This design pattern is consistent with other Alchemy integrations in the codebase.

Likely an incorrect or invalid review comment.

Comment thread app/api/alchemy/token-metadata/route.ts Outdated
Comment thread app/api/alchemy/token-metadata/route.ts
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
Copy link
Copy Markdown

@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

🧹 Nitpick comments (4)
app/api/alchemy/token-metadata/route.ts (3)

126-134: Consider adding timeout to fetch calls.

The fetch call to Alchemy lacks a timeout, which could cause requests to hang indefinitely if the external API is slow or unresponsive. This is especially important in a batched loop where multiple sequential requests are made.

Add a timeout using AbortSignal.timeout:

      const response = await fetch(url, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Accept: "application/json",
        },
        body: JSON.stringify({ tokens: slice }),
-        signal: request.signal,
+        signal: AbortSignal.any([
+          request.signal,
+          AbortSignal.timeout(10000)
+        ]),
      });

136-141: Consider surfacing more detailed error information.

The generic error message "Failed to fetch token metadata" doesn't provide details about what went wrong with the Alchemy API call. Including the status code and response body (if available) would help with debugging.

      if (!response.ok) {
+        const errorBody = await response.text().catch(() => "");
        return NextResponse.json(
-          { error: "Failed to fetch token metadata" },
+          { 
+            error: "Failed to fetch token metadata",
+            details: errorBody || `HTTP ${response.status}`,
+          },
          { status: response.status, headers: NO_STORE_HEADERS }
        );
      }

144-144: Defensive response parsing suggests API version uncertainty.

The fallback chain payload.tokens ?? payload.nfts ?? [] indicates the response structure may vary between API versions or that there's uncertainty about the shape. Consider documenting which Alchemy API version is expected and whether both formats are officially supported, or add a comment explaining why the fallback is necessary.

services/6529api.ts (1)

16-24: Verify that calling code properly handles 401 responses now returned instead of thrown.

The early return on line 19 is an intentional behavior change confirmed by the test suite (test: "fetchUrl removes cookie on 401 and returns json"). However, callers relying on try-catch error handling will no longer catch 401 errors. Verify that all code calling fetchUrl, postData, postFormData, and fetchAllPages explicitly checks the response status or .then() chaining to handle 401 responses, rather than depending on exception handling.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a2783ad and 6111384.

📒 Files selected for processing (7)
  • __tests__/components/header/HeaderSearchModalItem.test.tsx (1 hunks)
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx (7 hunks)
  • __tests__/components/user/layout/UserPageTabs.test.tsx (2 hunks)
  • __tests__/services/6529api.test.ts (1 hunks)
  • app/api/alchemy/token-metadata/route.ts (2 hunks)
  • jest.setup.js (2 hunks)
  • services/6529api.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • jest.setup.js
🧰 Additional context used
📓 Path-based instructions (15)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx,js,jsx}: Do not include any comments in the code; it should be self-explanatory
Write correct, up-to-date, bug-free, fully componentized, secure, and efficient code
Include all required imports and ensure proper naming of key components
Use NextJS features that match the current version

**/*.{ts,tsx,js,jsx}: Replace <img> elements with <Image /> from next/image to satisfy @next/next/no-img-element ESLint rule
Use <Link href="/path"> from Next.js for internal navigation instead of plain HTML links to satisfy @next/next/no-html-link-for-pages ESLint rule

Files:

  • __tests__/components/header/HeaderSearchModalItem.test.tsx
  • __tests__/services/6529api.test.ts
  • services/6529api.ts
  • app/api/alchemy/token-metadata/route.ts
  • __tests__/components/user/layout/UserPageTabs.test.tsx
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{tsx,jsx}: Use FontAwesome for icons in React components
Use TailwindCSS for styling in React components
Use react-query for data fetching
Always add readonly before props in React components

Files:

  • __tests__/components/header/HeaderSearchModalItem.test.tsx
  • __tests__/components/user/layout/UserPageTabs.test.tsx
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks)
Use framework APIs: internal links should use <Link>, images should use next/image, and adopt Next's ESLint rules (Core Web Vitals)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks rules)
Follow existing code style and naming conventions; maintain clean code standards (measured by SonarQube)

Files:

  • __tests__/components/header/HeaderSearchModalItem.test.tsx
  • __tests__/services/6529api.test.ts
  • services/6529api.ts
  • app/api/alchemy/token-metadata/route.ts
  • __tests__/components/user/layout/UserPageTabs.test.tsx
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Must pass tsc --noEmit type checking
Prefer direct named imports for React hooks and types (import { useMemo, useRef, FC, etc. } from "react") over React. namespace usage (React.useMemo, React.useRef, etc.)
If the react-hooks/exhaustive-deps lint rule is triggered: if the Effect only derives state, remove the Effect and compute during render; if listening to an external system and needing fresh props/state, wrap non-reactive logic in useEffectEvent

**/*.{ts,tsx}: Must pass tsc --noEmit for TypeScript type checking
Prefer Server Components over Client Components; use Server Functions/Server Actions ('use server') for mutations
Remove unnecessary Effects; if Effect only derives state, compute during render instead
Use useEffectEvent for non-reactive logic inside Effects to avoid unnecessary re-runs
Use framework APIs: <Link> for internal links, next/image for images, adopt Next's ESLint rules
Use 'use cache' directive and Cache Components features for explicit opt-in caching in Next.js 16
Use TypeScript and React functional components with hooks
When parsing Seize URLs or similar, fail fast if base origin is unavailable; do not fall back to placeholder origins
Replace <img> elements with <Image /> from next/image
Use <Link href="/path"> for internal navigation instead of plain HTML links
Move data fetches to Server Components; handle mutations through Server Functions/Server Actions with 'use server' directive

Files:

  • __tests__/components/header/HeaderSearchModalItem.test.tsx
  • __tests__/services/6529api.test.ts
  • services/6529api.ts
  • app/api/alchemy/token-metadata/route.ts
  • __tests__/components/user/layout/UserPageTabs.test.tsx
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
**/@(__tests__|*.test).{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Tests should live in __tests__/ or ComponentName.test.tsx; mock external dependencies and APIs in tests

Files:

  • __tests__/components/header/HeaderSearchModalItem.test.tsx
  • __tests__/services/6529api.test.ts
  • __tests__/components/user/layout/UserPageTabs.test.tsx
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
**/__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Place tests in __tests__/ directory or as ComponentName.test.tsx alongside components

Files:

  • __tests__/components/header/HeaderSearchModalItem.test.tsx
  • __tests__/services/6529api.test.ts
  • __tests__/components/user/layout/UserPageTabs.test.tsx
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Mock external dependencies and APIs in tests

Files:

  • __tests__/components/header/HeaderSearchModalItem.test.tsx
  • __tests__/services/6529api.test.ts
  • __tests__/components/user/layout/UserPageTabs.test.tsx
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
__tests__/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (tests/AGENTS.md)

Use Jest + ts-jest for TypeScript testing

Files:

  • __tests__/components/header/HeaderSearchModalItem.test.tsx
  • __tests__/services/6529api.test.ts
  • __tests__/components/user/layout/UserPageTabs.test.tsx
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (tests/AGENTS.md)

Functions must have ≤ 15 cognitive complexity; extract deep ternaries (>3 levels) and break down complex logic

Files:

  • __tests__/components/header/HeaderSearchModalItem.test.tsx
  • __tests__/services/6529api.test.ts
  • __tests__/components/user/layout/UserPageTabs.test.tsx
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
__tests__/**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (tests/AGENTS.md)

__tests__/**/*.{ts,tsx,js}: Prefer for...of loops over forEach as it allows break/continue and works with async/await
Use array.at(-1) and array.at(-2) instead of index-based array access for negative indexing
Use String.prototype.replaceAll() instead of replace() for global string replacements
Use globalThis.fetch() instead of direct fetch() calls
Organize imports with one import per module in order: external → internal → types, with no duplicates
Use element.remove() instead of parent.removeChild(element) for DOM manipulation
Catch errors only when meaningful; no empty catch blocks; log errors with context
Avoid double negatives in code; prefer explicit logic and remove redundant annotations; use optional chaining (?.)

Files:

  • __tests__/components/header/HeaderSearchModalItem.test.tsx
  • __tests__/services/6529api.test.ts
  • __tests__/components/user/layout/UserPageTabs.test.tsx
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
__tests__/**/{components,contexts,hooks}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (tests/AGENTS.md)

Use semantic HTML elements (<label>, <output>) over ARIA attributes when possible; every form control must have a label

Files:

  • __tests__/components/header/HeaderSearchModalItem.test.tsx
  • __tests__/components/user/layout/UserPageTabs.test.tsx
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
app/api/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (app/api/AGENTS.md)

app/api/**/*.{ts,tsx,js,jsx}: Never call fetch directly with user-controlled or scraped URLs. Use helpers from @/lib/security/urlGuard (parsePublicUrl, assertPublicUrl, fetchPublicUrl, fetchPublicJson) to validate URLs against host/IP allowlists and DNS checks before making network requests.
When needing custom headers or timeouts for external requests, pass them via @/lib/security/urlGuard helper options rather than re-implementing your own wrapper.
Catch UrlGuardError explicitly if returning a tailored response; otherwise let it bubble so the caller can surface the correct status code.
Follow the project default responses (NextResponse.json) and reuse existing util modules instead of duplicating logic.

Files:

  • app/api/alchemy/token-metadata/route.ts
app/api/**/route.ts

📄 CodeRabbit inference engine (app/api/AGENTS.md)

app/api/**/route.ts: Export HTTP verb handlers (e.g. GET, POST, etc.) from route.ts files, keeping logic in small internal functions when it grows beyond ~200 lines.
For edge caching behavior, prefer export const dynamic = "force-dynamic"; or revalidate constants rather than inline headers.

Files:

  • app/api/alchemy/token-metadata/route.ts
app/api/**/*.{ts,tsx}

📄 CodeRabbit inference engine (app/api/AGENTS.md)

Use TypeScript types for request parameters and responses; avoid any unless a 3rd-party payload truly has no shape guarantees.

Files:

  • app/api/alchemy/token-metadata/route.ts
app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Routes in app/ should export generateMetadata using the helper getAppMetadata with a title property

All production routes must live under the App Router (app/) directory

Files:

  • app/api/alchemy/token-metadata/route.ts
🧠 Learnings (20)
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Applies to **/@(__tests__|*.test).{ts,tsx} : Tests should live in `__tests__/` or `ComponentName.test.tsx`; mock external dependencies and APIs in tests

Applied to files:

  • __tests__/components/header/HeaderSearchModalItem.test.tsx
  • __tests__/services/6529api.test.ts
  • __tests__/components/user/layout/UserPageTabs.test.tsx
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.test.{ts,tsx} : Mock external dependencies and APIs in tests

Applied to files:

  • __tests__/components/header/HeaderSearchModalItem.test.tsx
  • __tests__/services/6529api.test.ts
  • __tests__/components/user/layout/UserPageTabs.test.tsx
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/*.{ts,tsx,js} : Use `globalThis.fetch()` instead of direct `fetch()` calls

Applied to files:

  • __tests__/services/6529api.test.ts
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/*.{ts,tsx,js} : Avoid double negatives in code; prefer explicit logic and remove redundant annotations; use optional chaining (`?.`)

Applied to files:

  • __tests__/services/6529api.test.ts
  • __tests__/components/user/layout/UserPageTabs.test.tsx
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
📚 Learning: 2025-11-25T08:37:44.688Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: app/api/AGENTS.md:0-0
Timestamp: 2025-11-25T08:37:44.688Z
Learning: Applies to app/api/**/*.{ts,tsx,js,jsx} : When needing custom headers or timeouts for external requests, pass them via `@/lib/security/urlGuard` helper options rather than re-implementing your own wrapper.

Applied to files:

  • __tests__/services/6529api.test.ts
  • services/6529api.ts
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/app/api/**/__tests__/**/*.test.{ts,tsx,js} : API integration tests should be located in `app/api`

Applied to files:

  • __tests__/services/6529api.test.ts
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/__tests__/**/*.test.{ts,tsx,js} : Keep tests independent, deterministic, and fast with production-like data

Applied to files:

  • __tests__/services/6529api.test.ts
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/__tests__/**/*.test.{ts,tsx,js} : Test high-risk areas including happy path workflows, invalid input errors, edge cases/boundaries, component & API interactions, and performance/security when relevant

Applied to files:

  • __tests__/services/6529api.test.ts
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/__tests__/**/*.test.{ts,tsx,js} : Write tests following Arrange – Act – Assert pattern with one behaviour per test and clear, descriptive names

Applied to files:

  • __tests__/services/6529api.test.ts
📚 Learning: 2025-11-25T08:37:44.688Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: app/api/AGENTS.md:0-0
Timestamp: 2025-11-25T08:37:44.688Z
Learning: All changes must pass the same commands listed in the top-level AGENTS.md: `npm run test`, `npm run lint`, and `npm run type-check` (or the targeted `test:cov:changed` when appropriate).

Applied to files:

  • __tests__/services/6529api.test.ts
📚 Learning: 2025-11-25T08:37:44.688Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: app/api/AGENTS.md:0-0
Timestamp: 2025-11-25T08:37:44.688Z
Learning: Applies to app/api/**/*.{ts,tsx,js,jsx} : Catch `UrlGuardError` explicitly if returning a tailored response; otherwise let it bubble so the caller can surface the correct status code.

Applied to files:

  • services/6529api.ts
📚 Learning: 2025-11-25T08:37:44.688Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: app/api/AGENTS.md:0-0
Timestamp: 2025-11-25T08:37:44.688Z
Learning: Applies to app/api/**/*.{ts,tsx,js,jsx} : Follow the project default responses (`NextResponse.json`) and reuse existing util modules instead of duplicating logic.

Applied to files:

  • services/6529api.ts
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/__tests__/**/components/**/*.test.{ts,tsx} : Use testing-library/react + user-event for React component tests

Applied to files:

  • __tests__/components/user/layout/UserPageTabs.test.tsx
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/__tests__/**/components/**/*.test.{ts,tsx} : Test accessibility with keyboard navigation and screen reader compatibility

Applied to files:

  • __tests__/components/user/layout/UserPageTabs.test.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Fix with modernization (no `// eslint-disable` unless explicitly instructed); prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions

Applied to files:

  • __tests__/components/user/layout/UserPageTabs.test.tsx
  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/{components,contexts,hooks}/**/*.{ts,tsx} : Use semantic HTML elements (`<label>`, `<output>`) over ARIA attributes when possible; every form control must have a label

Applied to files:

  • __tests__/components/user/layout/UserPageTabs.test.tsx
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/__tests__/**/*.{ts,tsx} : Place tests in `__tests__/` directory or as `ComponentName.test.tsx` alongside components

Applied to files:

  • __tests__/components/user/layout/UserPageTabs.test.tsx
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to app/**/page.{ts,tsx} : Export `generateMetadata` in App Router routes using the `getAppMetadata` helper from '@/components/providers/metadata'

Applied to files:

  • __tests__/components/user/layout/UserPageTabs.test.tsx
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.{ts,tsx} : Use framework APIs: `<Link>` for internal links, `next/image` for images, adopt Next's ESLint rules

Applied to files:

  • __tests__/components/user/layout/UserPageTabs.test.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: TypeScript + React functional components with hooks; follow existing code style and naming conventions; maintain clean code standards (measured by SonarQube)

Applied to files:

  • __tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx
🧬 Code graph analysis (1)
app/api/alchemy/token-metadata/route.ts (2)
services/alchemy/utils.ts (2)
  • normaliseAddress (153-168)
  • resolveNetwork (22-24)
helpers/Helpers.ts (1)
  • isValidEthAddress (234-235)
⏰ 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). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (7)
__tests__/components/user/layout/UserPageTabs.test.tsx (1)

5-10: LGTM! Clean addition of useParams mocking.

The changes properly add mocking for the useParams hook, following the same pattern as the other Next.js navigation hooks. The mock return value { user: "testuser" } appropriately simulates route parameters needed by the component under test.

Also applies to: 16-16, 43-43

__tests__/components/header/HeaderSearchModalItem.test.tsx (1)

45-45: LGTM!

The mock addition follows the existing pattern and correctly provides a test stub for the formatStatFloor helper. The identity function implementation is appropriate for unit testing where the focus is on component behavior rather than helper logic.

__tests__/components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.test.tsx (3)

1-62: LGTM: Imports and mocks properly structured.

The migration to alias imports and expanded mock coverage aligns well with the component's dependencies. The mock implementations are comprehensive and follow testing best practices.


66-109: LGTM: Test state and props align with updated component API.

The expanded state fields (isMinting, fetchingProofs, errors) and string-typed identifiers (mintForAddress, tokenId) correctly reflect the component's updated interface and match the new OwnerNft data structure introduced in the PR.


147-206: LGTM: Test cases properly updated for new data format.

The test suite correctly validates the component's behavior with the new OwnerNft structure:

  • NFT filtering logic verified with string-typed tokenIds
  • Connection and chain validation states covered
  • Minting and burn status handling tested

All assertions align with the updated API response format and maintain comprehensive coverage of the component's functionality.

app/api/alchemy/token-metadata/route.ts (1)

1-9: LGTM! Duplication issue resolved.

The imports now correctly use resolveNetwork from the shared utilities module, addressing the previous refactoring suggestion. Constants are well-defined.

__tests__/services/6529api.test.ts (1)

1-99: LGTM! Test refactoring improves maintainability.

The introduction of the getHeaders helper function and more explicit mock response shapes improves test clarity and maintainability. The functional behavior is preserved while making assertions more readable.

Comment thread app/api/alchemy/token-metadata/route.ts
Comment thread app/api/alchemy/token-metadata/route.ts Outdated
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown

@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 (3)
app/api/alchemy/token-metadata/route.ts (1)

45-48: Defensive but unreachable code path.

After isValidEthAddress(address) passes on line 42, the normaliseAddress call cannot return null because it only returns null when the address is falsy or fails isValidEthAddress. This makes lines 46-48 effectively dead code.

This defensive coding isn't harmful and protects against potential future changes to normaliseAddress, so it can remain as-is.

__tests__/services/6529api.test.ts (2)

1-4: Reorder imports: external before internal.

According to the coding guidelines, imports should be organized as external → internal → types. The js-cookie import should come before the internal @/ imports.

Apply this diff to fix the import order:

+import Cookies from "js-cookie";
 import { API_AUTH_COOKIE } from "@/constants";
 import * as api from "@/services/6529api";
 import { getStagingAuth } from "@/services/auth/auth.utils";
-import Cookies from "js-cookie";

Based on learnings, imports should be organized with one import per module in order: external → internal → types, with no duplicates.


21-32: Add ok: false to the 401 mock response.

The mock Response object should include ok: false to accurately simulate a real fetch Response with a 401 status. This makes the test more realistic and ensures the service code is tested against proper Response shapes.

Apply this diff to improve the mock:

     (globalThis.fetch as jest.Mock).mockResolvedValue({ status: 401, json });
+    (globalThis.fetch as jest.Mock).mockResolvedValue({ ok: false, status: 401, json });
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6111384 and eb5afac.

📒 Files selected for processing (2)
  • __tests__/services/6529api.test.ts (1 hunks)
  • app/api/alchemy/token-metadata/route.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (13)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx,js,jsx}: Do not include any comments in the code; it should be self-explanatory
Write correct, up-to-date, bug-free, fully componentized, secure, and efficient code
Include all required imports and ensure proper naming of key components
Use NextJS features that match the current version

**/*.{ts,tsx,js,jsx}: Replace <img> elements with <Image /> from next/image to satisfy @next/next/no-img-element ESLint rule
Use <Link href="/path"> from Next.js for internal navigation instead of plain HTML links to satisfy @next/next/no-html-link-for-pages ESLint rule

Files:

  • __tests__/services/6529api.test.ts
  • app/api/alchemy/token-metadata/route.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks)
Use framework APIs: internal links should use <Link>, images should use next/image, and adopt Next's ESLint rules (Core Web Vitals)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks rules)
Follow existing code style and naming conventions; maintain clean code standards (measured by SonarQube)

Files:

  • __tests__/services/6529api.test.ts
  • app/api/alchemy/token-metadata/route.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Must pass tsc --noEmit type checking
Prefer direct named imports for React hooks and types (import { useMemo, useRef, FC, etc. } from "react") over React. namespace usage (React.useMemo, React.useRef, etc.)
If the react-hooks/exhaustive-deps lint rule is triggered: if the Effect only derives state, remove the Effect and compute during render; if listening to an external system and needing fresh props/state, wrap non-reactive logic in useEffectEvent

**/*.{ts,tsx}: Must pass tsc --noEmit for TypeScript type checking
Prefer Server Components over Client Components; use Server Functions/Server Actions ('use server') for mutations
Remove unnecessary Effects; if Effect only derives state, compute during render instead
Use useEffectEvent for non-reactive logic inside Effects to avoid unnecessary re-runs
Use framework APIs: <Link> for internal links, next/image for images, adopt Next's ESLint rules
Use 'use cache' directive and Cache Components features for explicit opt-in caching in Next.js 16
Use TypeScript and React functional components with hooks
When parsing Seize URLs or similar, fail fast if base origin is unavailable; do not fall back to placeholder origins
Replace <img> elements with <Image /> from next/image
Use <Link href="/path"> for internal navigation instead of plain HTML links
Move data fetches to Server Components; handle mutations through Server Functions/Server Actions with 'use server' directive

Files:

  • __tests__/services/6529api.test.ts
  • app/api/alchemy/token-metadata/route.ts
**/@(__tests__|*.test).{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Tests should live in __tests__/ or ComponentName.test.tsx; mock external dependencies and APIs in tests

Files:

  • __tests__/services/6529api.test.ts
**/__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Place tests in __tests__/ directory or as ComponentName.test.tsx alongside components

Files:

  • __tests__/services/6529api.test.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Mock external dependencies and APIs in tests

Files:

  • __tests__/services/6529api.test.ts
__tests__/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (tests/AGENTS.md)

Use Jest + ts-jest for TypeScript testing

Files:

  • __tests__/services/6529api.test.ts
__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (tests/AGENTS.md)

Functions must have ≤ 15 cognitive complexity; extract deep ternaries (>3 levels) and break down complex logic

Files:

  • __tests__/services/6529api.test.ts
__tests__/**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (tests/AGENTS.md)

__tests__/**/*.{ts,tsx,js}: Prefer for...of loops over forEach as it allows break/continue and works with async/await
Use array.at(-1) and array.at(-2) instead of index-based array access for negative indexing
Use String.prototype.replaceAll() instead of replace() for global string replacements
Use globalThis.fetch() instead of direct fetch() calls
Organize imports with one import per module in order: external → internal → types, with no duplicates
Use element.remove() instead of parent.removeChild(element) for DOM manipulation
Catch errors only when meaningful; no empty catch blocks; log errors with context
Avoid double negatives in code; prefer explicit logic and remove redundant annotations; use optional chaining (?.)

Files:

  • __tests__/services/6529api.test.ts
app/api/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (app/api/AGENTS.md)

app/api/**/*.{ts,tsx,js,jsx}: Never call fetch directly with user-controlled or scraped URLs. Use helpers from @/lib/security/urlGuard (parsePublicUrl, assertPublicUrl, fetchPublicUrl, fetchPublicJson) to validate URLs against host/IP allowlists and DNS checks before making network requests.
When needing custom headers or timeouts for external requests, pass them via @/lib/security/urlGuard helper options rather than re-implementing your own wrapper.
Catch UrlGuardError explicitly if returning a tailored response; otherwise let it bubble so the caller can surface the correct status code.
Follow the project default responses (NextResponse.json) and reuse existing util modules instead of duplicating logic.

Files:

  • app/api/alchemy/token-metadata/route.ts
app/api/**/route.ts

📄 CodeRabbit inference engine (app/api/AGENTS.md)

app/api/**/route.ts: Export HTTP verb handlers (e.g. GET, POST, etc.) from route.ts files, keeping logic in small internal functions when it grows beyond ~200 lines.
For edge caching behavior, prefer export const dynamic = "force-dynamic"; or revalidate constants rather than inline headers.

Files:

  • app/api/alchemy/token-metadata/route.ts
app/api/**/*.{ts,tsx}

📄 CodeRabbit inference engine (app/api/AGENTS.md)

Use TypeScript types for request parameters and responses; avoid any unless a 3rd-party payload truly has no shape guarantees.

Files:

  • app/api/alchemy/token-metadata/route.ts
app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Routes in app/ should export generateMetadata using the helper getAppMetadata with a title property

All production routes must live under the App Router (app/) directory

Files:

  • app/api/alchemy/token-metadata/route.ts
🧠 Learnings (12)
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/*.{ts,tsx,js} : Use `globalThis.fetch()` instead of direct `fetch()` calls

Applied to files:

  • __tests__/services/6529api.test.ts
  • app/api/alchemy/token-metadata/route.ts
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.test.{ts,tsx} : Mock external dependencies and APIs in tests

Applied to files:

  • __tests__/services/6529api.test.ts
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Applies to **/@(__tests__|*.test).{ts,tsx} : Tests should live in `__tests__/` or `ComponentName.test.tsx`; mock external dependencies and APIs in tests

Applied to files:

  • __tests__/services/6529api.test.ts
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/*.{ts,tsx,js} : Avoid double negatives in code; prefer explicit logic and remove redundant annotations; use optional chaining (`?.`)

Applied to files:

  • __tests__/services/6529api.test.ts
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/__tests__/**/*.test.{ts,tsx,js} : Keep tests independent, deterministic, and fast with production-like data

Applied to files:

  • __tests__/services/6529api.test.ts
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/app/api/**/__tests__/**/*.test.{ts,tsx,js} : API integration tests should be located in `app/api`

Applied to files:

  • __tests__/services/6529api.test.ts
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/__tests__/**/*.test.{ts,tsx,js} : Test high-risk areas including happy path workflows, invalid input errors, edge cases/boundaries, component & API interactions, and performance/security when relevant

Applied to files:

  • __tests__/services/6529api.test.ts
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/*.{ts,tsx,js} : Organize imports with one import per module in order: external → internal → types, with no duplicates

Applied to files:

  • __tests__/services/6529api.test.ts
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/__tests__/**/*.test.{ts,tsx,js} : Write tests following Arrange – Act – Assert pattern with one behaviour per test and clear, descriptive names

Applied to files:

  • __tests__/services/6529api.test.ts
📚 Learning: 2025-11-25T08:37:44.688Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: app/api/AGENTS.md:0-0
Timestamp: 2025-11-25T08:37:44.688Z
Learning: Applies to app/api/**/*.{ts,tsx,js,jsx} : When needing custom headers or timeouts for external requests, pass them via `@/lib/security/urlGuard` helper options rather than re-implementing your own wrapper.

Applied to files:

  • __tests__/services/6529api.test.ts
  • app/api/alchemy/token-metadata/route.ts
📚 Learning: 2025-11-25T08:37:44.688Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: app/api/AGENTS.md:0-0
Timestamp: 2025-11-25T08:37:44.688Z
Learning: Applies to app/api/**/*.{ts,tsx,js,jsx} : Never call `fetch` directly with user-controlled or scraped URLs. Use helpers from `@/lib/security/urlGuard` (`parsePublicUrl`, `assertPublicUrl`, `fetchPublicUrl`, `fetchPublicJson`) to validate URLs against host/IP allowlists and DNS checks before making network requests.

Applied to files:

  • app/api/alchemy/token-metadata/route.ts
📚 Learning: 2025-11-25T08:37:44.688Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: app/api/AGENTS.md:0-0
Timestamp: 2025-11-25T08:37:44.688Z
Learning: Applies to app/api/**/*.{ts,tsx,js,jsx} : Catch `UrlGuardError` explicitly if returning a tailored response; otherwise let it bubble so the caller can surface the correct status code.

Applied to files:

  • app/api/alchemy/token-metadata/route.ts
🧬 Code graph analysis (2)
__tests__/services/6529api.test.ts (3)
services/auth/auth.utils.ts (1)
  • getStagingAuth (58-60)
services/6529api.ts (4)
  • fetchUrl (26-37)
  • fetchAllPages (39-57)
  • postData (83-100)
  • postFormData (102-115)
constants.ts (1)
  • API_AUTH_COOKIE (38-38)
app/api/alchemy/token-metadata/route.ts (3)
services/alchemy/utils.ts (2)
  • normaliseAddress (153-168)
  • resolveNetwork (22-24)
helpers/Helpers.ts (1)
  • isValidEthAddress (234-235)
lib/security/urlGuard.ts (2)
  • fetchPublicJson (465-481)
  • UrlGuardError (18-28)
⏰ 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). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (10)
app/api/alchemy/token-metadata/route.ts (5)

3-7: LGTM! Imports now use shared utilities as recommended.

The duplicated NETWORK_MAP and resolveNetwork have been removed in favor of importing from @/services/alchemy/utils. The use of fetchPublicJson and UrlGuardError from @/lib/security/urlGuard follows the coding guidelines for API routes.


25-36: Clean validation flow for tokens array.

The function properly leverages normaliseAddress which internally validates with isValidEthAddress and handles checksumming. Invalid tokens are filtered out, and the caller handles the empty result case appropriately.


52-99: Well-structured validation with consistent error handling.

The ParseResult discriminated union pattern cleanly separates success and error cases. Both input paths (tokens array and address + tokenIds) now consistently return 400 errors with descriptive messages when validation fails, addressing the previous inconsistency concern.


125-141: Proper batch processing with timeout protection.

The implementation correctly:

  • Uses fetchPublicJson with a 10-second timeout as recommended
  • Propagates request.signal for cancellation support
  • Handles both tokens and nfts response shapes from the Alchemy API
  • Batches requests according to MAX_BATCH_SIZE

147-160: UrlGuardError handling correctly surfaces status codes.

The UrlGuardError catch block properly extracts and returns the error's statusCode, addressing the previous review comment.

One consideration: the fallback (line 158) returns 400 for all non-UrlGuardError exceptions, which may mask legitimate server-side issues (e.g., Alchemy service unavailable) that would typically warrant a 5xx status. This is a minor point since the current approach avoids exposing internal errors.

__tests__/services/6529api.test.ts (5)

11-13: LGTM!

The helper function correctly extracts headers from the mock using globalThis.fetch as per the coding guidelines.


15-19: LGTM!

The test setup correctly uses globalThis for the fetch mock and properly resets mocks between tests.

Based on learnings, using globalThis.fetch() instead of direct fetch() calls is the correct approach.


34-64: LGTM!

The test correctly validates pagination concatenation and properly includes all Response properties (ok, status, json) in the mocks.


66-81: LGTM!

The test correctly validates JSON POST behavior and properly verifies the Content-Type and auth headers using the helper function.


83-98: LGTM!

The test correctly validates FormData POST behavior and properly verifies the auth token is included in the headers.

@prxt6529 prxt6529 merged commit c924f1b into main Dec 16, 2025
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants