Skip to content

migrate#177

Merged
techeng322 merged 4 commits intomainfrom
techengme/myc-4635-cron-migration-zora-media-envio-events-to-supabase
Apr 16, 2026
Merged

migrate#177
techeng322 merged 4 commits intomainfrom
techengme/myc-4635-cron-migration-zora-media-envio-events-to-supabase

Conversation

@techeng322
Copy link
Copy Markdown
Collaborator

@techeng322 techeng322 commented Apr 16, 2026

Summary by CodeRabbit

New Features

  • Added support for indexing and managing Zora Media moments and admins alongside existing sources.
  • Enhanced moment data handling with metadata URI support for richer content tracking and owner attribution.
  • Extended batch processing pipeline to accommodate new data types.

Tests

  • Added comprehensive test coverage for new data type handling and utilities.

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 16, 2026

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

Project Deployment Actions Updated (UTC)
in-process-api Ready Ready Preview Apr 16, 2026 7:31pm

Request Review

@supabase
Copy link
Copy Markdown

supabase bot commented Apr 16, 2026

Updates to Preview Branch (techengme/myc-4635-cron-migration-zora-media-envio-events-to-supabase) ↗︎

Deployments Status Updated
Database Thu, 16 Apr 2026 19:31:16 UTC
Services Thu, 16 Apr 2026 19:31:16 UTC
APIs Thu, 16 Apr 2026 19:31:16 UTC

Tasks are run on every commit but only new migration files are pushed.
Close and reopen this PR if you want to apply changes from existing seed or migration files.

Tasks Status Updated
Configurations Thu, 16 Apr 2026 19:31:16 UTC
Migrations Thu, 16 Apr 2026 19:31:16 UTC
Seeding Thu, 16 Apr 2026 19:31:16 UTC
Edge Functions Thu, 16 Apr 2026 19:31:16 UTC

View logs for this Workflow Run ↗︎.
Learn more about Supabase for Git ↗︎.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 16, 2026

Warning

Rate limit exceeded

@techeng322 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 52 minutes and 40 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 52 minutes and 40 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 46cbd9d7-f993-4241-be54-0b0eb5c67bcc

📥 Commits

Reviewing files that changed from the base of the PR and between c561259 and b8c1fa1.

📒 Files selected for processing (1)
  • src/lib/supabase/migrations/20260417000001_insert_zora_media_collection.sql
📝 Walkthrough

Walkthrough

This PR extends support for two new Zora Media data types—ZoraMedia_Moments_t and ZoraMedia_Admins_t—by updating type signatures across admin and moment processing functions, adding two new indexer configurations, introducing a moment URI derivation utility, and enriching metadata mapping logic to handle optional content URI and ownership fields.

Changes

