Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughReplaces token-centric APIs/providers/hooks with a Moment-based model: introduces Moment types and MomentProvider, replaces getTokenInfo with getMomentOnChainInfo/getMomentAdvancedInfo, updates API routes, libs, hooks, components, and DB selectors to accept/consume a single Moment ({ collectionAddress, tokenId, chainId }). Changes
Sequence Diagram(s)mermaid Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 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: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
components/CreatedMoment/CreatedMomentAirdrop.tsx (1)
7-22: Fix MomentProvider props: pass a moment object instead of token/chainId
CreatedMomentAirdropnow wrapsMomentAirdropwithMomentProvider, but it still passestokenandchainIdprops:<MomentProvider token={{ tokenContractAddress: createdContract as Address, tokenId: createdTokenId }} chainId={CHAIN_ID} >The
MomentProviderimplementation expects amomentprop (e.g.,{ collectionAddress, tokenId, chainId }), so this will fail type‑checking and the context won’t receive the intended data.You likely want to construct a
Momentobject here:- <MomentProvider - token={{ tokenContractAddress: createdContract as Address, tokenId: createdTokenId }} - chainId={CHAIN_ID} - > + <MomentProvider + moment={{ + collectionAddress: createdContract as Address, + tokenId: createdTokenId, + chainId: CHAIN_ID, + }} + > <MomentAirdrop /> - </MomentProvider> + </MomentProvider>Adjust the property names if your
Momenttype uses a different field name for the address, but the key point is to pass a singlemomentobject matchingMomentProvider’s expected props.lib/moment/getMomentApi.ts (1)
1-10: Bug: JSON.stringify(moment) passed directly into URLSearchParams will not build the intended query
URLSearchParamsexpects a query string like"a=1&b=2"or a key/value object. Passing a raw JSON string:const params = new URLSearchParams(JSON.stringify(moment));produces a single, essentially meaningless query key/value (e.g.
{"collectionAddress":"...","tokenId":"1","chainId":8453}) rather than proper parameters. The/api/momentroute will almost certainly not receive the fields it expects.You likely want either:
- Top‑level query params for each Moment field, or
- A single
momentparam containing the JSON string.For top‑level params (closest to traditional usage):
-import { Moment } from "@/types/moment"; - -export const getMomentApi = async (moment: Moment) => { - const params = new URLSearchParams(JSON.stringify(moment)); +import { Moment } from "@/types/moment"; + +export const getMomentApi = async (moment: Moment) => { + const params = new URLSearchParams({ + collectionAddress: moment.collectionAddress, + tokenId: moment.tokenId, + chainId: String(moment.chainId), + }); const res = await fetch(`/api/moment?${params.toString()}`);If the API route instead expects a single
momentparam, adjust to:const params = new URLSearchParams({ moment: JSON.stringify(moment), });Either way, avoid passing
JSON.stringify(moment)directly toURLSearchParamsas it currently breaks the request.hooks/useMomentCollect.ts (1)
41-45: Add null check formomentbefore accessing its properties.The function checks
saleConfigandartistWalletbut notmoment. Ifmomentis undefined, accessingmoment.collectionAddresson line 53 will throw.const collectWithComment = async () => { try { if (!saleConfig) return; if (!artistWallet) return; + if (!moment) return; setIsLoading(true);app/api/moment/route.ts (1)
74-86: Add validation formomentdata.ownerbefore callinggetAddress.If
momentdata.owneris empty or invalid,getAddress()will throw, resulting in a generic 500 error. Consider adding explicit validation.+ if (!momentdata.owner) { + return NextResponse.json({ error: "Owner not found" }, { status: 404 }); + } + return NextResponse.json({ uri: momentdata.tokenUri, owner: getAddress(momentdata.owner),
🧹 Nitpick comments (15)
lib/schema/getMomentSchema.ts (1)
3-15: Consider normalizing chainId type across schemasHere
chainIdis modeled as a string (withdefault(CHAIN_ID.toString())), whilecollectSchemauses a numericchainId. If both represent the same concept, it may be worth normalizing to a single type (e.g., always a number in internal code and only treating it as a string at the HTTP/query boundary) to avoid repeated conversions and subtle mismatches.hooks/useComments.ts (1)
6-27: useMomentProvider integration is fine; consider future naming alignmentSwapping to
useMomentProviderwhile still consumingtoken.tokenContractAddress,tokenId, andchainIdkeeps the existing query behavior intact, assuming the Moment context continues to expose atokenobject with that shape.Longer term, as the rest of the codebase moves toward
collectionAddress/moment‑centric naming, it may be worth aligning the comments fetch payload and query key parameters with that terminology to reduce confusion between “token” vs “moment” shapes.hooks/useShareMoment.ts (1)
3-13: Share hook’s switch to useMomentProvider preserves behaviorUsing
useMomentProviderto accesstokenkeeps the share URL logic unchanged and should work as before if the context still exposestokenContractAddress/tokenId. If you eventually phase out the token-centric view in favor of a puremomentshape, this is a good candidate to update to read frommoment.collectionAddress(or equivalent) at the same time.components/TokenPage/Token.tsx (1)
3-16: MomentProvider integration preserves Token layout behaviorReading
metadataandisOwnerfromuseMomentProviderslots into the existing render logic (metadata gate and owner-gated airdrop) without changing semantics. You may eventually want to align the component name with the “Moment” terminology, but that’s not required for this PR.types/moment.ts (1)
5-8: Align moment-related type naming and tighten typingsThe updated
Momentinterface withcollectionAddressandchainIdlooks good, but:
CommentsQueryParams.contractAddressnow diverges in naming fromMoment.collectionAddress, which can be confusing when wiring API/query layers.GetInProcessMomentsRpcResponse.moments: any[]andSaleConfig.type: stringare loosely typed and go against the “strict TypeScript, zeroany” guideline.Consider (when feasible) renaming
contractAddresstocollectionAddress(or documenting the distinction) and replacingany[]/plainstringwith concrete types (e.g.,Moment[]or a dedicated DTO type and a string union forSaleConfig.type).Also applies to: 15-20, 45-60
hooks/useBalanceOf.ts (1)
2-26: Verifytokenshape fromuseMomentProvidermatches balanceOf expectations
useBalanceOfnow pulls{ token }fromuseMomentProviderbut still callsreadContractwithtoken.tokenContractAddressandtoken.tokenId. Given the broader shift toward aMomentshape withcollectionAddress/chainId, this is a potential mismatch:
- If
tokenis now aMoment, this should likely usetoken.collectionAddress(and ensuretokenIdis still the correct field).- If
tokenintentionally remains a separate “token” object withtokenContractAddress, the naming and typing aroundMomentProvidervstokenmay be confusing.Please confirm the actual context type and adjust either the field names or the typings to keep this consistent with the new Moment model.
lib/viem/getTokenInfo.ts (1)
12-64: Moment-based getMomentOnChainInfo looks correct; consider tightening client typingThe refactor to
getMomentOnChainInfo(moment: Moment)cleanly switches all internal calls tocollectionAddress,tokenId, andchainIdand preserves the returned shape{ saleConfig, tokenUri, owner }, so existing consumers should continue to work as long as they pass a numericchainId.One improvement to align with your strict typing guidelines: avoid
publicClient: anyand instead type it using the return type ofgetPublicClient:const publicClient = getPublicClient(chainId); // or const publicClient: ReturnType<typeof getPublicClient> = getPublicClient(chainId);This keeps the API change focused while eliminating an explicit
any.providers/MomentProvider.tsx (1)
1-34: MomentProvider / useMomentProvider are well-structured; ESLint disable appears staleThe new
MomentProvideranduseMomentProvidercorrectly wrapuseMoment(moment)and expose both the rawmomentand derived data via context, with a good safety check in the hook.The
// eslint-disable-next-line @typescript-eslint/no-explicit-anyabovecreateContextno longer seems necessary, since the generic type doesn’t useany. You can safely remove it to keep the lint rule effective for future edits in this file.hooks/useUpdateMomentURI.ts (1)
2-88: Hook correctly migrated to MomentProvider; consider moving the context guard earlierThe hook now consistently uses
useMomentProviderandgetMomentOnChainInfo(moment), and passesmoment.collectionAddress/moment.tokenIdthrough tocallUpdateMomentURIandmigrateMuxToArweaveApi, which aligns with the new moment-centric model.One minor robustness tweak: you currently call
const tokenInfo = await getMomentOnChainInfo(moment);before checking:
if (!moment?.collectionAddress || !moment?.tokenId) { throw new Error("Missing token context"); }If
momentwere ever missing or incomplete, the earlier on-chain call would throw with a less clear error. Consider moving the “Missing token context” check above thegetMomentOnChainInfocall so the failure mode is deterministic and explicit.Functionally the change looks good given a valid Moment context.
hooks/useMoment.ts (1)
49-49: RenamefetchTokenInfoto align with the new naming convention.The hook and API have been renamed to use "Moment" terminology, but this returned property still uses "TokenInfo".
- fetchTokenInfo: query.refetch, + fetchMoment: query.refetch,hooks/useMomentCollect.ts (3)
14-14: Replaceanywith a proper type forparameters.The coding guidelines require strict TypeScript with zero
any. Consider typing this parameter properly.-const mintOnSmartWallet = async (parameters: any) => { +interface MintParameters { + address: Address; + abi: typeof zoraCreator1155ImplABI; + functionName: string; + args: unknown[]; +} + +const mintOnSmartWallet = async (parameters: MintParameters) => {
72-76: Avoidas anycast; type the comment object properly.Per coding guidelines, avoid
anytypes. TheaddCommentcall should accept a properly typed object.addComment({ sender: artistWallet as Address, comment, timestamp: new Date().getTime(), - } as any); + });If the type doesn't match, update the
addCommentfunction signature or create a proper type for new comments.
14-29: Consider extractingmintOnSmartWalletto a lib file.Per coding guidelines, hooks should focus on state management, and business logic should go in lib files. Additionally, this file exceeds the 100-line limit. Extracting this utility would improve separation of concerns and reduce file size.
Move to
lib/smartwallet/mintOnSmartWallet.ts:import { Address } from "viem"; import { zoraCreator1155ImplABI } from "@zoralabs/protocol-deployments"; interface MintParameters { address: Address; abi: typeof zoraCreator1155ImplABI; functionName: string; args: unknown[]; } export const mintOnSmartWallet = async (parameters: MintParameters) => { const response = await fetch(`/api/smartwallet/sendUserOperation`, { method: "POST", headers: { "content-type": "application/json", accept: "application/json", }, body: JSON.stringify({ parameters }), }); const data = await response.json(); return data.transactionHash; };app/api/moment/route.ts (2)
3-3: Import path doesn't match the exported function name.The import references
@/lib/viem/getTokenInfobut importsgetMomentOnChainInfo. Consider renaming the file to match the function name for clarity.Either rename the file:
@/lib/viem/getTokenInfo.ts→@/lib/viem/getMomentOnChainInfo.tsOr update the import if the file has been renamed:
-import getMomentOnChainInfo from "@/lib/viem/getTokenInfo"; +import getMomentOnChainInfo from "@/lib/viem/getMomentOnChainInfo";
66-72: Replaceanywith a proper type forsaleConfig.Per coding guidelines, avoid
anytypes. Define an interface for the sale configuration response.+interface SaleConfigResponse { + pricePerToken: string; + saleStart: number; + saleEnd: number; + maxTokensPerAddress: number; + [key: string]: unknown; // for spread properties +} - const saleConfig: any = { + const saleConfig: SaleConfigResponse = { ...momentdata.saleConfig, pricePerToken: pricePerToken.toString(), saleStart: Number(saleStart), saleEnd: Number(saleEnd), maxTokensPerAddress: Number(maxTokensPerAddress), };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (37)
app/api/moment/route.ts(3 hunks)components/CollectionManagePage/TokenOverview.tsx(1 hunks)components/CreatedMoment/CreatedMomentAirdrop.tsx(2 hunks)components/TokenManagePage/AirdropButton.tsx(1 hunks)components/TokenManagePage/AnimationUpload.tsx(1 hunks)components/TokenManagePage/Media.tsx(2 hunks)components/TokenManagePage/OwnerWarning.tsx(1 hunks)components/TokenManagePage/Sale.tsx(1 hunks)components/TokenManagePage/SaveMediaButton.tsx(1 hunks)components/TokenManagePage/TokenManagePage.tsx(3 hunks)components/TokenPage/BackToTimeline.tsx(1 hunks)components/TokenPage/CollectModal.tsx(2 hunks)components/TokenPage/CommentSection.tsx(2 hunks)components/TokenPage/MetaAndComments.tsx(2 hunks)components/TokenPage/Token.tsx(2 hunks)components/TokenPage/TokenPage.tsx(2 hunks)hooks/useAirdrop.ts(1 hunks)hooks/useBalanceOf.ts(1 hunks)hooks/useComments.ts(1 hunks)hooks/useDownload.ts(1 hunks)hooks/useMoment.ts(2 hunks)hooks/useMomentCollect.ts(4 hunks)hooks/useSaleConfig.ts(2 hunks)hooks/useShareMoment.ts(1 hunks)hooks/useToken.ts(0 hunks)hooks/useUpdateMomentURI.ts(4 hunks)lib/moment/collectMoment.ts(2 hunks)lib/moment/collectMomentApi.ts(1 hunks)lib/moment/getMomentApi.ts(1 hunks)lib/moment/indexMoment.ts(1 hunks)lib/mux/migrateMuxToArweave.ts(2 hunks)lib/schema/collectSchema.ts(1 hunks)lib/schema/getMomentSchema.ts(1 hunks)lib/viem/getTokenInfo.ts(3 hunks)providers/MomentProvider.tsx(1 hunks)providers/TokenProvider.tsx(0 hunks)types/moment.ts(1 hunks)
💤 Files with no reviewable changes (2)
- hooks/useToken.ts
- providers/TokenProvider.tsx
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx}: Minimize code to absolute minimum needed - avoid unnecessary abstractions, intermediate steps, or redundant patterns
Write self-documenting code through precise naming (verbs for functions, nouns for variables), single-responsibility components, obvious data flow, and add short comments only when necessary
Apply Single Responsibility Principle (SRP): each function/component should have ONE clear responsibility - extract functions into separate files when they handle distinct concerns - hooks focus on state management, business logic goes in lib files - each function should be in its own file when it has a distinct purpose
Use strict TypeScript types with zero 'any' - prioritize type-exact definitions
Implement built-in security for authentication and data handling - follow secure coding practices throughout the application
Follow Next.js optimization guides for performance - implement proper caching, code splitting, and rendering strategies
Keep all files under 100 lines of code to maintain readability and follow single responsibility principle - split hooks/components when they grow too large or handle multiple concerns
Before coding, make a plan inside a tag: identify core requirement, consider 3 implementation approaches, choose simplest that meets needs, verify if code can be split into smaller functions, check for unnecessary abstractions, and ensure clarity for junior developers
Files:
components/CreatedMoment/CreatedMomentAirdrop.tsxcomponents/TokenManagePage/Sale.tsxcomponents/TokenPage/MetaAndComments.tsxlib/moment/collectMomentApi.tstypes/moment.tscomponents/TokenManagePage/SaveMediaButton.tsxhooks/useShareMoment.tscomponents/TokenManagePage/AnimationUpload.tsxcomponents/TokenManagePage/Media.tsxhooks/useDownload.tslib/moment/indexMoment.tscomponents/TokenPage/CommentSection.tsxcomponents/TokenManagePage/OwnerWarning.tsxhooks/useAirdrop.tshooks/useUpdateMomentURI.tshooks/useComments.tscomponents/TokenManagePage/AirdropButton.tsxcomponents/TokenPage/BackToTimeline.tsxlib/viem/getTokenInfo.tslib/moment/collectMoment.tsproviders/MomentProvider.tsxcomponents/TokenPage/CollectModal.tsxlib/schema/collectSchema.tscomponents/TokenManagePage/TokenManagePage.tsxlib/mux/migrateMuxToArweave.tscomponents/TokenPage/Token.tsxlib/moment/getMomentApi.tslib/schema/getMomentSchema.tscomponents/CollectionManagePage/TokenOverview.tsxhooks/useBalanceOf.tshooks/useMomentCollect.tshooks/useSaleConfig.tscomponents/TokenPage/TokenPage.tsxapp/api/moment/route.tshooks/useMoment.ts
lib/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
Library files should contain pure business logic, data transformation, validation, and API calls - never include React state management or UI concerns
Files:
lib/moment/collectMomentApi.tslib/moment/indexMoment.tslib/viem/getTokenInfo.tslib/moment/collectMoment.tslib/schema/collectSchema.tslib/mux/migrateMuxToArweave.tslib/moment/getMomentApi.tslib/schema/getMomentSchema.ts
hooks/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
Hooks should focus exclusively on state management and data fetching - extract business logic, validation, and data transformation into separate lib files
Files:
hooks/useShareMoment.tshooks/useDownload.tshooks/useAirdrop.tshooks/useUpdateMomentURI.tshooks/useComments.tshooks/useBalanceOf.tshooks/useMomentCollect.tshooks/useSaleConfig.tshooks/useMoment.ts
🧬 Code graph analysis (27)
components/CreatedMoment/CreatedMomentAirdrop.tsx (2)
providers/MomentProvider.tsx (1)
MomentProvider(13-26)lib/consts.ts (1)
CHAIN_ID(20-20)
components/TokenManagePage/Sale.tsx (1)
providers/MomentProvider.tsx (1)
useMomentProvider(28-34)
components/TokenPage/MetaAndComments.tsx (1)
providers/MomentProvider.tsx (1)
useMomentProvider(28-34)
components/TokenManagePage/SaveMediaButton.tsx (1)
providers/MomentProvider.tsx (1)
useMomentProvider(28-34)
hooks/useShareMoment.ts (1)
providers/MomentProvider.tsx (1)
useMomentProvider(28-34)
components/TokenManagePage/AnimationUpload.tsx (1)
providers/MomentProvider.tsx (1)
useMomentProvider(28-34)
components/TokenManagePage/Media.tsx (1)
providers/MomentProvider.tsx (1)
useMomentProvider(28-34)
hooks/useDownload.ts (1)
providers/MomentProvider.tsx (1)
useMomentProvider(28-34)
components/TokenManagePage/OwnerWarning.tsx (1)
providers/MomentProvider.tsx (1)
useMomentProvider(28-34)
hooks/useAirdrop.ts (1)
providers/MomentProvider.tsx (1)
useMomentProvider(28-34)
hooks/useUpdateMomentURI.ts (2)
providers/MomentProvider.tsx (1)
useMomentProvider(28-34)lib/mux/migrateMuxToArweaveApi.ts (1)
migrateMuxToArweaveApi(18-43)
hooks/useComments.ts (1)
providers/MomentProvider.tsx (1)
useMomentProvider(28-34)
components/TokenManagePage/AirdropButton.tsx (2)
providers/AirdropProvider.tsx (1)
useAirdropProvider(21-27)providers/MomentProvider.tsx (1)
useMomentProvider(28-34)
components/TokenPage/BackToTimeline.tsx (1)
providers/MomentProvider.tsx (1)
useMomentProvider(28-34)
lib/moment/collectMoment.ts (1)
lib/moment/validateBalanceAndAllowance.ts (1)
validateBalanceAndAllowance(15-40)
providers/MomentProvider.tsx (1)
types/moment.ts (1)
Moment(4-8)
components/TokenPage/CollectModal.tsx (1)
providers/MomentProvider.tsx (1)
useMomentProvider(28-34)
lib/schema/collectSchema.ts (2)
lib/schema/commentsSchema.ts (1)
momentSchema(4-7)lib/consts.ts (1)
CHAIN_ID(20-20)
components/TokenManagePage/TokenManagePage.tsx (1)
providers/MomentProvider.tsx (1)
MomentProvider(13-26)
lib/mux/migrateMuxToArweave.ts (1)
lib/consts.ts (1)
CHAIN_ID(20-20)
components/TokenPage/Token.tsx (1)
providers/MomentProvider.tsx (1)
useMomentProvider(28-34)
lib/moment/getMomentApi.ts (1)
types/moment.ts (1)
Moment(4-8)
lib/schema/getMomentSchema.ts (1)
lib/consts.ts (1)
CHAIN_ID(20-20)
components/CollectionManagePage/TokenOverview.tsx (1)
providers/MomentProvider.tsx (1)
useMomentProvider(28-34)
hooks/useBalanceOf.ts (1)
providers/MomentProvider.tsx (1)
useMomentProvider(28-34)
hooks/useSaleConfig.ts (1)
providers/MomentProvider.tsx (1)
useMomentProvider(28-34)
components/TokenPage/TokenPage.tsx (3)
providers/MomentProvider.tsx (1)
MomentProvider(13-26)providers/MomentCommentsProvider.tsx (1)
MomentCommentsProvider(14-31)providers/MomentCollectProvider.tsx (1)
MomentCollectProvider(26-26)
🔇 Additional comments (24)
lib/schema/collectSchema.ts (1)
3-9: Schema updates for collectionAddress/chainId look correctImporting
CHAIN_ID, renaming tocollectionAddress, and addingchainId: z.number().optional().default(CHAIN_ID)are consistent and should give you a reliably populated numericchainIdon parsed moments. Just be aware that with the default in place, inferred types will now treatchainIdas always defined after parsing, so any call sites that still assume it can beundefinedmay need tightening.hooks/useDownload.ts (1)
2-7: Provider swap to useMomentProvider looks safeUsing
useMomentProviderto getmetadatapreserves the existing download logic and keeps the hook focused on state + side effects. As long asMomentProviderexposesmetadatawith the samedata/contentshape, this should be a drop‑in replacement.hooks/useAirdrop.ts (1)
11-21: Airdrop hook now sourcing token from MomentProvider looks correctPulling
tokenfromuseMomentProviderand derivingmomentContract/tokenIdkeeps the airdrop payload the same, so executeAirdrop should behave identically to the TokenProvider version provided the context still exposes those fields.components/TokenManagePage/Sale.tsx (1)
4-10: Sale component’s migration to useMomentProvider is straightforwardReading
saleConfigfromuseMomentProviderwhile keepinguseSaleConfigfor local state/effects maintains the existing control flow and safeguards. AssumingsaleConfigin the Moment context matches the prior TokenProvider shape, this should be a non‑breaking swap.components/CollectionManagePage/TokenOverview.tsx (1)
6-10: Provider swap touseMomentProvideris consistentUsing
metadataandisLoadingfromuseMomentProvidermirrors the prior TokenProvider usage and integrates cleanly with existing rendering and skeleton states. No issues from this change alone.components/TokenPage/BackToTimeline.tsx (1)
3-12: Owner sourced fromuseMomentProvidercorrectly
ownerfromuseMomentProvideris used in exactly the same way as before (profile lookup, lowercased route, null-guarded). The provider swap is safe and preserves behavior.components/TokenPage/MetaAndComments.tsx (1)
1-20: Sale/metadata now sourced from MomentProvider without behavior changeSwitching to
useMomentProviderforsaleConfig,metadata,isLoading, andisSetSalekeeps the existing price and comments logic intact, with the same guards aroundmetadataand sale state.components/TokenPage/CollectModal.tsx (1)
3-20: Collect modal now correctly reads from MomentProviderUsing
useMomentProviderforsaleConfig,isLoading,isSetSale, andmetadatamaintains the previous control flow (early return when sale isn’t configured, same disabled state and price display). The swap looks safe.lib/moment/collectMomentApi.ts (1)
4-20: Sending fullMomentobject in collect payload is consistent with new modelPassing the
Momentobject directly in the POST body (moment, amount, comment) matches the updated Moment-centric typing and keeps the call site simple. As long as/api/moment/collectexpects this shape, this change is correct and improves cohesion around theMomenttype.components/TokenPage/CommentSection.tsx (1)
1-1: MomentProvider swap forisSetSalelooks correctUsing
useMomentProviderhere to sourceisSetSalealigns with the new Moment-based context and keeps the rendering logic unchanged. No issues from a correctness or clarity standpoint.Also applies to: 10-10
components/TokenManagePage/AnimationUpload.tsx (1)
5-5: Ownership gating correctly migrated to MomentProviderDeriving
isOwnerfromuseMomentProviderkeeps the upload/reset enablement logic intact and consistent with the new context. No further changes needed here.Also applies to: 11-11
components/TokenManagePage/Media.tsx (1)
4-4: Media component successfully re‑wired to MomentProviderSwitching to
useMomentProviderformetadata,isOwner, andisLoadingis consistent with the new moment-based flow and preserves the existing UX (skeleton, disabled fields, etc.). Looks good.Also applies to: 16-16
components/TokenPage/TokenPage.tsx (1)
5-5: Moment object wiring and provider hierarchy look consistentConstructing
momentfrom the route params and passing it intoMomentProvidermatches the new Moment shape, and the provider wrapping order remains clear and predictable for descendants likeToken, comments, and collect components.Also applies to: 21-25, 30-37
components/TokenManagePage/AirdropButton.tsx (1)
3-3: Airdrop authorization correctly migrated to MomentProviderReading
ownerandtokenAdminsfromuseMomentProvidermaintains the existingcanAirdropchecks without changing semantics. No additional changes required here.Also applies to: 8-8
components/TokenManagePage/TokenManagePage.tsx (1)
8-8: TokenManagePage correctly migrated to MomentProvider with Moment shapePassing
{ collectionAddress: collection.address, tokenId, chainId: collection.chainId }intoMomentProvidercleanly aligns manage flows (overview, airdrop, sale, media) with the new moment-based context. The surrounding logic stays unchanged and coherent.Also applies to: 20-25, 37-37
components/TokenManagePage/SaveMediaButton.tsx (1)
2-2: SaveMediaButton ownership check correctly uses MomentProviderSourcing
isOwnerfromuseMomentProviderand reusing it in the disabled logic preserves the previous access control semantics while aligning with the new provider.Also applies to: 9-9
components/TokenManagePage/OwnerWarning.tsx (1)
2-9: OwnerWarning correctly migrated to MomentProviderUsing
useMomentProviderand destructuringisOwneris consistent with the new context API; no behavioral change introduced.lib/moment/collectMoment.ts (1)
7-53: Verify moment.chainId presence and consistency with CHAIN_IDThe switch to
getMomentOnChainInfowithconst { saleConfig } = await getMomentOnChainInfo({ ...moment, collectionAddress: moment.collectionAddress as Address, });assumes that
momentalways contains a valid numericchainIdcompatible withgetPublicClient(chainId), while the rest of this function (split distribution and returnedchainId) still relies on the globalCHAIN_ID.Please double‑check:
collectSchemaguaranteesmoment.chainIdexists and is a number.moment.chainIdis intended to always matchCHAIN_IDhere, or else update the later usage to stay on the same chain as the on‑chain fetch.If multi‑chain support is expected, aligning
CHAIN_IDversusmoment.chainIdin this flow will avoid subtle mismatches.lib/moment/indexMoment.ts (1)
5-13: Indexing call correctly updated to getMomentOnChainInfoThe new
getMomentOnChainInfousage with{ collectionAddress: address, tokenId: tokenId.toString(), chainId }matches the Moment shape and preserves the existinguri/adminmapping.lib/mux/migrateMuxToArweave.ts (1)
6-51: migrateMuxToArweave correctly switched to getMomentOnChainInfoThe helper is now called with an object
{ collectionAddress, tokenId, chainId: CHAIN_ID }, which matches the new function signature while preserving the prior single‑chain behavior.hooks/useMoment.ts (1)
12-18: LGTM!The
useQueryconfiguration is well-structured with appropriate stale time, retry logic, and enabled condition.hooks/useMomentCollect.ts (1)
51-71: LGTM!The branching logic for free vs. paid mints is clear, and the migration to use
moment.collectionAddressandmoment.tokenIdis correctly implemented.app/api/moment/route.ts (2)
30-36: LGTM!The Moment object construction is clean, with proper address normalization via
getAddressand chainId parsing. Schema validation upstream ensures the values are valid.
9-28: LGTM!The request validation using Zod schema with detailed error responses is a solid pattern. The error details include field-level information which aids debugging.
| const useMoment = (moment: Moment) => { | ||
| const { collectionAddress, tokenId, chainId } = moment; |
There was a problem hiding this comment.
Potential runtime error if moment is undefined.
The destructuring on line 9 will throw if moment is undefined or null, even though the enabled condition on line 15 tries to guard against missing fields. Consider adding a defensive check or ensuring the hook is only called with a valid Moment object.
const useMoment = (moment: Moment) => {
- const { collectionAddress, tokenId, chainId } = moment;
+ const { collectionAddress, tokenId, chainId } = moment ?? {};Alternatively, if the caller must always provide a valid Moment, enforce this at the call site and document the expectation.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const useMoment = (moment: Moment) => { | |
| const { collectionAddress, tokenId, chainId } = moment; | |
| const useMoment = (moment: Moment) => { | |
| const { collectionAddress, tokenId, chainId } = moment ?? {}; |
🤖 Prompt for AI Agents
In hooks/useMoment.ts around lines 8 to 9, the direct destructuring const {
collectionAddress, tokenId, chainId } = moment will throw if moment is
undefined/null; add a defensive check before destructuring (e.g., guard early
return when moment is falsy) or change the hook signature to accept moment?:
Moment and handle the undefined case explicitly so downstream logic that relies
on those values only runs when moment is valid; alternatively enforce and
document that callers must pass a valid Moment and add a runtime assertion at
the top of the hook to fail fast with a clear message.
| @@ -1,5 +1,5 @@ | |||
| import { useEffect, useState } from "react"; | |||
| import { useTokenProvider } from "@/providers/TokenProvider"; | |||
| import { useMomentProvider } from "@/providers/MomentProvider"; | |||
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# First, let's find and read hooks/useSaleConfig.ts
echo "=== Reading hooks/useSaleConfig.ts ==="
fd -t f "useSaleConfig.ts" -x cat -n {}
echo
echo "=== File size check ==="
wc -l hooks/useSaleConfig.ts 2>/dev/null || echo "File not found yet, searching..."Repository: sweetmantech/in_process
Length of output: 2793
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Searching for remaining TokenProvider usages ==="
rg -n "useTokenProvider|TokenProvider" --type ts --type tsx
echo
echo "=== Searching for tokenContractAddress references ==="
rg -n "tokenContractAddress" --type ts --type tsx
echo
echo "=== Finding and reading MomentProvider ==="
fd -t f "MomentProvider" -x cat -n {}Repository: sweetmantech/in_process
Length of output: 164
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Searching for remaining TokenProvider usages ==="
rg -n "useTokenProvider|TokenProvider" --type typescript
echo
echo "=== Searching for tokenContractAddress references ==="
rg -n "tokenContractAddress" --type typescript
echo
echo "=== Finding and reading MomentProvider ==="
fd -t f "MomentProvider" -x wc -l {}
fd -t f "MomentProvider" -x head -80 {}Repository: sweetmantech/in_process
Length of output: 171
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Searching for remaining TokenProvider usages ==="
rg -n "useTokenProvider|TokenProvider"
echo
echo "=== Searching for tokenContractAddress references ==="
rg -n "tokenContractAddress"
echo
echo "=== Finding MomentProvider ==="
fd -t f "MomentProvider"Repository: sweetmantech/in_process
Length of output: 119
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Searching for tokenContractAddress references ==="
rg -n "tokenContractAddress" 2>&1 | head -20
echo
echo "=== Finding MomentProvider files ==="
fd -t f "MomentProvider"
echo
echo "=== Searching for providers directory ==="
fd -t d "providers" | head -5
echo
echo "=== List providers files ==="
ls -la providers/ 2>/dev/null || echo "providers directory not found"Repository: sweetmantech/in_process
Length of output: 3514
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Reading MomentProvider.tsx ==="
cat -n providers/MomentProvider.tsx
echo
echo "=== Reading types/token.ts ==="
cat -n types/token.ts
echo
echo "=== Context around useShareMoment.ts line 12 ==="
sed -n '1,20p' hooks/useShareMoment.ts | cat -nRepository: sweetmantech/in_process
Length of output: 3083
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Finding and reading useMoment hook ==="
fd -t f "useMoment.ts" -o "useMoment.tsx" | head -1 | xargs wc -l
echo
fd -t f "useMoment.ts" -o "useMoment.tsx" | head -1 | xargs head -100Repository: sweetmantech/in_process
Length of output: 274
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Finding useMoment hook ==="
fd "useMoment" hooks/
echo
echo "=== Reading useMoment hook ==="
fd "useMoment" hooks/ -x cat -n {}Repository: sweetmantech/in_process
Length of output: 20305
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Checking types/moment.ts for Moment structure ==="
cat -n types/moment.ts
echo
echo "=== Full context of useSaleConfig.ts around token usage ==="
cat -n hooks/useSaleConfig.tsRepository: sweetmantech/in_process
Length of output: 4412
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Check MomentProvider return type again - what does useMomentProvider return? ==="
sed -n '28,34p' providers/MomentProvider.tsx
echo
echo "=== Check useMoment return statement ==="
sed -n '34,53p' hooks/useMoment.ts
echo
echo "=== Verify: does useMomentProvider return moment? ==="
sed -n '13,26p' providers/MomentProvider.tsxRepository: sweetmantech/in_process
Length of output: 1248
Fix critical bug: useSaleConfig references non-existent token field from useMomentProvider
The main issue is that useSaleConfig is trying to destructure a token field that does not exist in useMomentProvider(). The provider returns moment, saleConfig, metadata, and other fields—but no token.
Additionally, consolidate the two useMomentProvider() calls into one. Here's the corrected approach:
const useSaleConfig = () => {
- const { saleConfig: sale } = useMomentProvider();
+ const { saleConfig: sale, moment, fetchTokenInfo } = useMomentProvider();
const [saleStart, setSaleStart] = useState<Date>(new Date());
- const { token, fetchTokenInfo } = useMomentProvider();
const { signTransaction } = useSignTransaction();
const { connectedAddress } = useUserProvider();
const [isLoading, setIsLoading] = useState<boolean>(false);
const setSale = async () => {
if (!sale) return;
setIsLoading(true);
const newSale = {
...sale,
saleStart: BigInt(Number(saleStart.getTime() / 1000).toFixed(0)),
};
const calldata = encodeFunctionData({
abi: zoraCreatorFixedPriceSaleStrategyABI,
functionName: "setSale",
- args: [BigInt(token.tokenId), newSale],
+ args: [BigInt(moment.tokenId), newSale],
});
const publicClient = getPublicClient(CHAIN_ID);
const hash = await signTransaction({
- address: token.tokenContractAddress,
+ address: moment.collectionAddress,
abi: zoraCreator1155ImplABI,
functionName: "callSale",
- args: [token.tokenId, zoraCreatorFixedPriceSaleStrategyAddress[CHAIN_ID], calldata],
+ args: [moment.tokenId, zoraCreatorFixedPriceSaleStrategyAddress[CHAIN_ID], calldata],
account: connectedAddress as Address,
chain: CHAIN,
});The moment object (available from useMomentProvider) has collectionAddress and tokenId fields—use those instead of the non-existent token object.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import { useMomentProvider } from "@/providers/MomentProvider"; | |
| const useSaleConfig = () => { | |
| const { saleConfig: sale, moment, fetchTokenInfo } = useMomentProvider(); | |
| const [saleStart, setSaleStart] = useState<Date>(new Date()); | |
| const { signTransaction } = useSignTransaction(); | |
| const { connectedAddress } = useUserProvider(); | |
| const [isLoading, setIsLoading] = useState<boolean>(false); | |
| const setSale = async () => { | |
| if (!sale) return; | |
| setIsLoading(true); | |
| const newSale = { | |
| ...sale, | |
| saleStart: BigInt(Number(saleStart.getTime() / 1000).toFixed(0)), | |
| }; | |
| const calldata = encodeFunctionData({ | |
| abi: zoraCreatorFixedPriceSaleStrategyABI, | |
| functionName: "setSale", | |
| args: [BigInt(moment.tokenId), newSale], | |
| }); | |
| const publicClient = getPublicClient(CHAIN_ID); | |
| const hash = await signTransaction({ | |
| address: moment.collectionAddress, | |
| abi: zoraCreator1155ImplABI, | |
| functionName: "callSale", | |
| args: [moment.tokenId, zoraCreatorFixedPriceSaleStrategyAddress[CHAIN_ID], calldata], | |
| account: connectedAddress as Address, | |
| chain: CHAIN, | |
| }); |
🤖 Prompt for AI Agents
In hooks/useSaleConfig.ts around line 2, the hook incorrectly destructures a
non-existent token field from useMomentProvider() and calls useMomentProvider()
twice; update the code to call useMomentProvider() once, remove token from the
destructure, and replace any token.* usage with moment.collectionAddress and
moment.tokenId (or equivalent fields) so the hook uses the actual fields
returned by the provider.
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
app/api/moment/route.ts (1)
54-54: Useunknowninstead ofanyfor caught errors.Per strict TypeScript guidelines, prefer
unknownand narrow the type safely.- } catch (error: any) { + } catch (error: unknown) { console.error("Error fetching moment info:", error); + const message = error instanceof Error ? error.message : "Failed to fetch moment info"; return NextResponse.json( - { error: error?.message || "Failed to fetch moment info" }, + { error: message }, { status: 500 } ); }
♻️ Duplicate comments (1)
hooks/useSaleConfig.ts (1)
15-17: Consolidate duplicateuseMomentProvider()calls.The hook calls
useMomentProvider()twice (lines 15 and 17), which is inefficient and violates DRY principles.Consolidate into a single call:
- const { saleConfig: sale } = useMomentProvider(); + const { saleConfig: sale, moment, fetchTokenInfo } = useMomentProvider(); const [saleStart, setSaleStart] = useState<Date>(new Date()); - const { moment, fetchTokenInfo } = useMomentProvider();
🧹 Nitpick comments (12)
hooks/useAirdrop.ts (1)
19-20: Consider clearer variable naming.The destructuring renames
collectionAddresstomomentContract, which adds an unnecessary layer of indirection. Consider using the property name directly or use a more descriptive variable name.Apply this diff for clearer naming:
- const { moment } = useMomentProvider(); - const { collectionAddress: momentContract, tokenId } = moment; + const { moment } = useMomentProvider(); + const { collectionAddress, tokenId } = moment;Then update line 70:
- momentContract, + collectionAddress,lib/moment/momentComments.ts (1)
15-15: Use consistent camelCase naming convention.The variable
momentdatadoesn't follow camelCase convention. Consider renaming tomomentDatafor consistency with TypeScript/JavaScript naming standards.Apply this diff:
- const momentdata = await selectMoment({ + const momentData = await selectMoment({ collectionAddress: moment.contractAddress as Address, tokenId: moment.tokenId, chainId, }); - if (!momentdata) { + if (!momentData) { throw new Error("Moment not found"); } const comments = await selectComments({ - momentId: momentdata.id, + momentId: momentData.id, offset, });Also applies to: 21-21, 26-26
hooks/useBalanceOf.ts (1)
2-26: Consider adding error handling aroundreadContractThe shift to
useMomentProviderand use ofmoment.collectionAddress/moment.tokenIdlooks correct, butreadContractfailures will currently surface as unhandled promise rejections from the effect. Wrapping the call in atry/catch(and maybe logging or defaultingbalanceOfto0) would make this hook more resilient.lib/zora/getSalesConfig.tsx (1)
4-38: Switching to MomentType enums is fine; consider tighteningsaleStrategytypeUsing
MomentType.FixedPriceMint/TimedMint/Erc20Mintkeeps behavior intact. To avoid invalid values slipping through, consider updating thesaleStrategyparameter type toMomentType(or a union of the specific members used) instead of plainstring.lib/sales/convertDatabaseSaleToApi.ts (2)
10-10: Unsafe cast offunds_recipienttoAddress.The string is cast to
Addresswithout validation. If the database contains an invalid address format, this could cause issues downstream.Consider using viem's
isAddressfor validation:+import { Address, zeroAddress, isAddress } from "viem"; ... - fundsRecipient: sale.funds_recipient as Address, + fundsRecipient: isAddress(sale.funds_recipient) ? sale.funds_recipient : zeroAddress,Alternatively, if you trust the database integrity, the current approach is acceptable.
7-8: RedundantNumber()calls on already-numeric types.
DatabaseSaledefinessale_start,sale_end, andmax_tokens_per_addressasnumbertypes. TheNumber()wrapper is unnecessary.- saleStart: Number(sale.sale_start), - saleEnd: Number(sale.sale_end), - maxTokensPerAddress: Number(sale.max_tokens_per_address), + saleStart: sale.sale_start, + saleEnd: sale.sale_end, + maxTokensPerAddress: sale.max_tokens_per_address,lib/moment/getMomentAdvancedInfo.ts (2)
4-4: Confusing import path vs function name.The function
getMomentOnChainInfois imported from"@/lib/viem/getTokenInfo". This naming mismatch between the file and the exported function can cause confusion. Based on the AI summary, this was renamed fromgetTokenInfobut the file wasn't renamed.Consider renaming the file to match the function name for consistency:
- Rename
lib/viem/getTokenInfo.ts→lib/viem/getMomentOnChainInfo.ts
8-42: Consider adding error handling for failed data fetches.The function has no try-catch blocks. If
selectMoment,selectSale, orgetMomentOnChainInfothrow, the error propagates directly. Depending on how this is used, you may want to return a null/partial result instead.If graceful degradation is desired:
export const getMomentAdvancedInfo = async (moment: Moment): Promise<MomentAdvancedInfo> => { + try { const momentdata = await selectMoment(moment); // ... rest of logic + } catch (error) { + console.error("Failed to get moment advanced info:", error); + return { uri: null, owner: null, saleConfig: null }; + } };Otherwise, if letting errors propagate is intentional, this is acceptable.
lib/moment/collectMoment.ts (1)
7-7: Import path naming inconsistency.Same issue as in
getMomentAdvancedInfo.ts- importinggetMomentOnChainInfofrom a file namedgetTokenInfo. Consider renaming the file for clarity.lib/viem/getTokenInfo.ts (2)
11-12: Combine imports from the same module.-import { MomentType } from "@/types/moment"; -import { Moment } from "@/types/moment"; +import { Moment, MomentType } from "@/types/moment";
49-58: Add null safety checks for multicall results.If any multicall fails, accessing
.resulton undefined could cause runtime errors. Consider defensive checks before accessing nested properties.+ const erc20Result = infoCalls[0]?.result; + const fixedResult = infoCalls[1]?.result; + const saleConfig = - infoCalls[0]?.result?.saleEnd > BigInt(0) + erc20Result?.saleEnd && erc20Result.saleEnd > BigInt(0) ? { - ...infoCalls[0]?.result, + ...erc20Result, type: MomentType.Erc20Mint, } : { - ...infoCalls[1]?.result, + ...fixedResult, type: MomentType.FixedPriceMint, };app/api/moment/route.ts (1)
38-38: Handle missing URI more explicitly.Passing an empty string to
fetchTokenMetadatawhenuriis undefined may lead to failed fetches or unexpected behavior. Consider returning early or providing a more meaningful fallback.+ if (!uri) { + return NextResponse.json( + { error: "Moment URI not found" }, + { status: 404 } + ); + } + - const metadata = await fetchTokenMetadata(uri || ""); + const metadata = await fetchTokenMetadata(uri);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (46)
app/api/moment/route.ts(2 hunks)app/api/moment/update-uri/route.ts(1 hunks)app/api/og/artist/route.tsx(2 hunks)app/api/og/token/route.tsx(2 hunks)components/ArtSlider/CarouselItem.tsx(2 hunks)components/CollectionManagePage/CollectionOverview.tsx(2 hunks)components/CreatedMoment/CreatedMomentAirdrop.tsx(1 hunks)components/HorizontalFeed/FeedHover.tsx(1 hunks)components/Renderers/ContentRenderer.tsx(1 hunks)hooks/useAirdrop.ts(1 hunks)hooks/useBalanceOf.ts(1 hunks)hooks/useCollectBalanceValidation.ts(2 hunks)hooks/useCollection.ts(1 hunks)hooks/useComments.ts(1 hunks)hooks/useMediaInitialization.ts(1 hunks)hooks/useMetadata.ts(1 hunks)hooks/useSaleConfig.ts(3 hunks)hooks/useShareMoment.ts(1 hunks)lib/fetchArtistLatestMint.ts(1 hunks)lib/fetchTokenMetadata.ts(1 hunks)lib/getArtistLatestMoment.ts(1 hunks)lib/getPrice.ts(1 hunks)lib/getPriceUnit.ts(1 hunks)lib/getSaleConfigType.ts(1 hunks)lib/moment/collectMoment.ts(3 hunks)lib/moment/fetchComments.ts(1 hunks)lib/moment/getMomentAdvancedInfo.ts(1 hunks)lib/moment/momentComments.ts(2 hunks)lib/moment/validateBalanceAndAllowance.ts(2 hunks)lib/sales/convertDatabaseSaleToApi.ts(1 hunks)lib/sales/convertOnChainSaleToApi.ts(1 hunks)lib/supabase/in_process_admins/selectAdmins.ts(1 hunks)lib/supabase/in_process_moments/selectMoment.ts(2 hunks)lib/supabase/in_process_sales/selectSale.ts(1 hunks)lib/supabase/in_process_tokens/selectInProcessToken.ts(0 hunks)lib/viem/getCollectCall.ts(2 hunks)lib/viem/getNextTokenIds.ts(0 hunks)lib/viem/getTokenInfo.ts(4 hunks)lib/zora/getSalesConfig.tsx(2 hunks)types/dune.ts(0 hunks)types/fetch-collections.ts(0 hunks)types/jam.ts(0 hunks)types/moment.ts(2 hunks)types/sale.ts(1 hunks)types/token.ts(0 hunks)types/zora.ts(0 hunks)
💤 Files with no reviewable changes (7)
- types/jam.ts
- types/dune.ts
- lib/supabase/in_process_tokens/selectInProcessToken.ts
- types/token.ts
- types/fetch-collections.ts
- lib/viem/getNextTokenIds.ts
- types/zora.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx}: Minimize code to absolute minimum needed - avoid unnecessary abstractions, intermediate steps, or redundant patterns
Write self-documenting code through precise naming (verbs for functions, nouns for variables), single-responsibility components, obvious data flow, and add short comments only when necessary
Apply Single Responsibility Principle (SRP): each function/component should have ONE clear responsibility - extract functions into separate files when they handle distinct concerns - hooks focus on state management, business logic goes in lib files - each function should be in its own file when it has a distinct purpose
Use strict TypeScript types with zero 'any' - prioritize type-exact definitions
Implement built-in security for authentication and data handling - follow secure coding practices throughout the application
Follow Next.js optimization guides for performance - implement proper caching, code splitting, and rendering strategies
Keep all files under 100 lines of code to maintain readability and follow single responsibility principle - split hooks/components when they grow too large or handle multiple concerns
Before coding, make a plan inside a tag: identify core requirement, consider 3 implementation approaches, choose simplest that meets needs, verify if code can be split into smaller functions, check for unnecessary abstractions, and ensure clarity for junior developers
Files:
components/CreatedMoment/CreatedMomentAirdrop.tsxlib/moment/momentComments.tslib/getPrice.tslib/moment/validateBalanceAndAllowance.tshooks/useMediaInitialization.tslib/getArtistLatestMoment.tslib/supabase/in_process_admins/selectAdmins.tstypes/sale.tshooks/useShareMoment.tshooks/useAirdrop.tshooks/useCollection.tshooks/useCollectBalanceValidation.tslib/getPriceUnit.tshooks/useMetadata.tslib/sales/convertDatabaseSaleToApi.tsapp/api/moment/update-uri/route.tscomponents/CollectionManagePage/CollectionOverview.tsxlib/sales/convertOnChainSaleToApi.tscomponents/HorizontalFeed/FeedHover.tsxapp/api/og/token/route.tsxlib/fetchArtistLatestMint.tslib/moment/getMomentAdvancedInfo.tsapp/api/moment/route.tslib/fetchTokenMetadata.tshooks/useBalanceOf.tscomponents/Renderers/ContentRenderer.tsxlib/supabase/in_process_sales/selectSale.tslib/moment/collectMoment.tshooks/useSaleConfig.tslib/supabase/in_process_moments/selectMoment.tslib/moment/fetchComments.tslib/viem/getTokenInfo.tslib/zora/getSalesConfig.tsxcomponents/ArtSlider/CarouselItem.tsxlib/getSaleConfigType.tsapp/api/og/artist/route.tsxlib/viem/getCollectCall.tshooks/useComments.tstypes/moment.ts
lib/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
Library files should contain pure business logic, data transformation, validation, and API calls - never include React state management or UI concerns
Files:
lib/moment/momentComments.tslib/getPrice.tslib/moment/validateBalanceAndAllowance.tslib/getArtistLatestMoment.tslib/supabase/in_process_admins/selectAdmins.tslib/getPriceUnit.tslib/sales/convertDatabaseSaleToApi.tslib/sales/convertOnChainSaleToApi.tslib/fetchArtistLatestMint.tslib/moment/getMomentAdvancedInfo.tslib/fetchTokenMetadata.tslib/supabase/in_process_sales/selectSale.tslib/moment/collectMoment.tslib/supabase/in_process_moments/selectMoment.tslib/moment/fetchComments.tslib/viem/getTokenInfo.tslib/zora/getSalesConfig.tsxlib/getSaleConfigType.tslib/viem/getCollectCall.ts
hooks/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
Hooks should focus exclusively on state management and data fetching - extract business logic, validation, and data transformation into separate lib files
Files:
hooks/useMediaInitialization.tshooks/useShareMoment.tshooks/useAirdrop.tshooks/useCollection.tshooks/useCollectBalanceValidation.tshooks/useMetadata.tshooks/useBalanceOf.tshooks/useSaleConfig.tshooks/useComments.ts
🧬 Code graph analysis (26)
components/CreatedMoment/CreatedMomentAirdrop.tsx (3)
providers/MomentCreateProvider/MomentCreateProvider.tsx (1)
useMomentCreateProvider(31-31)providers/MomentProvider.tsx (1)
MomentProvider(13-26)lib/consts.ts (1)
CHAIN_ID(20-20)
hooks/useMediaInitialization.ts (1)
types/moment.ts (1)
MomentMetadata(62-72)
lib/getArtistLatestMoment.ts (1)
types/moment.ts (1)
MomentMetadata(62-72)
lib/supabase/in_process_admins/selectAdmins.ts (2)
types/moment.ts (1)
Moment(4-8)lib/supabase/client.ts (1)
supabase(7-7)
hooks/useAirdrop.ts (1)
providers/MomentProvider.tsx (1)
useMomentProvider(28-34)
hooks/useCollection.ts (1)
types/moment.ts (1)
MomentMetadata(62-72)
hooks/useMetadata.ts (1)
types/moment.ts (1)
MomentMetadata(62-72)
lib/sales/convertDatabaseSaleToApi.ts (2)
types/sale.ts (1)
DatabaseSale(13-20)types/moment.ts (1)
MomentApiSaleConfig(80-87)
components/CollectionManagePage/CollectionOverview.tsx (1)
types/moment.ts (1)
MomentMetadata(62-72)
lib/sales/convertOnChainSaleToApi.ts (2)
types/sale.ts (1)
OnChainSaleConfig(4-11)types/moment.ts (1)
MomentApiSaleConfig(80-87)
components/HorizontalFeed/FeedHover.tsx (1)
types/moment.ts (1)
MomentMetadata(62-72)
lib/fetchArtistLatestMint.ts (1)
types/moment.ts (1)
MomentMetadata(62-72)
lib/moment/getMomentAdvancedInfo.ts (3)
types/moment.ts (2)
Moment(4-8)MomentAdvancedInfo(97-101)lib/sales/convertDatabaseSaleToApi.ts (1)
convertDatabaseSaleToApi(5-15)lib/sales/convertOnChainSaleToApi.ts (1)
convertOnChainSaleToApi(4-11)
app/api/moment/route.ts (2)
types/moment.ts (1)
Moment(4-8)lib/moment/getMomentAdvancedInfo.ts (1)
getMomentAdvancedInfo(8-42)
lib/fetchTokenMetadata.ts (1)
types/moment.ts (1)
MomentMetadata(62-72)
hooks/useBalanceOf.ts (3)
providers/MomentProvider.tsx (1)
useMomentProvider(28-34)providers/UserProvider.tsx (1)
useUserProvider(38-44)lib/viem/publicClient.ts (2)
publicClient(16-16)getPublicClient(7-14)
components/Renderers/ContentRenderer.tsx (1)
types/moment.ts (1)
MomentMetadata(62-72)
lib/supabase/in_process_sales/selectSale.ts (1)
lib/supabase/client.ts (1)
supabase(7-7)
lib/moment/collectMoment.ts (2)
lib/moment/validateBalanceAndAllowance.ts (1)
validateBalanceAndAllowance(15-40)lib/consts.ts (1)
USDC_ADDRESS(32-34)
hooks/useSaleConfig.ts (1)
providers/MomentProvider.tsx (1)
useMomentProvider(28-34)
lib/supabase/in_process_moments/selectMoment.ts (1)
types/moment.ts (1)
Moment(4-8)
lib/moment/fetchComments.ts (1)
types/moment.ts (2)
MomentCommentsInput(10-13)MintComment(26-32)
lib/viem/getTokenInfo.ts (3)
types/moment.ts (1)
Moment(4-8)lib/viem/publicClient.ts (2)
publicClient(16-16)getPublicClient(7-14)lib/protocolSdk/constants.ts (1)
erc20MinterAddresses(70-83)
components/ArtSlider/CarouselItem.tsx (2)
types/moment.ts (1)
MomentMetadata(62-72)app/page.tsx (1)
metadata(8-34)
app/api/og/artist/route.tsx (1)
app/page.tsx (1)
metadata(8-34)
hooks/useComments.ts (1)
providers/MomentProvider.tsx (1)
useMomentProvider(28-34)
🔇 Additional comments (31)
hooks/useCollection.ts (1)
2-2: LGTM! Clean type migration.The type changes from
MetadatatoMomentMetadataare consistent with the moment-centric refactor and align with the new type definition intypes/moment.ts.Also applies to: 7-7
hooks/useMediaInitialization.ts (1)
2-2: LGTM! Type migration is correct.The parameter type update to
MomentMetadataaligns with the broader refactor and maintains compatibility with the existing initialization logic.Also applies to: 5-5
components/CreatedMoment/CreatedMomentAirdrop.tsx (1)
6-6: LGTM! Provider migration correctly implemented.The transition from
TokenProvidertoMomentProvideris properly structured with the correctmomentobject shape containingcollectionAddress,tokenId, andchainId. TheAddresstype assertion on Line 18 is appropriate.Also applies to: 8-8, 16-24
hooks/useCollectBalanceValidation.ts (1)
2-2: LGTM! Enum migration is correct.The update from
MintTypetoMomentTypealigns with the codebase-wide refactor. The balance validation logic remains unchanged.Also applies to: 14-14
lib/viem/getCollectCall.ts (1)
5-5: LGTM! Enum reference correctly updated.The change from
MintType.Erc20MinttoMomentType.Erc20Mintis consistent with the moment-centric refactor. The function logic and ABI encoding remain unchanged.Also applies to: 25-25
lib/moment/validateBalanceAndAllowance.ts (1)
9-9: LGTM! Enum migration is correct.The update to
MomentType.Erc20Mintmaintains the existing validation logic while aligning with the moment-centric type system.Also applies to: 21-21
app/api/moment/update-uri/route.ts (1)
40-40: Schema alignment verified—collectionAddressis properly defined inmomentSchema.The
updateMomentURISchemacorrectly usesmomentSchemafromlib/schema/collectSchema.ts, which includes thecollectionAddressfield as anaddressSchematype. The property change fromcontractAddresstocollectionAddressis fully supported by the schema validation, confirming the moment-centric refactor is consistent throughout the validation layer.lib/getArtistLatestMoment.ts (1)
1-1: Type consistency verified — no issues found.The
fetchTokenMetadatafunction inlib/fetchTokenMetadata.ts(line 7) correctly returnsPromise<MomentMetadata | null>, which aligns with:
- The
MomentMetadataimport from@/types/moment(line 1)- The return type of
getArtistLatestMomentfunction (line 8 inlib/getArtistLatestMoment.ts)Type consistency is maintained across both functions.
components/CollectionManagePage/CollectionOverview.tsx (1)
5-5: LGTM!The type migration from
MetadatatoMomentMetadatais correctly applied and aligns with the PR's objective to migrate to moment-centric data flow.Also applies to: 42-42
lib/supabase/in_process_sales/selectSale.ts (1)
3-11: LGTM!The function implementation is clean and follows the single responsibility principle. Returning
nullon error is an acceptable pattern for optional data retrieval.app/api/og/artist/route.tsx (1)
41-41: LGTM!The addition of optional chaining for
metadata.content?.mimeis a good defensive programming practice that aligns with theMomentMetadatainterface wherecontentis optional. This prevents potential runtime errors whencontentis undefined or null.Also applies to: 88-88
hooks/useMetadata.ts (1)
2-2: LGTM!The type migration from
MetadatatoMomentMetadatais correctly applied throughout the function signature and aligns with the PR's moment-centric refactoring.Also applies to: 5-5
lib/fetchTokenMetadata.ts (1)
1-1: LGTM!The type migration to
MomentMetadatais correct. Note that the function namefetchTokenMetadatastill references "token" while returningMomentMetadata, but this is acceptable given it's fetching metadata for NFT tokens.Also applies to: 7-7
components/Renderers/ContentRenderer.tsx (1)
3-3: LGTM!The type migration from
MetadatatoMomentMetadatain the component props and import is correctly applied. All property accesses remain compatible with the new type structure.Also applies to: 11-11
hooks/useComments.ts (1)
10-78: LGTM! Clean migration to MomentProvider.The hook successfully migrates to the moment-based data model while maintaining clean state management patterns. The pagination implementation, optimistic updates, and memoization are well-structured.
lib/supabase/in_process_moments/selectMoment.ts (1)
4-23: LGTM! Clean refactor to moment-based signature.The migration to a single
Momentparameter and the use of.single()for fetching a single record are appropriate improvements. Error handling with null return is consistent with the new pattern.types/moment.ts (1)
4-101: LGTM! Well-structured type definitions.The moment-centric types are well-defined with proper TypeScript strictness. The renaming from
contractAddresstocollectionAddressand addition ofchainIdalign with the broader migration to moment-based data flow.lib/getPrice.ts (1)
1-7: LGTM! Clean type migration.The migration from
MintTypetoMomentTypeis straightforward and preserves the existing logic correctly.lib/getPriceUnit.ts (1)
1-6: LGTM! Consistent type migration.The migration from
MintTypetoMomentTypemaintains the existing behavior correctly.hooks/useShareMoment.ts (1)
6-19: LGTM! Clean provider migration.The hook successfully migrates to
useMomentProviderwhile maintaining its focused responsibility of sharing moment URLs. The field mappings tocollectionAddressandtokenIdare correct.components/ArtSlider/CarouselItem.tsx (1)
2-41: MomentMetadata swap and safer content access look correctUsing
MomentMetadataandmetadata.content?.mime/urialigns with the new type and avoids runtime errors whencontentis null, while preserving existing rendering branches.components/HorizontalFeed/FeedHover.tsx (1)
3-19: FeedHover props now correctly use MomentMetadataThe prop type and import update to
MomentMetadataare consistent with the new data model; runtime behavior remains the same.lib/fetchArtistLatestMint.ts (1)
1-18: Return type alignment with MomentMetadata is appropriateUpdating
getArtistLatestMintto returnPromise<MomentMetadata | null>matches the new metadata shape without changing the existing fetch logic.app/api/og/token/route.tsx (1)
35-47: Optional chaining formetadata.contentis a safe improvementUsing
metadata.content?.mimeandmetadata.content?.uricorrectly guards against missingcontentwhile keeping the writing/image branches unchanged.lib/getSaleConfigType.ts (1)
1-7: MomentType mapping ingetSaleConfigTypelooks correctThe function now cleanly maps the three string values to the corresponding
MomentTypeenum members; no behavior regressions apparent.lib/sales/convertOnChainSaleToApi.ts (1)
4-11: LGTM!Clean utility function with correct type conversions. The
biginttoNumberconversions for timestamps are safe for realistic Unix timestamps. The implementation follows the single-responsibility principle for lib files.types/sale.ts (1)
1-20: LGTM!Well-structured type definitions with clear separation between on-chain (
bigintfor blockchain values) and database representations. The snake_case naming forDatabaseSalecorrectly reflects typical database column conventions.lib/moment/collectMoment.ts (2)
71-71: LGTM on MomentType usage.The switch from
MintTypetoMomentType.Erc20Mintis consistent with the usage invalidateBalanceAndAllowance.ts(per the code snippet).
38-41: Redundant spread and cast is confirmed—simplify to passmomentdirectly.The
getMomentOnChainInfofunction (line 14 inlib/viem/getTokenInfo.ts) expects aMomenttype parameter directly. SinceMoment.collectionAddressis already typed asAddressintypes/moment.ts, the spread with explicit override adds no value and introduces unnecessary complexity.- const { saleConfig } = await getMomentOnChainInfo({ - ...moment, - collectionAddress: moment.collectionAddress as Address, - }); + const { saleConfig } = await getMomentOnChainInfo(moment);This refactor maintains type safety while improving clarity.
lib/viem/getTokenInfo.ts (1)
21-21: VerifytokenIdtype compatibility with ABI expectations.The
tokenIdis passed as astring, but ERC-1155 ABIs typically expectbigintfor token ID arguments. This could cause runtime issues or incorrect encoding.+ const tokenIdBigInt = BigInt(tokenId); + const erc20SaleConfigCall = { address: erc20MinterAddresses[chainId as keyof typeof erc20MinterAddresses], abi: erc20MinterABI, functionName: "sale", - args: [collectionAddress, tokenId], + args: [collectionAddress, tokenIdBigInt], }; const fixedSaleConfigCall = { ... - args: [collectionAddress, tokenId], + args: [collectionAddress, tokenIdBigInt], }; const uriCall = { ... - args: [tokenId], + args: [tokenIdBigInt], };Also applies to: 30-30, 36-36
app/api/moment/route.ts (1)
41-53: Response structure looks good for the moment-centric migration.The response payload correctly includes
uri,owner,saleConfig,momentAdmins, and enriched metadata fields, aligning with the refactored data flow.
| const { collectionAddress, tokenId, chainId } = parseResult.data; | ||
| const moment: Moment = { | ||
| collectionAddress: getAddress(collectionAddress), | ||
| tokenId, | ||
| chainId: parseInt(chainId, 10), | ||
| }; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for getMomentSchema definition
ast-grep --pattern 'getMomentSchema'Repository: sweetmantech/in_process
Length of output: 321
🏁 Script executed:
#!/bin/bash
# Read the schema file to see chainId definition
cat -n lib/schema/getMomentSchema.tsRepository: sweetmantech/in_process
Length of output: 609
🏁 Script executed:
#!/bin/bash
# Read the relevant sections of app/api/moment/route.ts
cat -n app/api/moment/route.ts | head -60Repository: sweetmantech/in_process
Length of output: 2577
Based on my verification, I can now provide the rewritten review comment. The key finding is that the original review's concern about parseInt being redundant is incorrect — the schema explicitly returns chainId as a string, making the conversion necessary. However, there are two other valid concerns.
Remove the parseInt redundancy concern; focus on error typing violation and uri handling.
The schema defines chainId as z.string() with validation, so the parseInt(chainId, 10) conversion is necessary and correct. However, fix the error typing at line 54 (error: any should be error: unknown for strict TypeScript compliance), and the uri || "" fallback at line 38 could mask issues if fetchTokenMetadata expects a valid URI.
🤖 Prompt for AI Agents
In app/api/moment/route.ts around lines 30-35 and also referencing lines ~38 and
~54, the review wrongly flagged parseInt as redundant (it's needed because
schema returns chainId as string), but you must fix two real issues: replace the
error parameter type from `any` to `unknown` at line 54 and handle the `uri`
fallback at line 38 without silently passing an empty string. Change the catch
signature to `error: unknown` and narrow/format it before logging/responding;
for the URI, validate that `uri` is present and well-formed before calling
fetchTokenMetadata (return a 400 or handle missing/invalid URIs explicitly)
instead of using `uri || ""` which can mask errors.
| } = await getMomentOnChainInfo(moment); | ||
| return { | ||
| uri: tokenUri, | ||
| owner: tokenOwner as string, |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find the getMomentAdvancedInfo.ts file and check its location
fd -t f "getMomentAdvancedInfo.ts" --type tsRepository: sweetmantech/in_process
Length of output: 236
🏁 Script executed:
#!/bin/bash
# Find getMomentAdvancedInfo.ts file
fd "getMomentAdvancedInfo.ts"
# Also search for the specific file we know exists
find . -name "getMomentAdvancedInfo.ts" -type fRepository: sweetmantech/in_process
Length of output: 140
🏁 Script executed:
#!/bin/bash
# Read the getMomentAdvancedInfo.ts file to see context around line 39
wc -l lib/moment/getMomentAdvancedInfo.ts
cat -n lib/moment/getMomentAdvancedInfo.ts
# Also search for getMomentOnChainInfo function definition
rg -n "getMomentOnChainInfo" --type-list | head -5
rg -n "getMomentOnChainInfo" -A 10 -B 2Repository: sweetmantech/in_process
Length of output: 12624
🏁 Script executed:
#!/bin/bash
# Read the full getMomentOnChainInfo function in lib/viem/getTokenInfo.ts
cat -n lib/viem/getTokenInfo.ts
# Search for MomentAdvancedInfo type definition
rg -n "type MomentAdvancedInfo|interface MomentAdvancedInfo" -A 10Repository: sweetmantech/in_process
Length of output: 2631
🏁 Script executed:
#!/bin/bash
# Check if there's any error handling around the multicall or owner property
rg -n "multicall|infoCalls\[3\]" lib/viem/getTokenInfo.ts -B 3 -A 3
# Check how tokenOwner is used in other places
rg -n "tokenOwner" lib/moment/ -B 2 -A 2
# Look for any null/undefined checks on owner in the codebase
rg -n "owner.*\?" types/moment.ts -B 5 -A 5Repository: sweetmantech/in_process
Length of output: 1001
Add null check before casting tokenOwner to string.
The cast at line 39 (tokenOwner as string) suppresses type checking without validating that tokenOwner is not null. Since getMomentOnChainInfo returns owner: infoCalls[3].result from a smart contract multicall with no error handling, the result can be null or undefined if the call fails. MomentAdvancedInfo.owner accepts string | null, so either:
- Remove the cast and allow null (matches the type), or
- Add a null check:
owner: tokenOwner ?? fallbackValueorowner: tokenOwner as string | null
🤖 Prompt for AI Agents
In lib/moment/getMomentAdvancedInfo.ts around line 39, the code casts tokenOwner
to string without checking for null which can hide a failed multicall result;
change the assignment so it does not force a non-null string: either remove the
cast and assign owner: tokenOwner allowing the declared type string | null, or
explicitly check and provide a fallback (e.g. owner: tokenOwner ?? null) so
null/undefined is handled safely instead of suppressed by a cast.
| const selectAdmins = async (moment: Moment) => { | ||
| const { data, error } = await supabase | ||
| .from("in_process_admins") | ||
| .select("*") | ||
| .eq("collection", moment.collectionAddress) | ||
| .or(`token_id.in.(0,${moment.tokenId})`); | ||
| if (error) return []; | ||
| return data || []; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# First, check the file structure and read the specific file
find . -name "selectAdmins.ts" -type f 2>/dev/null | head -5Repository: sweetmantech/in_process
Length of output: 115
🏁 Script executed:
#!/bin/bash
# Read the file to see current implementation
wc -l ./lib/supabase/in_process_admins/selectAdmins.ts
cat -n ./lib/supabase/in_process_admins/selectAdmins.tsRepository: sweetmantech/in_process
Length of output: 606
🏁 Script executed:
#!/bin/bash
# Check the Moment type to understand tokenId
fd -e ts -e tsx -e js | xargs grep -l "type Moment\|interface Moment" | head -5Repository: sweetmantech/in_process
Length of output: 245
🏁 Script executed:
#!/bin/bash
# Read the Moment type definition
cat -n ./types/moment.tsRepository: sweetmantech/in_process
Length of output: 2750
🏁 Script executed:
#!/bin/bash
# Search for Supabase query patterns - look for .in() and .or() usage
rg -n '\.(in|or)\s*\(' lib/supabase --type ts -A 2 -B 2 | head -60Repository: sweetmantech/in_process
Length of output: 2270
🏁 Script executed:
#!/bin/bash
# Let's check the getInProcessTokens.ts file to understand .in() better
cat -n ./lib/supabase/in_process_tokens/getInProcessTokens.tsRepository: sweetmantech/in_process
Length of output: 2434
🏁 Script executed:
#!/bin/bash
# Let me check if there's any documentation or usage showing why .or() was used vs .in()
# Check if there are any complex .or() patterns that justify the string approach
rg -n "\.or\(" lib/supabase --type ts -B 2 -A 2Repository: sweetmantech/in_process
Length of output: 469
Based on my verification, I've confirmed the review comment's concerns are valid:
-
Verified the pattern is anomalous: The codebase uses
.in(field, array)consistently in 5+ other locations (getInProcessTokens, updateInProcessTokens, selectPayments, selectArtists), but selectAdmins.ts uniquely uses string interpolation in.or(). -
Confirmed semantic equivalence: The suggested refactor from
.or(\token_id.in.(0,${moment.tokenId})`)to.in("token_id", [0, Number(moment.tokenId)])` is semantically identical and achieves the same filtering logic. -
Validated tokenId type: tokenId is a string, and the suggested
Number()conversion is appropriate. -
String interpolation risk: While the Supabase JS SDK likely provides escaping, the string interpolation approach is less robust and inconsistent with established patterns in this codebase.
Replace .or() string interpolation with parameterized .in() for consistency and safety
This is the only place in the Supabase lib that uses string-built filters. The codebase consistently uses .in(field, array) elsewhere. Refactor to:
- const { data, error } = await supabase
- .from("in_process_admins")
- .select("*")
- .eq("collection", moment.collectionAddress)
- .or(`token_id.in.(0,${moment.tokenId})`);
+ const { data, error } = await supabase
+ .from("in_process_admins")
+ .select("*")
+ .eq("collection", moment.collectionAddress)
+ .in("token_id", [0, Number(moment.tokenId)]);
+
+ if (error) {
+ console.error("Failed to select admins", error);
+ return [];
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const selectAdmins = async (moment: Moment) => { | |
| const { data, error } = await supabase | |
| .from("in_process_admins") | |
| .select("*") | |
| .eq("collection", moment.collectionAddress) | |
| .or(`token_id.in.(0,${moment.tokenId})`); | |
| if (error) return []; | |
| return data || []; | |
| const selectAdmins = async (moment: Moment) => { | |
| const { data, error } = await supabase | |
| .from("in_process_admins") | |
| .select("*") | |
| .eq("collection", moment.collectionAddress) | |
| .in("token_id", [0, Number(moment.tokenId)]); | |
| if (error) { | |
| console.error("Failed to select admins", error); | |
| return []; | |
| } | |
| return data || []; | |
| }; |
🤖 Prompt for AI Agents
In lib/supabase/in_process_admins/selectAdmins.ts around lines 4 to 11, the
query uses a string-interpolated .or(`token_id.in.(0,${moment.tokenId})`) which
is inconsistent and less safe than the codebase standard; replace that with the
parameterized .in("token_id", [0, Number(moment.tokenId)]) while keeping the
.eq("collection", moment.collectionAddress) intact so the query becomes
.from("in_process_admins").select("*").eq("collection",
moment.collectionAddress).in("token_id", [0, Number(moment.tokenId)]); ensure
Number() conversion for tokenId and leave the existing error/data handling
unchanged.
| ) => { | ||
| const getMomentOnChainInfo = async (moment: Moment) => { | ||
| const { collectionAddress, tokenId, chainId } = moment; | ||
| const publicClient: any = getPublicClient(chainId); |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Avoid using any type for publicClient.
The PublicClient type is available from viem. Using any bypasses TypeScript's type checking and violates the strict typing guideline.
- const publicClient: any = getPublicClient(chainId);
+ const publicClient = getPublicClient(chainId);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const publicClient: any = getPublicClient(chainId); | |
| const publicClient = getPublicClient(chainId); |
🤖 Prompt for AI Agents
In lib/viem/getTokenInfo.ts around line 16, the variable publicClient is typed
as any which disables TypeScript checks; import the PublicClient type from
'viem' (or the correct export path) and annotate publicClient with that type
(e.g., const publicClient: PublicClient = getPublicClient(chainId)), updating
imports accordingly so the function benefits from strict typing and
autocomplete.
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 (1)
app/api/moment/comments/route.ts (1)
45-49: Replaceanywithunknownfor strict type safety.The catch clause uses
e: any, which violates the coding guideline requiring "zero 'any'" types.As per coding guidelines, use strict TypeScript types. Apply this diff:
- } catch (e: any) { + } catch (e: unknown) { console.log(e); - const message = e?.message ?? "failed to get comments"; + const message = e instanceof Error ? e.message : "failed to get comments"; return Response.json({ message }, { status: 500, headers: corsHeaders }); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
app/api/moment/comments/route.ts(1 hunks)lib/moment/fetchComments.ts(1 hunks)lib/moment/getMomentApi.ts(1 hunks)lib/moment/momentComments.ts(2 hunks)lib/schema/commentsSchema.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- lib/moment/fetchComments.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx}: Minimize code to absolute minimum needed - avoid unnecessary abstractions, intermediate steps, or redundant patterns
Write self-documenting code through precise naming (verbs for functions, nouns for variables), single-responsibility components, obvious data flow, and add short comments only when necessary
Apply Single Responsibility Principle (SRP): each function/component should have ONE clear responsibility - extract functions into separate files when they handle distinct concerns - hooks focus on state management, business logic goes in lib files - each function should be in its own file when it has a distinct purpose
Use strict TypeScript types with zero 'any' - prioritize type-exact definitions
Implement built-in security for authentication and data handling - follow secure coding practices throughout the application
Follow Next.js optimization guides for performance - implement proper caching, code splitting, and rendering strategies
Keep all files under 100 lines of code to maintain readability and follow single responsibility principle - split hooks/components when they grow too large or handle multiple concerns
Before coding, make a plan inside a tag: identify core requirement, consider 3 implementation approaches, choose simplest that meets needs, verify if code can be split into smaller functions, check for unnecessary abstractions, and ensure clarity for junior developers
Files:
lib/schema/commentsSchema.tslib/moment/momentComments.tsapp/api/moment/comments/route.tslib/moment/getMomentApi.ts
lib/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
Library files should contain pure business logic, data transformation, validation, and API calls - never include React state management or UI concerns
Files:
lib/schema/commentsSchema.tslib/moment/momentComments.tslib/moment/getMomentApi.ts
🧬 Code graph analysis (3)
lib/schema/commentsSchema.ts (2)
lib/schema/collectSchema.ts (1)
momentSchema(5-9)lib/consts.ts (1)
CHAIN_ID(20-20)
app/api/moment/comments/route.ts (1)
lib/consts.ts (1)
CHAIN_ID(20-20)
lib/moment/getMomentApi.ts (1)
types/moment.ts (1)
Moment(4-8)
🔇 Additional comments (4)
lib/moment/momentComments.ts (1)
3-3: LGTM!The import change from
selectMomentstoselectMomentcorrectly reflects the single-moment fetch pattern.lib/schema/commentsSchema.ts (1)
3-9: LGTM! Schema updates align with Moment-based model.The changes correctly:
- Rename
contractAddresstocollectionAddressfor consistency with the new Moment type- Add
chainIdwith a sensible default fromCHAIN_ID- Match the structure in
lib/schema/collectSchema.tsThe schema properly validates the Moment object structure throughout the codebase.
app/api/moment/comments/route.ts (1)
21-28: LGTM! Query parameter construction properly updated.The changes correctly:
- Use
collectionAddressinstead ofcontractAddressto match the updated schema- Parse
chainIdfrom search params with appropriate default fallback toCHAIN_ID- Construct a moment object that validates against the updated
commentsSchemaThe validation on line 30 ensures type safety despite the
as Addresscast.lib/moment/getMomentApi.ts (1)
10-13: LGTM: Solid error handling.The error handling correctly manages both HTTP errors and JSON parsing failures with appropriate fallbacks, improving reliability.
| import { Moment } from "@/types/moment"; | ||
|
|
||
| export const getMomentApi = async (tokenContract: Address, tokenId: string, chainId: number) => { | ||
| export const getMomentApi = async (moment: Moment) => { |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Add explicit return type annotation.
The function signature lacks an explicit return type, violating the coding guideline: "Use strict TypeScript types with zero 'any' - prioritize type-exact definitions." Without it, the return type is inferred as Promise<any>, allowing any to propagate through the codebase.
As per coding guidelines, define the expected return type structure or import it from your types.
Example:
+import { MomentApiResponse } from "@/types/moment"; // or define inline
+
-export const getMomentApi = async (moment: Moment) => {
+export const getMomentApi = async (moment: Moment): Promise<MomentApiResponse> => {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import { Moment } from "@/types/moment"; | |
| export const getMomentApi = async (tokenContract: Address, tokenId: string, chainId: number) => { | |
| export const getMomentApi = async (moment: Moment) => { | |
| import { MomentApiResponse } from "@/types/moment"; | |
| export const getMomentApi = async (moment: Moment): Promise<MomentApiResponse> => { |
🤖 Prompt for AI Agents
In lib/moment/getMomentApi.ts lines 1-3, the async function getMomentApi lacks
an explicit return type (currently inferred as Promise<any>), so update the
function signature to declare a precise return type (e.g.,
Promise<YourResponseType>), either by importing an existing response/interface
from your types or by creating a specific type for the API response, and ensure
the implementation conforms to that type so no any is propagated.
| const momentdata = await selectMoment({ | ||
| collectionAddress: moment.collectionAddress as Address, | ||
| tokenId: moment.tokenId, | ||
| chainId, | ||
| chainId: moment.chainId, | ||
| }); | ||
|
|
||
| const momentData = data[0]; | ||
|
|
||
| if (!momentData) { | ||
| if (!momentdata) { | ||
| throw new Error("Moment not found"); | ||
| } | ||
|
|
||
| const comments = await selectComments({ | ||
| momentId: momentData.id, | ||
| momentId: momentdata.id, |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Fix variable naming convention and remove type assertion.
Two issues:
- Variable
momentdataviolates camelCase convention—should bemomentData. - Type assertion
as Addresson line 15 bypasses type checking and may hide a type mismatch.
Apply this diff to fix both issues:
- const momentdata = await selectMoment({
- collectionAddress: moment.collectionAddress as Address,
+ const momentData = await selectMoment({
+ collectionAddress: moment.collectionAddress,
tokenId: moment.tokenId,
chainId: moment.chainId,
});
- if (!momentdata) {
+ if (!momentData) {
throw new Error("Moment not found");
}
const comments = await selectComments({
- momentId: momentdata.id,
+ momentId: momentData.id,
offset,
});As per coding guidelines, use precise camelCase naming and strict TypeScript types without type assertions.
🤖 Prompt for AI Agents
In lib/moment/momentComments.ts around lines 14 to 25, rename the variable
momentdata to momentData to follow camelCase and remove the unsafe type
assertion "as Address" on moment.collectionAddress; pass collectionAddress:
moment.collectionAddress (rely on correct typing) and if the compiler complains,
update the Moment type or add an explicit runtime validation/conversion for
collectionAddress rather than using a type assertion.
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
lib/moment/callUpdateMomentURI.ts (1)
1-39: Fix return type mismatch (Promise<void>vsreturn data.hash) and tighten error typing tounknownThe function signature declares
Promise<void>while the implementation returnsdata.hash. This is a TypeScript error and must be corrected. Since the caller inhooks/useUpdateMomentURI.ts(line 69) does not capture the return value, and the hash is not used downstream, remove thereturn data.hash;statement to align with thePromise<void>signature:export async function callUpdateMomentURI({ moment, newUri, accessToken, }: CallUpdateMomentURIInput): Promise<void> { try { const response = await fetch("/api/moment/update-uri", { method: "POST", headers: { "content-type": "application/json", authorization: `Bearer ${accessToken}`, }, body: JSON.stringify({ moment, newUri, }), }); const data = await response.json(); if (!response.ok) { throw new Error(data.message || "Failed to update moment metadata"); } - return data.hash; } catch (error: any) { - throw new Error(error?.message || "Failed to update moment metadata"); + if (error instanceof Error) { + throw new Error(error.message || "Failed to update moment metadata"); + } + throw new Error("Failed to update moment metadata"); } }Also, replace
error: anywitherror: unknownand add theinstanceof Errorguard to comply with the zero-any typing standard used throughout the codebase.
🧹 Nitpick comments (2)
lib/moment/updateMomentURI.ts (1)
6-36: Moment-based input looks good; consider whether to usemoment.chainIdinstead of a global chain idThe migration to
moment: MomentinUpdateMomentURIInputand the corresponding use ofmoment.collectionAddress/moment.tokenIdingetUpdateTokenURICallis clean and keeps the business logic unchanged. This aligns well with the PR’s move toward a Moment-centric data model.One thing to double‑check:
UpdateMomentURIResult.chainIdis still coming from the globalCHAIN_ID, and thenetworkforsendUserOperationis derived fromIS_TESTNET, while theMomenttype itself carries achainId. If you expect to support multiple chains per deployment, you may eventually want to derive the network/chain id frommoment.chainIdto avoid drift between the Moment data and the configured constants, even if it’s not required for the current single‑chain setup.app/api/moment/update-uri/route.ts (1)
7-7: Avoid uncheckedas Momentcast by aligning schema typing with theMomenttypeUsing
data.moment as Momentworks but is an unsafe cast: it assumesupdateMomentURISchemaalways produces a payload that structurally matchesMoment(collectionAddress, tokenId, chainId), without the compiler enforcing that contract. As per coding guidelines, we want strict, exact typing with minimal casts.If possible, consider typing
updateMomentURISchemaso thatz.infer<typeof updateMomentURISchema>(or themomentfield within it) is assignable toMoment, and then passdata.momentdirectly withoutas Moment. At minimum, please confirm that the schema andMomentstay in lockstep whenever either changes.Also applies to: 41-44
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
app/api/moment/update-uri/route.ts(2 hunks)hooks/useUpdateMomentURI.ts(5 hunks)lib/moment/callUpdateMomentURI.ts(3 hunks)lib/moment/updateMomentURI.ts(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- hooks/useUpdateMomentURI.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx}: Minimize code to absolute minimum needed - avoid unnecessary abstractions, intermediate steps, or redundant patterns
Write self-documenting code through precise naming (verbs for functions, nouns for variables), single-responsibility components, obvious data flow, and add short comments only when necessary
Apply Single Responsibility Principle (SRP): each function/component should have ONE clear responsibility - extract functions into separate files when they handle distinct concerns - hooks focus on state management, business logic goes in lib files - each function should be in its own file when it has a distinct purpose
Use strict TypeScript types with zero 'any' - prioritize type-exact definitions
Implement built-in security for authentication and data handling - follow secure coding practices throughout the application
Follow Next.js optimization guides for performance - implement proper caching, code splitting, and rendering strategies
Keep all files under 100 lines of code to maintain readability and follow single responsibility principle - split hooks/components when they grow too large or handle multiple concerns
Before coding, make a plan inside a tag: identify core requirement, consider 3 implementation approaches, choose simplest that meets needs, verify if code can be split into smaller functions, check for unnecessary abstractions, and ensure clarity for junior developers
Files:
lib/moment/updateMomentURI.tsapp/api/moment/update-uri/route.tslib/moment/callUpdateMomentURI.ts
lib/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
Library files should contain pure business logic, data transformation, validation, and API calls - never include React state management or UI concerns
Files:
lib/moment/updateMomentURI.tslib/moment/callUpdateMomentURI.ts
🧬 Code graph analysis (3)
lib/moment/updateMomentURI.ts (2)
types/moment.ts (1)
Moment(4-8)lib/coinbase/getOrCreateSmartWallet.ts (1)
getOrCreateSmartWallet(6-19)
app/api/moment/update-uri/route.ts (1)
types/moment.ts (1)
Moment(4-8)
lib/moment/callUpdateMomentURI.ts (1)
types/moment.ts (1)
Moment(4-8)
…o techengme/myc-3542-moment-page-using-new-supabase-table
Summary by CodeRabbit
New Features
Refactor
Bug Fixes
✏️ Tip: You can customize this high-level summary in your review settings.