Conversation
Signed-off-by: prxt6529 <prxt@6529.io>
WalkthroughAdds a backend failover path for Alchemy requests, centralizes Alchemy response processing into new utility functions, introduces an exported Changes
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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
filterTokensOwnedForBurnAddressfunction referencesprops.collection_merkleproperties, butprops.collection_merkleis not included in the dependency array. Ifprops.collection_merklechanges whilemintForAddressremains the same, the filtering logic will use stale values.Consider adding
props.collection_merkleto 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, andaddress?.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.
mockPublicEnvat lines 3-7 duplicates the values injest.mockat 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
fetchJsonfunction throws on!response.okbefore callingresponse.json(). The mock'sjson()returning{ error: "ALCHEMY_API_KEY..." }is never executed. This test effectively duplicates the "non-ok response" test at lines 55-81.Consider either:
- Rename to clarify it's just another non-ok response case
- Remove as duplicate coverage
- If testing specific error parsing is needed, modify
fetchJsonto read and include error details
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 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 />fromnext/imageto satisfy@next/next/no-img-elementESLint rule
Use<Link href="/path">from Next.js for internal navigation instead of plain HTML links to satisfy@next/next/no-html-link-for-pagesESLint rule
Files:
components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsxhooks/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 addreadonlybefore 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 usenext/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.tsxhooks/useAlchemyNftQueries.ts__tests__/hooks/useAlchemyNftQueries.test.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Must passtsc --noEmittype checking
Prefer direct named imports for React hooks and types (import { useMemo, useRef, FC, etc. } from "react") overReact.namespace usage (React.useMemo,React.useRef, etc.)
If thereact-hooks/exhaustive-depslint 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 inuseEffectEvent
**/*.{ts,tsx}: Must passtsc --noEmitfor 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
UseuseEffectEventfor non-reactive logic inside Effects to avoid unnecessary re-runs
Use framework APIs:<Link>for internal links,next/imagefor 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 />fromnext/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.tsxhooks/useAlchemyNftQueries.ts__tests__/hooks/useAlchemyNftQueries.test.ts
**/@(__tests__|*.test).{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Tests should live in
__tests__/orComponentName.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 asComponentName.test.tsxalongside 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-jestfor 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}: Preferfor...ofloops overforEachas it allowsbreak/continueand works with async/await
Usearray.at(-1)andarray.at(-2)instead of index-based array access for negative indexing
UseString.prototype.replaceAll()instead ofreplace()for global string replacements
UseglobalThis.fetch()instead of directfetch()calls
Organize imports with one import per module in order: external → internal → types, with no duplicates
Useelement.remove()instead ofparent.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
fetchOwnerNftswith correct parameters and maintains proper abort handling. The error handling correctly checkscontroller.signal.abortedbefore 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
BigIntconversion for token IDs.
There was a problem hiding this comment.
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
imageproperty 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
📒 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 />fromnext/imageto satisfy@next/next/no-img-elementESLint rule
Use<Link href="/path">from Next.js for internal navigation instead of plain HTML links to satisfy@next/next/no-html-link-for-pagesESLint 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 usenext/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 passtsc --noEmittype checking
Prefer direct named imports for React hooks and types (import { useMemo, useRef, FC, etc. } from "react") overReact.namespace usage (React.useMemo,React.useRef, etc.)
If thereact-hooks/exhaustive-depslint 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 inuseEffectEvent
**/*.{ts,tsx}: Must passtsc --noEmitfor 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
UseuseEffectEventfor non-reactive logic inside Effects to avoid unnecessary re-runs
Use framework APIs:<Link>for internal links,next/imagefor 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 />fromnext/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
There was a problem hiding this comment.
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 dependencyfilterTokensOwnedForBurnAddressin useEffect.The
filterTokensOwnedForBurnAddressfunction is called inside the effect but capturesprops.collection_merklefrom the outer scope. Ifcollection_merklechanges withoutmintForAddresschanging, 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
filterTokensOwnedForBurnAddressto acceptcollection_merkleas 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_MAPandresolveNetworklogic to a common utility module.
🧹 Nitpick comments (9)
helpers/alchemy/response-processing.ts (2)
369-379: Consider returningtitlein addition tonamefor consistency.The
AlchemyTokenMetadataEntrytype includes bothtitleandnamefields, andnormaliseTokenMetadata(line 403-408) usestitleas the primary source. However,processOwnerNftsResponseonly mapsname. If Alchemy returnstitlewithoutnamefor owned NFTs, the name would incorrectly benull.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.
parseTokenIdToBigintthrows whentokenIdis empty (line 382-384), but an empty string aftertrim()would still reachBigInt("")which throws aSyntaxError. 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: Addreadonlybefore Props interface properties.Per coding guidelines, always add
readonlybefore 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_MAPandresolveNetworkpattern is duplicated acrosscontract/route.ts,collections/route.ts, andowner-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_checksummay mask upstream issues.If the API response doesn't include
_checksum, the code falls back to the locally computedchecksum, which is fine. However, castingpayload._checksumdirectly to`0x${string}`without validation could be problematic if the API returns a malformed value.Consider using
normaliseAddresson 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
📒 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 />fromnext/imageto satisfy@next/next/no-img-elementESLint rule
Use<Link href="/path">from Next.js for internal navigation instead of plain HTML links to satisfy@next/next/no-html-link-for-pagesESLint rule
Files:
app/api/alchemy/owner-nfts/route.tscomponents/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsxapp/api/alchemy/collections/route.tshooks/useAlchemyNftQueries.tsapp/api/alchemy/token-metadata/route.tshelpers/alchemy/response-processing.tsapp/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 callfetchdirectly 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/urlGuardhelper options rather than re-implementing your own wrapper.
CatchUrlGuardErrorexplicitly 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.tsapp/api/alchemy/collections/route.tsapp/api/alchemy/token-metadata/route.tsapp/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.) fromroute.tsfiles, keeping logic in small internal functions when it grows beyond ~200 lines.
For edge caching behavior, preferexport const dynamic = "force-dynamic";orrevalidateconstants rather than inline headers.
Files:
app/api/alchemy/owner-nfts/route.tsapp/api/alchemy/collections/route.tsapp/api/alchemy/token-metadata/route.tsapp/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
anyunless a 3rd-party payload truly has no shape guarantees.
Files:
app/api/alchemy/owner-nfts/route.tsapp/api/alchemy/collections/route.tsapp/api/alchemy/token-metadata/route.tsapp/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 usenext/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.tscomponents/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsxapp/api/alchemy/collections/route.tshooks/useAlchemyNftQueries.tsapp/api/alchemy/token-metadata/route.tshelpers/alchemy/response-processing.tsapp/api/alchemy/contract/route.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Must passtsc --noEmittype checking
Prefer direct named imports for React hooks and types (import { useMemo, useRef, FC, etc. } from "react") overReact.namespace usage (React.useMemo,React.useRef, etc.)
If thereact-hooks/exhaustive-depslint 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 inuseEffectEvent
**/*.{ts,tsx}: Must passtsc --noEmitfor 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
UseuseEffectEventfor non-reactive logic inside Effects to avoid unnecessary re-runs
Use framework APIs:<Link>for internal links,next/imagefor 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 />fromnext/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.tscomponents/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsxapp/api/alchemy/collections/route.tshooks/useAlchemyNftQueries.tsapp/api/alchemy/token-metadata/route.tshelpers/alchemy/response-processing.tsapp/api/alchemy/contract/route.ts
app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Routes in
app/should exportgenerateMetadatausing the helpergetAppMetadatawith a title propertyAll production routes must live under the App Router (
app/) directory
Files:
app/api/alchemy/owner-nfts/route.tsapp/api/alchemy/collections/route.tsapp/api/alchemy/token-metadata/route.tsapp/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 addreadonlybefore 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.tshooks/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.tsxhooks/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 onAlchemyNftMetadata(line 79) appropriately allows for unknown additional properties.
127-141: Verify the fallback behavior whengetAddressthrows.The catch block on line 138-139 returns the address cast as
0x${string}even thoughgetAddressfrom viem threw. SinceisValidEthAddressalready 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
pickImageandpickThumbnailfunctions correctly handle multiple potential sources with appropriate null checks.
255-298: LGTM! Contract extraction handles metadata from multiple sources correctly.The
extractContractfunction 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.mintForAddressnot in deps.This effect calls
props.mintForAddress(mintForAddress)but only depends onmintForAddress. Ifprops.mintForAddresscallback 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 typedfetchOwnerNftshelper.The component now uses the centralized
fetchOwnerNftshelper with proper abort signal handling and typedOwnerNft[]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
nullwith 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
URLclass withsearchParamsensures 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
getBackendAlchemyProxyUrlcorrectly constructs the proxy URL usingpublicEnv.API_ENDPOINT. TheisAbortErrorhelper properly handles bothDOMExceptionand genericErrorwithAbortErrorname, covering browser variations.
73-90: Failover logic now correctly handles abort errors.The implementation properly re-throws
AbortErrorto 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. Theinitobject correctly propagates the signal for abort handling.
434-453: NewfetchOwnerNftsexport is well-structured.The function correctly uses
fetchJsonWithFailoverwith proper query string construction and signal propagation. The response processing viaprocessOwnerNftsResponsehandles theownedNftsarray with a fallback to empty array.app/api/alchemy/token-metadata/route.ts (1)
11-17: No changes needed.SupportedChainis a string literal type with only"ethereum"as its single possible value, soNETWORK_MAPcorrectly 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.
There was a problem hiding this comment.
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
tokenTypewill 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
📒 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 />fromnext/imageto satisfy@next/next/no-img-elementESLint rule
Use<Link href="/path">from Next.js for internal navigation instead of plain HTML links to satisfy@next/next/no-html-link-for-pagesESLint 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 usenext/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 passtsc --noEmittype checking
Prefer direct named imports for React hooks and types (import { useMemo, useRef, FC, etc. } from "react") overReact.namespace usage (React.useMemo,React.useRef, etc.)
If thereact-hooks/exhaustive-depslint 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 inuseEffectEvent
**/*.{ts,tsx}: Must passtsc --noEmitfor 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
UseuseEffectEventfor non-reactive logic inside Effects to avoid unnecessary re-runs
Use framework APIs:<Link>for internal links,next/imagefor 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 />fromnext/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
toSafelistandparseFloorPricedemonstrate 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
extractContracthelper for consistency. The null handling is correct.
265-283: LGTM: Straightforward owner NFT processing.The
OwnerNfttype 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:
parseTokenIdToBigintthrows on invalid input,normaliseTokenMetadatacatches and returns null, andprocessTokenMetadataResponsefilters out failures. This ensures malformed token data doesn't break the entire batch.
There was a problem hiding this comment.
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
fetchfails 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
queryKeyarray contains duplicate entries:QueryKey.NFT_TOKEN_METADATA,chain, andaddress?.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 importingresolveNetworkfrom@/services/alchemy/utils.This
NETWORK_MAPandresolveNetworkfunction duplicate the implementation inservices/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
filterTokensOwnedForBurnAddressfunction referencesprops.collection_merkleproperties, but the useEffect dependency array only includes[account.address, mintForAddress]. Ifcollection_merklechanges, the filter will use stale values.Consider either:
- Adding
props.collection_merkleto the dependency array- Moving the filter logic inline within the useEffect
- Using
useCallbackforfilterTokensOwnedForBurnAddresswith proper dependenciesuseEffect(() => { 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.mintForAddressbut 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
normaliseAddressreturns null for theaddress + tokenIdspath, the code returns an emptytokensarray (line 63). However, for thetokensarray 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
📒 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 />fromnext/imageto satisfy@next/next/no-img-elementESLint rule
Use<Link href="/path">from Next.js for internal navigation instead of plain HTML links to satisfy@next/next/no-html-link-for-pagesESLint rule
Files:
jest.setup.jsapp/api/alchemy/token-metadata/route.tsservices/alchemy/tokens.tsservices/alchemy/utils.tsservices/alchemy/owner-nfts.tsservices/alchemy/collections.ts__tests__/services/alchemy-api.test.tshooks/useAlchemyNftQueries.tscomponents/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsxservices/alchemy/types.tsapp/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 usenext/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.jsapp/api/alchemy/token-metadata/route.tsservices/alchemy/tokens.tsservices/alchemy/utils.tsservices/alchemy/owner-nfts.tsservices/alchemy/collections.ts__tests__/services/alchemy-api.test.tshooks/useAlchemyNftQueries.tscomponents/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsxservices/alchemy/types.tsapp/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 callfetchdirectly 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/urlGuardhelper options rather than re-implementing your own wrapper.
CatchUrlGuardErrorexplicitly 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.tsapp/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.) fromroute.tsfiles, keeping logic in small internal functions when it grows beyond ~200 lines.
For edge caching behavior, preferexport const dynamic = "force-dynamic";orrevalidateconstants rather than inline headers.
Files:
app/api/alchemy/token-metadata/route.tsapp/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
anyunless a 3rd-party payload truly has no shape guarantees.
Files:
app/api/alchemy/token-metadata/route.tsapp/api/alchemy/contract/route.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Must passtsc --noEmittype checking
Prefer direct named imports for React hooks and types (import { useMemo, useRef, FC, etc. } from "react") overReact.namespace usage (React.useMemo,React.useRef, etc.)
If thereact-hooks/exhaustive-depslint 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 inuseEffectEvent
**/*.{ts,tsx}: Must passtsc --noEmitfor 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
UseuseEffectEventfor non-reactive logic inside Effects to avoid unnecessary re-runs
Use framework APIs:<Link>for internal links,next/imagefor 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 />fromnext/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.tsservices/alchemy/tokens.tsservices/alchemy/utils.tsservices/alchemy/owner-nfts.tsservices/alchemy/collections.ts__tests__/services/alchemy-api.test.tshooks/useAlchemyNftQueries.tscomponents/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsxservices/alchemy/types.tsapp/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 exportgenerateMetadatausing the helpergetAppMetadatawith a title propertyAll production routes must live under the App Router (
app/) directory
Files:
app/api/alchemy/token-metadata/route.tsapp/api/alchemy/contract/route.ts
**/@(__tests__|*.test).{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Tests should live in
__tests__/orComponentName.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 asComponentName.test.tsxalongside 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-jestfor 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}: Preferfor...ofloops overforEachas it allowsbreak/continueand works with async/await
Usearray.at(-1)andarray.at(-2)instead of index-based array access for negative indexing
UseString.prototype.replaceAll()instead ofreplace()for global string replacements
UseglobalThis.fetch()instead of directfetch()calls
Organize imports with one import per module in order: external → internal → types, with no duplicates
Useelement.remove()instead ofparent.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 addreadonlybefore 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.jscomponents/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 nodedirective is appropriate for testing server-side Alchemy API code, and the mock for@/config/alchemyEnvproperly 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 withurlGuardcoding guidelines for external API calls.Per the coding guidelines for
app/api/**/*.{ts,tsx,js,jsx}, external fetches should use helpers from@/lib/security/urlGuardto validate URLs. While the Alchemy URL is constructed from a trusted template and config, please verify ifurlGuardhelpers 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
./utilsmodule, 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 undefinedwindowproperties.
106-111: LGTM!Minor formatting improvements to the ResizeObserver mock methods.
services/alchemy/collections.ts (3)
49-50: LGTM!Clean delegation to
processSearchResponsewith proper passing of thehideSpamparameter. 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
chainandhideSpam.services/alchemy/types.ts (3)
1-1: LGTM!Import consolidation to a single line is cleaner.
122-149: LGTM!The
contracttype extension withspamClassificationsaligns withAlchemyContractResultdefinition at line 65, maintaining consistency across type definitions.
160-167: LGTM!The
OwnerNfttype is well-structured with a requiredtokenIdand 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
createMintStatehelper is expanded to include all fields from the actualuseMintSharedStatehook, providing a complete mock state for tests.
86-136: LGTM!The
basePropsandrenderWidgethelper are well-structured. Themerkle_rootchanged from a number to string aligns with typical merkle root representations, and the addedstatusfield enables burn-state testing.
148-181: LGTM!Test data structure updated to wrap NFTs in
ownedNftsobject, matching theAlchemyGetNftsForOwnerResponsetype. 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 whenisMintingis true. TheSpinnercomponent 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
isAbortErrorhelper correctly handles bothDOMExceptionand genericErrorwithAbortErrorname, ensuring compatibility across different environments.
73-90: LGTM!The failover implementation correctly re-throws
AbortErrorto prevent unintended fallback requests when a request is intentionally cancelled. This addresses the concern from the previous review.
100-116: LGTM!The
fetchCollectionsFromApifunction properly constructs query strings and delegates tofetchJsonWithFailoverwith appropriate primary and fallback paths.
118-148: LGTM!The
fetchContractOverviewFromApifunction properly validates the address withnormaliseAddressbefore making the request, and correctly extracts the checksum from the response or uses the validated one.
150-173: LGTM!The
fetchTokenMetadataFromApifunction correctly uses POST method with JSON body for batch token metadata requests, aligning with API expectations.
434-453: LGTM!The
fetchOwnerNftsfunction is well-implemented with proper query string construction and failover support. The?? []fallback forownedNftsensures safe handling of missing data.components/nextGen/collections/collectionParts/mint/NextGenMintBurnWidget.tsx (2)
3-34: LGTM!Import reorganization is clean, bringing in the new
fetchOwnerNftshelper andOwnerNfttype 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 withNumber(t.tokenId)for range comparison andstartsWithfor 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
processSearchResponsefunction cleanly separates concerns: extraction, spam filtering, and result shaping. The hidden count logic correctly tracks filtered spam items.
238-268: LGTM!The
processContractMetadataResponsefunction properly resolves OpenSea metadata from multiple sources and delegates toextractContractfor consistent suggestion creation.
270-278: LGTM!The
processOwnerNftsResponsefunction provides clean mapping fromAlchemyOwnedNfttoOwnerNftwith appropriate defaults for missing fields.
280-317: LGTM!The
parseTokenIdToBigintandnormaliseTokenMetadatafunctions 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
processTokenMetadataResponsefunction correctly handles bothtokensandnftsresponse 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
OwnerNfttype andprocessOwnerNftsResponseutility, enabling consistent response processing.
17-57: LGTM!The
createAbortErroranddelayWithAborthelpers are well-implemented:
createAbortErrorhandles both modern DOMException and legacy Error environmentsdelayWithAbortproperly cleans up event listeners in both completion and abort paths, preventing memory leaks
67-122: LGTM!The
getNftsForContractAndOwnerfunction 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
processOwnerNftsResponsefor result transformationNote: 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 inuseAlchemyNftQueries.tsexplicitly expectsAlchemyTokenMetadataResponse(the raw format) and applies normalization throughprocessTokenMetadataResponse()after receiving it. This design pattern is consistent with other Alchemy integrations in the codebase.Likely an incorrect or invalid review comment.
There was a problem hiding this comment.
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, andfetchAllPagesexplicitly 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
📒 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 />fromnext/imageto satisfy@next/next/no-img-elementESLint rule
Use<Link href="/path">from Next.js for internal navigation instead of plain HTML links to satisfy@next/next/no-html-link-for-pagesESLint rule
Files:
__tests__/components/header/HeaderSearchModalItem.test.tsx__tests__/services/6529api.test.tsservices/6529api.tsapp/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 addreadonlybefore 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 usenext/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.tsservices/6529api.tsapp/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 passtsc --noEmittype checking
Prefer direct named imports for React hooks and types (import { useMemo, useRef, FC, etc. } from "react") overReact.namespace usage (React.useMemo,React.useRef, etc.)
If thereact-hooks/exhaustive-depslint 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 inuseEffectEvent
**/*.{ts,tsx}: Must passtsc --noEmitfor 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
UseuseEffectEventfor non-reactive logic inside Effects to avoid unnecessary re-runs
Use framework APIs:<Link>for internal links,next/imagefor 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 />fromnext/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.tsservices/6529api.tsapp/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__/orComponentName.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 asComponentName.test.tsxalongside 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-jestfor 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}: Preferfor...ofloops overforEachas it allowsbreak/continueand works with async/await
Usearray.at(-1)andarray.at(-2)instead of index-based array access for negative indexing
UseString.prototype.replaceAll()instead ofreplace()for global string replacements
UseglobalThis.fetch()instead of directfetch()calls
Organize imports with one import per module in order: external → internal → types, with no duplicates
Useelement.remove()instead ofparent.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 callfetchdirectly 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/urlGuardhelper options rather than re-implementing your own wrapper.
CatchUrlGuardErrorexplicitly 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.) fromroute.tsfiles, keeping logic in small internal functions when it grows beyond ~200 lines.
For edge caching behavior, preferexport const dynamic = "force-dynamic";orrevalidateconstants 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
anyunless 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 exportgenerateMetadatausing the helpergetAppMetadatawith a title propertyAll 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.tsservices/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
useParamshook, 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
formatStatFloorhelper. 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
resolveNetworkfrom 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
getHeadershelper function and more explicit mock response shapes improves test clarity and maintainability. The functional behavior is preserved while making assertions more readable.
Signed-off-by: prxt6529 <prxt@6529.io>
|
There was a problem hiding this comment.
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, thenormaliseAddresscall cannot returnnullbecause it only returnsnullwhen the address is falsy or failsisValidEthAddress. 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-cookieimport 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: Addok: falseto the 401 mock response.The mock Response object should include
ok: falseto 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
📒 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 />fromnext/imageto satisfy@next/next/no-img-elementESLint rule
Use<Link href="/path">from Next.js for internal navigation instead of plain HTML links to satisfy@next/next/no-html-link-for-pagesESLint rule
Files:
__tests__/services/6529api.test.tsapp/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 usenext/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.tsapp/api/alchemy/token-metadata/route.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Must passtsc --noEmittype checking
Prefer direct named imports for React hooks and types (import { useMemo, useRef, FC, etc. } from "react") overReact.namespace usage (React.useMemo,React.useRef, etc.)
If thereact-hooks/exhaustive-depslint 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 inuseEffectEvent
**/*.{ts,tsx}: Must passtsc --noEmitfor 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
UseuseEffectEventfor non-reactive logic inside Effects to avoid unnecessary re-runs
Use framework APIs:<Link>for internal links,next/imagefor 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 />fromnext/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.tsapp/api/alchemy/token-metadata/route.ts
**/@(__tests__|*.test).{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Tests should live in
__tests__/orComponentName.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 asComponentName.test.tsxalongside 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-jestfor 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}: Preferfor...ofloops overforEachas it allowsbreak/continueand works with async/await
Usearray.at(-1)andarray.at(-2)instead of index-based array access for negative indexing
UseString.prototype.replaceAll()instead ofreplace()for global string replacements
UseglobalThis.fetch()instead of directfetch()calls
Organize imports with one import per module in order: external → internal → types, with no duplicates
Useelement.remove()instead ofparent.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 callfetchdirectly 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/urlGuardhelper options rather than re-implementing your own wrapper.
CatchUrlGuardErrorexplicitly 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.) fromroute.tsfiles, keeping logic in small internal functions when it grows beyond ~200 lines.
For edge caching behavior, preferexport const dynamic = "force-dynamic";orrevalidateconstants 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
anyunless 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 exportgenerateMetadatausing the helpergetAppMetadatawith a title propertyAll 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.tsapp/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.tsapp/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_MAPandresolveNetworkhave been removed in favor of importing from@/services/alchemy/utils. The use offetchPublicJsonandUrlGuardErrorfrom@/lib/security/urlGuardfollows the coding guidelines for API routes.
25-36: Clean validation flow for tokens array.The function properly leverages
normaliseAddresswhich internally validates withisValidEthAddressand 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
ParseResultdiscriminated union pattern cleanly separates success and error cases. Both input paths (tokensarray andaddress + 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
fetchPublicJsonwith a 10-second timeout as recommended- Propagates
request.signalfor cancellation support- Handles both
tokensandnftsresponse shapes from the Alchemy API- Batches requests according to
MAX_BATCH_SIZE
147-160: UrlGuardError handling correctly surfaces status codes.The
UrlGuardErrorcatch block properly extracts and returns the error'sstatusCode, addressing the previous review comment.One consideration: the fallback (line 158) returns
400for all non-UrlGuardErrorexceptions, which may mask legitimate server-side issues (e.g., Alchemy service unavailable) that would typically warrant a5xxstatus. 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.fetchas per the coding guidelines.
15-19: LGTM!The test setup correctly uses
globalThisfor the fetch mock and properly resets mocks between tests.Based on learnings, using
globalThis.fetch()instead of directfetch()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.



Summary by CodeRabbit
New Features
Bug Fixes
Tests
✏️ Tip: You can customize this high-level summary in your review settings.