Cohort / File(s) Summary
Type Definitions
src/types/envio.ts
Added two new exported types: ZoraMedia_Moments_t (with owner, optional uri/metadata_uri, chain/timestamp metadata) and ZoraMedia_Admins_t (with admin, collection, token_id, chain, updated_at).
Admin Type Support
src/lib/admins/getScope.ts, src/lib/admins/mapAdminsForDeletion.ts, src/lib/admins/mapAdminsToSupabase.ts, src/lib/admins/processAdminsInBatches.ts
Extended function signatures to accept ZoraMedia_Admins_t alongside existing admin types. getScope now conditionally returns roles field when present, else defaults to 1.
Admin Tests
src/lib/admins/__tests__/getScope.test.ts
Added test case for ZoraMedia_Admins_t asserting getScope returns 1 when no explicit scope/permission field is set.
Admin Indexer
src/lib/indexer/zoraAdminsIndexer.ts
New indexer configuration for ZoraMedia_Admins with GraphQL query fragment filtering by updated_at, pagination, and field selection.
Moment URI Derivation
src/lib/moment/getMomentUris.ts
New utility function that builds a lookup map keyed by collection:tokenId, storing contentUri and owner for moments with metadata_uri present.
Moment Mapping
src/lib/moment/mapMomentsToSupabase.ts, src/lib/moment/processMomentsInBatches.ts
Extended signatures to accept ZoraMedia_Moments_t; mapMomentsToSupabase now conditionally uses metadata_uri when available; processMomentsInBatches enriches moments with URI/owner data via getMomentUris before metadata mapping.
Moment Metadata Processing
src/lib/moment/mapMetadataToSupabase.ts
Updated input shape to accept optional contentUri and owner; now keys artist names by owner (when present) instead of collection.creator; increased retry backoff from 500 * attempt to 1000 * attempt ms.
Supabase Return Type
src/lib/supabase/in_process_moments/upsertMoments.ts
Updated return type to include token_id and collection.address alongside existing id, uri, and collection.creator.
Moment Tests
src/lib/moment/__tests__/getMomentUris.test.ts, src/lib/moment/__tests__/mapMetadataToSupabase.test.ts, src/lib/moment/__tests__/mapMomentsToSupabase.test.ts
Added comprehensive test coverage for getMomentUris (non-Zora, Zora with/without metadata_uri), metadata mapping with contentUri/owner, and mapMomentsToSupabase with ZoraMedia_Moments_t using metadata_uri fallback logic.
Moment Indexer
src/lib/indexer/zoraMomentsIndexer.ts
New indexer configuration for ZoraMedia_Moments with GraphQL query fragment filtering by updated_at, pagination, and field selection.
Indexer Registration
src/lib/indexer/indexers.ts
Added imports and appended zoraMomentsIndexer and zoraAdminsIndexer to the exported indexers array.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A new Zora moment hops into view,
With admins and metadata—shiny and new!
URI maps flutter, ownership's clear,
Two indexers dance round the data frontier,
Enriched and precise, our pipeline takes flight! 🚀

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'migrate' is extremely vague and provides no meaningful information about what is being migrated or why. Use a more descriptive title such as 'Add Zora Media indexers and admin/moment types' or 'Migrate Zora Media admins and moments to indexer pipeline' to clearly convey the primary changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch techengme/myc-4635-cron-migration-zora-media-envio-events-to-supabase

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

❤️ Share

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

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (2)
src/lib/moment/mapMetadataToSupabase.ts (1)

49-49: Retry backoff bumped to 1s × attempt.

Max cumulative wait is ~3s per moment (1s + 2s). Given Promise.all over all moments this is fine, but for large batches with many failing URIs you'll serialize ~3s per moment in parallel. No action needed — just confirm this doesn't push cron runtime past its budget.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/moment/mapMetadataToSupabase.ts` at line 49, The retry backoff in
mapMetadataToSupabase.ts uses sleep(1000 * attempt) (so retries wait 1s then 2s)
which can cumulate ~3s per failing moment when run inside the Promise.all over
moments; verify that this increased per-item backoff doesn't push the overall
cron job past its runtime budget by (a) estimating worst-case concurrent failing
URIs given batch size and (b) running or simulating the job to confirm
average/peak runtime—if it risks overrunning, reduce the backoff multiplier in
the sleep call or implement a capped exponential backoff and/or limit
concurrency of Promise.all.
src/lib/moment/__tests__/mapMomentsToSupabase.test.ts (1)

35-95: Consider adding a test where both uri and metadata_uri are undefined.

The implementation falls back to ''. A test locking that behavior (or rejecting it, if empty URIs should be filtered upstream) would round out coverage.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/moment/__tests__/mapMomentsToSupabase.test.ts` around lines 35 - 95,
Add a test to src/lib/moment/__tests__/mapMomentsToSupabase.test.ts that passes
a Zora-like moment where both uri and metadata_uri are undefined (e.g., clone
zoraMoment with uri: undefined and metadata_uri: undefined), mock
getCollectionIdMap the same way as other tests, call
mapMomentsToSupabase([thatMoment]) and assert that the mapped result uses the
expected fallback (e.g., result[0].uri === ''), and still preserves token_id and
other fields; reference mapMomentsToSupabase and the zoraMoment test case
pattern when adding the new test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/lib/indexer/zoraAdminsIndexer.ts`:
- Around line 8-11: The selectMaxTimestampFn currently points to
selectMaxGrantedAt while the queryFragment orders/filters by updated_at, causing
a timestamp mismatch; change the selector used for indexName 'zoraAdmins' (or
replace selectMaxGrantedAt) to return the max updated_at from in_process_admins
(or create/select selectMaxUpdatedAt) so the high-water mark matches the
queryFragment's order_by/where field (updated_at), and update any references to
selectMaxTimestampFn for dataPath 'ZoraMedia_Admins' to use that updated-at
selector.

In `@src/lib/moment/__tests__/getMomentUris.test.ts`:
- Around line 61-72: The test label is misleading: the spec "uses tier + 1 as
token key for Sound moments" doesn't exercise the tier+1 branch in
getMomentUris; update the test in getMomentUris.test.ts to either rename the
it(...) description to reflect that a Sound_Moments_t without metadata_uri
yields no entries, or modify the test to include a ZoraMedia-style moment (e.g.,
a ZoraMedia_t/Media moment with a tier property and metadata_uri) so
getMomentUris([...]) actually exercises the tier + 1 keying logic; reference
getMomentUris and the existing Sound_Moments_t object when making the change.

In `@src/lib/moment/getMomentUris.ts`:
- Around line 28-38: The map key must use a lowercased collection address so
downstream lookups match; update the key creation in the for-loop where you
build the map (currently using `${moment.collection}:${tokenId}`) to normalize
the collection address with .toLowerCase() before concatenation, and set
contentUri directly from moment.uri (remove the redundant `?? undefined`),
keeping owner as-is; this change affects the map.set call inside the loop so
entries match lookups performed in processMomentsInBatches.ts and
mapMomentsToSupabase.ts.

In `@src/lib/moment/processMomentsInBatches.ts`:
- Around line 27-34: The URI enrichment can miss matches due to address-casing
mismatch: ensure keys are normalized to lowercase in both getMomentUris and when
looking up in processMomentsInBatches; update getMomentUris to build its Map
using moment.collection.toLowerCase() (or collection.address.toLowerCase() if
that field is used) and change the lookup here to use
m.collection.address.toLowerCase() when constructing the key
`${m.collection.address}:${m.token_id}` so both sides compare lowercased
addresses consistently.

In `@src/types/envio.ts`:
- Around line 169-189: mapMomentsToSupabase is feeding
mapMetadataToSupabase/getMetadataHandler with moments that have neither uri nor
metadata_uri because the current expression moment.metadata_uri ?? moment.uri ??
'' falls back to an empty string; change mapMomentsToSupabase so it filters out
any ZoraMedia_Moments_t where both moment.metadata_uri and moment.uri are
missing/empty before calling mapMetadataToSupabase (i.e., only pass moments
where at least one of metadata_uri or uri is a non-empty string), or
alternatively adjust the mapping to skip adding entries with an empty URI;
reference ZoraMedia_Moments_t, mapMomentsToSupabase, mapMetadataToSupabase and
getMetadataHandler when making this change.

---

Nitpick comments:
In `@src/lib/moment/__tests__/mapMomentsToSupabase.test.ts`:
- Around line 35-95: Add a test to
src/lib/moment/__tests__/mapMomentsToSupabase.test.ts that passes a Zora-like
moment where both uri and metadata_uri are undefined (e.g., clone zoraMoment
with uri: undefined and metadata_uri: undefined), mock getCollectionIdMap the
same way as other tests, call mapMomentsToSupabase([thatMoment]) and assert that
the mapped result uses the expected fallback (e.g., result[0].uri === ''), and
still preserves token_id and other fields; reference mapMomentsToSupabase and
the zoraMoment test case pattern when adding the new test.

In `@src/lib/moment/mapMetadataToSupabase.ts`:
- Line 49: The retry backoff in mapMetadataToSupabase.ts uses sleep(1000 *
attempt) (so retries wait 1s then 2s) which can cumulate ~3s per failing moment
when run inside the Promise.all over moments; verify that this increased
per-item backoff doesn't push the overall cron job past its runtime budget by
(a) estimating worst-case concurrent failing URIs given batch size and (b)
running or simulating the job to confirm average/peak runtime—if it risks
overrunning, reduce the backoff multiplier in the sleep call or implement a
capped exponential backoff and/or limit concurrency of Promise.all.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0827b5db-2433-44be-8430-8ebc3e0557e4

📥 Commits

Reviewing files that changed from the base of the PR and between 1c6ff13 and c561259.

📒 Files selected for processing (17)
  • src/lib/admins/__tests__/getScope.test.ts
  • src/lib/admins/getScope.ts
  • src/lib/admins/mapAdminsForDeletion.ts
  • src/lib/admins/mapAdminsToSupabase.ts
  • src/lib/admins/processAdminsInBatches.ts
  • src/lib/indexer/indexers.ts
  • src/lib/indexer/zoraAdminsIndexer.ts
  • src/lib/indexer/zoraMomentsIndexer.ts
  • src/lib/moment/__tests__/getMomentUris.test.ts
  • src/lib/moment/__tests__/mapMetadataToSupabase.test.ts
  • src/lib/moment/__tests__/mapMomentsToSupabase.test.ts
  • src/lib/moment/getMomentUris.ts
  • src/lib/moment/mapMetadataToSupabase.ts
  • src/lib/moment/mapMomentsToSupabase.ts
  • src/lib/moment/processMomentsInBatches.ts
  • src/lib/supabase/in_process_moments/upsertMoments.ts
  • src/types/envio.ts

Comment on lines +8 to +11
selectMaxTimestampFn: selectMaxGrantedAt,
indexName: 'zoraAdmins',
dataPath: 'ZoraMedia_Admins',
queryFragment: `ZoraMedia_Admins(limit: $limit, offset: $offset_zoraAdmins, order_by: {updated_at: asc}, where: {updated_at: {_gt: $minTimestamp_zoraAdmins}}) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Timestamp field mismatch between selectMaxTimestampFn and queryFragment filter.

selectMaxGrantedAt reads the max granted_at from in_process_admins, but the query filters by updated_at > $minTimestamp_zoraAdmins. Because granted_at and updated_at are distinct fields (and updated_at is typically ≥ granted_at), the high-water mark will drift: on each run the filter will re-fetch rows whose updated_at is between the stored granted_at and now, causing redundant work and/or potentially missing rows depending on how granted_at is populated on upsert.

Either switch the selector to read the max updated_at (matching the order_by/where clause), or change the queryFragment to order/filter by the same field the selector returns. For consistency with the rest of the indexer registry, aligning both on updated_at is usually preferable.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/indexer/zoraAdminsIndexer.ts` around lines 8 - 11, The
selectMaxTimestampFn currently points to selectMaxGrantedAt while the
queryFragment orders/filters by updated_at, causing a timestamp mismatch; change
the selector used for indexName 'zoraAdmins' (or replace selectMaxGrantedAt) to
return the max updated_at from in_process_admins (or create/select
selectMaxUpdatedAt) so the high-water mark matches the queryFragment's
order_by/where field (updated_at), and update any references to
selectMaxTimestampFn for dataPath 'ZoraMedia_Admins' to use that updated-at
selector.

Comment on lines +61 to +72
it('uses tier + 1 as token key for Sound moments (no entry added)', () => {
const moment: Sound_Moments_t = {
id: '4',
collection: '0xCOL',
tier: 2,
uri: 'ipfs://uri',
chain_id: 8453,
created_at: 1000,
updated_at: 2000,
transaction_hash: '0xtx',
};
expect(getMomentUris([moment]).size).toBe(0);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Misleading test label.

The it(...) name says "uses tier + 1 as token key for Sound moments," but the assertion only checks that no entry is added (because Sound moments lack metadata_uri). The tier + 1 branch inside getMomentUris is never actually exercised here. Either rename the test to reflect the real assertion, or add a ZoraMedia-style moment with tier to actually cover the tier + 1 keying logic.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/moment/__tests__/getMomentUris.test.ts` around lines 61 - 72, The
test label is misleading: the spec "uses tier + 1 as token key for Sound
moments" doesn't exercise the tier+1 branch in getMomentUris; update the test in
getMomentUris.test.ts to either rename the it(...) description to reflect that a
Sound_Moments_t without metadata_uri yields no entries, or modify the test to
include a ZoraMedia-style moment (e.g., a ZoraMedia_t/Media moment with a tier
property and metadata_uri) so getMomentUris([...]) actually exercises the tier +
1 keying logic; reference getMomentUris and the existing Sound_Moments_t object
when making the change.

Comment on lines +28 to +38
for (const moment of moments) {
const tokenId =
'tier' in moment ? String(moment.tier + 1) : String(moment.token_id);
const key = `${moment.collection}:${tokenId}`;
if ('metadata_uri' in moment && moment.metadata_uri) {
map.set(key, {
contentUri: moment.uri ?? undefined,
owner: moment.owner,
});
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Key must be lowercased to match downstream lookup.

The map key is ${moment.collection}:${tokenId} with the raw Envio address, while the only consumer (processMomentsInBatches.ts line 33) looks it up with m.collection.address pulled from Supabase. Addresses in this codebase are inconsistently cased across sources and are normalized with .toLowerCase() before any comparison (see mapMomentsToSupabase.ts line 28). Without lowercasing the key here, ZoraMedia URI/owner enrichment will silently be dropped whenever casing differs.

🔒 Proposed fix
-    const key = `${moment.collection}:${tokenId}`;
+    const key = `${moment.collection.toLowerCase()}:${tokenId}`;

Minor nit on line 34: moment.uri ?? undefined is a no-op — moment.uri is already string | undefined; can simplify to contentUri: moment.uri.

As per coding guidelines: "Normalize all addresses to lowercase before comparisons using .toLowerCase()".

📝 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.

Suggested change
for (const moment of moments) {
const tokenId =
'tier' in moment ? String(moment.tier + 1) : String(moment.token_id);
const key = `${moment.collection}:${tokenId}`;
if ('metadata_uri' in moment && moment.metadata_uri) {
map.set(key, {
contentUri: moment.uri ?? undefined,
owner: moment.owner,
});
}
}
for (const moment of moments) {
const tokenId =
'tier' in moment ? String(moment.tier + 1) : String(moment.token_id);
const key = `${moment.collection.toLowerCase()}:${tokenId}`;
if ('metadata_uri' in moment && moment.metadata_uri) {
map.set(key, {
contentUri: moment.uri ?? undefined,
owner: moment.owner,
});
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/moment/getMomentUris.ts` around lines 28 - 38, The map key must use a
lowercased collection address so downstream lookups match; update the key
creation in the for-loop where you build the map (currently using
`${moment.collection}:${tokenId}`) to normalize the collection address with
.toLowerCase() before concatenation, and set contentUri directly from moment.uri
(remove the redundant `?? undefined`), keeping owner as-is; this change affects
the map.set call inside the loop so entries match lookups performed in
processMomentsInBatches.ts and mapMomentsToSupabase.ts.

Comment on lines +27 to +34
const momentUris = getMomentUris(batch);
const mappedMoments = await mapMomentsToSupabase(batch);
const upsertedMoments = await upsertMoments(mappedMoments);

const momentsWithUris = upsertedMoments.map((m) => ({
...m,
...momentUris.get(`${m.collection.address}:${m.token_id}`),
}));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

URI enrichment will silently miss entries due to address-casing mismatch.

The map is built in getMomentUris using the raw Envio moment.collection string (see src/lib/moment/getMomentUris.ts line 31), but the lookup here uses m.collection.address returned from Supabase (in_process_collections). These two sides are not guaranteed to agree on casing — elsewhere in the pipeline addresses are explicitly normalized with .toLowerCase() (e.g., mapMomentsToSupabase.ts line 28) before comparison. If the Envio address is mixed-case and the Supabase row stores the lowercase form (or vice versa), every momentUris.get(...) will return undefined and momentsWithUris will contain none of the enriched contentUri/owner values, defeating the purpose of this PR for ZoraMedia moments.

Fix by lowercasing both sides consistently. Root cause is in getMomentUris.ts; fix there and mirror here:

🔒 Proposed fix
       const momentsWithUris = upsertedMoments.map((m) => ({
         ...m,
-        ...momentUris.get(`${m.collection.address}:${m.token_id}`),
+        ...momentUris.get(`${m.collection.address.toLowerCase()}:${m.token_id}`),
       }));

As per coding guidelines: "Normalize all addresses to lowercase before comparisons using .toLowerCase()".

📝 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.

Suggested change
const momentUris = getMomentUris(batch);
const mappedMoments = await mapMomentsToSupabase(batch);
const upsertedMoments = await upsertMoments(mappedMoments);
const momentsWithUris = upsertedMoments.map((m) => ({
...m,
...momentUris.get(`${m.collection.address}:${m.token_id}`),
}));
const momentUris = getMomentUris(batch);
const mappedMoments = await mapMomentsToSupabase(batch);
const upsertedMoments = await upsertMoments(mappedMoments);
const momentsWithUris = upsertedMoments.map((m) => ({
...m,
...momentUris.get(`${m.collection.address.toLowerCase()}:${m.token_id}`),
}));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/moment/processMomentsInBatches.ts` around lines 27 - 34, The URI
enrichment can miss matches due to address-casing mismatch: ensure keys are
normalized to lowercase in both getMomentUris and when looking up in
processMomentsInBatches; update getMomentUris to build its Map using
moment.collection.toLowerCase() (or collection.address.toLowerCase() if that
field is used) and change the lookup here to use
m.collection.address.toLowerCase() when constructing the key
`${m.collection.address}:${m.token_id}` so both sides compare lowercased
addresses consistently.

Comment thread src/types/envio.ts
Comment on lines +169 to +189
export type ZoraMedia_Moments_t = {
readonly id: string;
readonly collection: string;
readonly token_id: string; // BigInt from GraphQL comes as string
readonly owner: string;
readonly uri: string | undefined;
readonly metadata_uri: string | undefined;
readonly chain_id: number;
readonly created_at: number;
readonly updated_at: number;
readonly transaction_hash: string;
};

export type ZoraMedia_Admins_t = {
readonly id: string;
readonly admin: string;
readonly collection: string;
readonly token_id: string; // BigInt from GraphQL comes as string
readonly chain_id: number;
readonly updated_at: number;
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -t f 'processMomentsInBatches.ts' | xargs cat
fd -t f 'getMomentUris.ts' | xargs cat

Repository: sweetmantech/In-Process-API

Length of output: 3061


🏁 Script executed:

fd -t f 'mapMetadataToSupabase.ts' | xargs cat

Repository: sweetmantech/In-Process-API

Length of output: 1940


🏁 Script executed:

rg -t ts 'ZoraMedia_Moments_t' -B 2 -A 2

Repository: sweetmantech/In-Process-API

Length of output: 4894


🏁 Script executed:

fd -t f 'mapMomentsToSupabase.ts' -not -path '*/__tests__/*' | xargs cat

Repository: sweetmantech/In-Process-API

Length of output: 301


🏁 Script executed:

fd -t f 'mapMomentsToSupabase.ts' -not -path '*/__tests__/*'

Repository: sweetmantech/In-Process-API

Length of output: 301


🏁 Script executed:

cat src/lib/moment/mapMomentsToSupabase.ts

Repository: sweetmantech/In-Process-API

Length of output: 1588


URI fallback in mapMomentsToSupabase does not filter moments lacking both uri and metadata_uri.

For ZoraMedia_Moments_t, moments without either field pass to mapMetadataToSupabase with uri: '' instead of being filtered upstream. The logic moment.metadata_uri ?? moment.uri ?? '' provides an empty string fallback rather than excluding such moments. This allows getMetadataHandler to be called with an empty URI, which may fail silently or cause unexpected behavior.

Moments lacking valid URIs should either be filtered before mapMetadataToSupabase is called, or getMetadataHandler should be hardened to handle empty URIs explicitly.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/types/envio.ts` around lines 169 - 189, mapMomentsToSupabase is feeding
mapMetadataToSupabase/getMetadataHandler with moments that have neither uri nor
metadata_uri because the current expression moment.metadata_uri ?? moment.uri ??
'' falls back to an empty string; change mapMomentsToSupabase so it filters out
any ZoraMedia_Moments_t where both moment.metadata_uri and moment.uri are
missing/empty before calling mapMetadataToSupabase (i.e., only pass moments
where at least one of metadata_uri or uri is a non-empty string), or
alternatively adjust the mapping to skip adding entries with an empty URI;
reference ZoraMedia_Moments_t, mapMomentsToSupabase, mapMetadataToSupabase and
getMetadataHandler when making this change.

@techeng322 techeng322 merged commit 2f47071 into main Apr 16, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant