Skip to content

Fix: Cloud Sync Not working#356

Open
Shashwat-CODING wants to merge 8 commits inton-ce:devfrom
Shashwat-CODING:dev
Open

Fix: Cloud Sync Not working#356
Shashwat-CODING wants to merge 8 commits inton-ce:devfrom
Shashwat-CODING:dev

Conversation

@Shashwat-CODING
Copy link
Contributor

@Shashwat-CODING Shashwat-CODING commented Dec 1, 2025

This PR fixes the issue where cloud sync was failing to update and fetch user data reliably.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added artist profile functionality displaying top songs and recommendations
    • Added list preview capability with shareable metadata
    • Enabled bulk track synchronization for improved data management
  • Chores

    • Optimized backend infrastructure with automated cleanup for data retention and storage efficiency

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

Migrated all cloudsync related functions to edge-functions to resolve environment issues
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 1, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Introduces three new Netlify Edge Functions for artist lookup, list preview generation, and content synchronization. Migrates three existing Netlify Functions (sync-related handlers) from serverless runtime to Edge Functions. Removes corresponding serverless function implementations.

Changes

Cohort / File(s) Summary
New Edge Functions - Data Fetching
netlify/edge-functions/artist.ts
Fetches artist data from YouTube Music API using artistId from route parameters; parses nested JSON response to extract artist name, top songs playlist, recommended artists, and featured-on playlists; returns structured JSON with type-safe TypeScript interfaces.
New Edge Functions - HTML Preview
netlify/edge-functions/listPreview.ts
Generates HTML meta tags from query string parameters (type, id); includes inline redirect script using location-based URL encoding; exposes via /list route.
Migrated Sync Functions to Edge Runtime
netlify/edge-functions/syncBulkTracks.ts, netlify/edge-functions/syncContent.ts
Moved serverless POST/GET handlers from serverless to edge runtime; validatepayloads and request methods; integrate with Netlify Blobs stores for track and content persistence; handle errors with structured JSON responses.
Migrated Scheduled Cleanup to Edge Runtime
netlify/edge-functions/syncCleanup.ts
Moved scheduled cleanup job to edge runtime with two-phase retention workflow: (1) evaluates user inactivity via lastModified metadata against 100-day threshold, deletes inactive user meta and track data; (2) removes orphaned content blobs exceeding retention period; includes per-step error handling and structured logging.
Removed Serverless Functions
netlify/functions/syncBulkTracks.ts, netlify/functions/syncContent.ts, netlify/functions/syncCleanup.ts
Deleted original serverless implementations after migration to edge runtime.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • netlify/edge-functions/syncCleanup.ts: Pay close attention to retention-based deletion logic across two phases, error handling isolation per step, and blob store iteration patterns to ensure data safety.
  • netlify/edge-functions/artist.ts: Verify YouTube Music API integration, nested response parsing correctness, and error propagation from external API calls.
  • Netlify Blobs integration patterns: Confirm consistency of store initialization, error handling, and data persistence across syncBulkTracks, syncContent, and syncCleanup.
  • Runtime migration: Verify that edge function signatures, context objects, and configuration paths (path vs. route parameters) are correct and compatible with Netlify's edge runtime.

Poem

🐰 Hops through the clouds, a fleet synchronizes,
Artist and lists now preview paradise,
Edges take cleanup with retention so sweet,
No more serverless—our blobs now compete! 🎵

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix: Cloud Sync Not working' directly addresses the PR's core objective of fixing cloud sync failures, matching the primary change across multiple edge functions that replace serverless functions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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.

@n-ce
Copy link
Owner

n-ce commented Dec 1, 2025

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 1, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@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: 7

♻️ Duplicate comments (1)
netlify/edge-functions/syncCleanup.ts (1)

5-13: Same type definition issues as other files.

Duplicated types and missing comma after duration: string. See the comment on syncContent.ts for the recommended refactor to extract shared types.

🧹 Nitpick comments (8)
netlify/edge-functions/listPreview.ts (2)

5-6: Query string parsing is fragile and may not work as expected.

The parsing logic url.search.substring(1).split('=') assumes the query string format is ?type=id, but this doesn't follow standard URL query parameter conventions (?key=value). If the query is ?playlist=ABC123, this would set type = "playlist" and id = "ABC123", which seems intentional but non-standard.

Consider using URLSearchParams for more robust parsing:

-  const [type, id] = url.search.substring(1).split('=');
+  const params = new URLSearchParams(url.search);
+  const type = params.keys().next().value || '';
+  const id = params.get(type) || '';

Or if specific parameters are expected:

const type = params.get('type') || '';
const id = params.get('id') || '';

22-22: Prefer encodeURIComponent over encodeURI for query parameters.

encodeURI does not encode characters like &, =, +, which could break URL parsing. Use encodeURIComponent for encoding values that will be used in query parameters.

-<script>location.replace('/?e=' + encodeURI(location.pathname + location.search))</script></html>
+<script>location.replace('/?e=' + encodeURIComponent(location.pathname + location.search))</script></html>
netlify/edge-functions/syncBulkTracks.ts (1)

61-66: Consider reporting skipped tracks to aid debugging.

Tracks without a valid id are silently skipped. While this prevents failures, it may hide data quality issues from the client. Consider including a count of skipped tracks in the response.

+        let skippedCount = 0;
         // Update or add tracks
         for (const track of addedTrackItems) {
             if (track && track.id) {
                 userTracks[track.id] = track;
+            } else {
+                skippedCount++;
             }
         }
         ...
         return new Response(JSON.stringify({
-            message: `Successfully synced ${addedTrackItems.length} tracks for user ${userId}`
+            message: `Successfully synced ${addedTrackItems.length - skippedCount} tracks for user ${userId}`,
+            skipped: skippedCount
         }), {
netlify/edge-functions/artist.ts (2)

93-104: Consider adding timeout and caching for external API calls.

The fetch to YouTube Music API has no timeout, which could cause the edge function to hang. Also, artist data is relatively stable and could benefit from caching to reduce API load.

-  return fetch(YOUTUBE_MUSIC_API_URL, {
+  const controller = new AbortController();
+  const timeoutId = setTimeout(() => controller.abort(), 10000); // 10s timeout
+
+  return fetch(YOUTUBE_MUSIC_API_URL, {
     method: 'POST',
     headers: {
       'Content-Type': 'application/json',
     },
     body: JSON.stringify(requestBody),
+    signal: controller.signal,
   })
     .then((response) => {
+      clearTimeout(timeoutId);
       if (!response.ok) {

163-166: Inconsistent config formatting compared to other edge functions.

The config object has inconsistent indentation compared to the patterns in other edge functions like listPreview.ts and syncBulkTracks.ts.

 export const config: Config = {
-    path: '/artist/:id',
-    };
+  path: '/artist/:id',
+};
netlify/edge-functions/syncContent.ts (2)

17-26: Consider using Context.params instead of manual URL parsing.

Other edge functions like syncBulkTracks.ts use context.params to extract route parameters. This function manually parses the URL path, which is less robust and inconsistent with the codebase pattern.

-export default async (req: Request): Promise<Response> => {
+export default async (req: Request, context: Context): Promise<Response> => {
     // GET: Retrieve content by timestamp
     if (req.method === 'GET') {
-        const url = new URL(req.url);
-        const pathParts = url.pathname.split('/');
-        const timestamp = pathParts[pathParts.length - 1];
+        const timestamp = context.params.timestamp;

         if (!timestamp) {
             return new Response('Timestamp is required', { status: 400 });
         }

Also update the import:

-import type { Config } from "@netlify/edge-functions";
+import type { Config, Context } from "@netlify/edge-functions";

28-42: Duplicated store initialization error handling.

The store initialization try-catch block is duplicated for GET and POST handlers. Consider extracting to a helper function.

const getContentStore = () => {
  try {
    return { store: getStore('content'), error: null };
  } catch (storeError) {
    console.error("Failed to initialize content store:", storeError);
    return { 
      store: null, 
      error: new Response(JSON.stringify({
        error: 'Netlify Blobs configuration error',
        details: 'Could not initialize "content" store.',
        rawError: String(storeError)
      }), {
        status: 500,
        headers: { 'Content-Type': 'application/json' }
      })
    };
  }
};

Also applies to: 78-91

netlify/edge-functions/syncCleanup.ts (1)

42-76: Consider batching deletions to avoid timeouts on large datasets.

The cleanup iterates through all blobs sequentially with individual delete operations. For large datasets, this could exceed edge function time limits. Consider batching or using Promise.all for parallel deletions.

// Example: Batch deletions in parallel chunks
const BATCH_SIZE = 10;
const blobsToDelete = userMetaBlobs.filter(/* inactive criteria */);

for (let i = 0; i < blobsToDelete.length; i += BATCH_SIZE) {
  const batch = blobsToDelete.slice(i, i + BATCH_SIZE);
  await Promise.all(batch.map(blob => Promise.all([
    metaStore.delete(blob.key),
    trackStore.delete(blob.key)
  ])));
}

Also applies to: 85-97

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a7083ae and 572fab0.

📒 Files selected for processing (8)
  • netlify/edge-functions/artist.ts (1 hunks)
  • netlify/edge-functions/listPreview.ts (1 hunks)
  • netlify/edge-functions/syncBulkTracks.ts (1 hunks)
  • netlify/edge-functions/syncCleanup.ts (1 hunks)
  • netlify/edge-functions/syncContent.ts (1 hunks)
  • netlify/functions/syncBulkTracks.ts (0 hunks)
  • netlify/functions/syncCleanup.ts (0 hunks)
  • netlify/functions/syncContent.ts (0 hunks)
💤 Files with no reviewable changes (3)
  • netlify/functions/syncBulkTracks.ts
  • netlify/functions/syncCleanup.ts
  • netlify/functions/syncContent.ts
🧰 Additional context used
🧬 Code graph analysis (4)
netlify/edge-functions/listPreview.ts (5)
netlify/edge-functions/artist.ts (1)
  • config (164-166)
netlify/edge-functions/syncBulkTracks.ts (1)
  • config (89-91)
netlify/edge-functions/syncCleanup.ts (1)
  • config (123-125)
netlify/edge-functions/syncContent.ts (1)
  • config (118-120)
netlify/edge-functions/linkPreview.ts (1)
  • config (42-44)
netlify/edge-functions/syncBulkTracks.ts (4)
netlify/edge-functions/syncContent.ts (2)
  • req (17-116)
  • config (118-120)
netlify/edge-functions/artist.ts (1)
  • config (164-166)
netlify/edge-functions/listPreview.ts (1)
  • config (28-30)
netlify/edge-functions/syncCleanup.ts (1)
  • config (123-125)
netlify/edge-functions/syncCleanup.ts (4)
netlify/edge-functions/artist.ts (1)
  • config (164-166)
netlify/edge-functions/listPreview.ts (1)
  • config (28-30)
netlify/edge-functions/syncBulkTracks.ts (1)
  • config (89-91)
netlify/edge-functions/syncContent.ts (1)
  • config (118-120)
netlify/edge-functions/syncContent.ts (2)
netlify/edge-functions/syncBulkTracks.ts (2)
  • req (21-87)
  • config (89-91)
netlify/edge-functions/blobs.ts (2)
  • req (5-42)
  • config (45-47)
🔇 Additional comments (2)
netlify/edge-functions/syncBulkTracks.ts (1)

21-86: LGTM: Solid error handling and validation.

The function has comprehensive validation (method, body, userId, payload structure) and properly structured error responses with appropriate status codes. The nested try-catch for store initialization is a good pattern for distinguishing configuration errors from runtime errors.

netlify/edge-functions/syncCleanup.ts (1)

21-109: Good structured cleanup logic with comprehensive logging.

The two-phase approach (user retention, content cleanup) is well-organized with clear logging for debugging. Error handling prevents a single failure from aborting the entire cleanup cycle.

Comment on lines 82 to 91
const requestBody = {
browseId: artistId,
context: {
client: {
clientName: 'WEB_REMIX',
clientVersion: '1.20250915.03.00',
gl: countryCode,
},
},
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

YouTube Music API clientVersion requirements 2024 2025 outdated

💡 Result:

Short answer: YouTube Music's undocumented "innertube" API requires a current clientName/clientVersion in requests; these values are time-sensitive and Google can and does change/validate them, so using an outdated clientVersion often causes requests to fail or return degraded data. Keep clientVersion matched to a recent official YouTube/YouTube Music app build (or use the official YouTube Data API where possible) and monitor YouTube's developer revision history for breaking changes. [1][2]

Sources:

  • YouTube API Services — Required Minimum Functionality (notes about API client identity/identification and that requirements change). [1]
  • Public reverse-engineered clients / code examples showing innertube clientVersion strings used for YouTube Music/YouTube requests (examples of how clientVersion is set and updated). [2]

Hardcoded clientVersion should be externalized or regularly updated.

The clientVersion: '1.20250915.03.00' is hardcoded and YouTube Music's innertube API validates client versions; outdated versions cause requests to fail or return degraded data. Either move this to configuration, implement version detection from the YouTube app, or establish a process to update it when YouTube requires newer versions.

🤖 Prompt for AI Agents
In netlify/edge-functions/artist.ts around lines 82 to 91, the clientVersion
value is hardcoded which will break when YouTube changes/validates versions;
replace the literal with a configurable value (read from an environment variable
or a shared config file), add a sensible default/fallback and a short validation
check (e.g., non-empty string and pattern) so failures surface quickly, and
document/update the repo README or config doc with the process for keeping
clientVersion current (or implement an automated fetch/upgrade step) so
maintainers can update it when YouTube requires a newer version.

Comment on lines 106 to 116
.then((data: ResponseData) => {
const contents = data.contents.singleColumnBrowseResultsRenderer.tabs[0].tabRenderer.content.sectionListRenderer.contents;

const artistName = data.header.musicImmersiveHeaderRenderer.title.runs[0].text;

const topSongsShelf = contents.find(
(item): item is MusicShelfRendererContainer =>
'musicShelfRenderer' in item &&
item.musicShelfRenderer.title.runs[0].text === 'Top songs'
);
const playlistId = topSongsShelf?.musicShelfRenderer.contents[0].musicResponsiveListItemRenderer.flexColumns[0].musicResponsiveListItemFlexColumnRenderer.text.runs[0].navigationEndpoint?.watchEndpoint.playlistId;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential null pointer exceptions from deeply nested access.

The response parsing accesses deeply nested properties without null checks. If the YouTube API response structure changes or returns incomplete data, this will throw runtime errors instead of returning gracefully.

Add optional chaining throughout the parsing logic:

-      const contents = data.contents.singleColumnBrowseResultsRenderer.tabs[0].tabRenderer.content.sectionListRenderer.contents;
-      const artistName = data.header.musicImmersiveHeaderRenderer.title.runs[0].text;
+      const contents = data.contents?.singleColumnBrowseResultsRenderer?.tabs?.[0]?.tabRenderer?.content?.sectionListRenderer?.contents;
+      const artistName = data.header?.musicImmersiveHeaderRenderer?.title?.runs?.[0]?.text;
+
+      if (!contents || !artistName) {
+        return new Response(JSON.stringify({ error: 'Unexpected API response structure' }), {
+          status: 502,
+          headers: { 'content-type': 'application/json' },
+        });
+      }
🤖 Prompt for AI Agents
In netlify/edge-functions/artist.ts around lines 106 to 116, the code performs
deeply nested property access on the YouTube response which can throw if any
node is missing; update the parsing to use optional chaining and nullish
coalescing and add guards: replace direct property chains with optional chaining
(?.) and provide safe defaults (?? []) or undefined where appropriate, check
that contents and arrays exist and have expected length before indexing, verify
topSongsShelf is truthy before accessing its musicShelfRenderer.contents[0], and
treat playlistId extraction with optional chaining so the function returns
gracefully when fields are absent.

Comment on lines 7 to 22
return new Response(`
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="description"
content="View ${type} in ytify">
<meta name="author" content="n-ce">
<meta property="og:type" content="website">
<meta property="og:title" content="${type} | ytify">
<meta property="og:url" content="https://ytify.pp.ua">
<meta property="og:site_name" content="ytify">
<meta property="og:description" content="View ${id} - ${type} in ytify">
<title>${type} | ytify</title>
</head>
<script>location.replace('/?e=' + encodeURI(location.pathname + location.search))</script></html>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

XSS vulnerability: User input is directly interpolated into HTML without sanitization.

The type and id values from the query string are directly embedded into HTML meta tags and content. A malicious query like ?"><script>alert(1)</script>=test could inject arbitrary HTML/JavaScript.

Sanitize or escape the values before embedding in HTML:

+const escapeHtml = (str: string) => 
+  str.replace(/&/g, '&amp;')
+     .replace(/</g, '&lt;')
+     .replace(/>/g, '&gt;')
+     .replace(/"/g, '&quot;')
+     .replace(/'/g, '&#039;');
+
+const safeType = escapeHtml(type);
+const safeId = escapeHtml(id);
+
 return new Response(`     
 <!doctype html>
 <html lang="en">
 <head>
   <meta charset="UTF-8">
   <meta name="description"
-    content="View ${type} in ytify">
+    content="View ${safeType} in ytify">
   ...

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +5 to +13
type CollectionItem = {
id: string,
title: string,
author: string,
duration: string
authorId: string,
albumId?: string,
plays?: number
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Missing comma in type definition causes syntax error.

There's a missing comma after duration: string on line 9, which would cause a TypeScript compilation error.

 type CollectionItem = {
     id: string,
     title: string,
     author: string,
-    duration: string
+    duration: string,
     authorId: string,
     albumId?: string,
     plays?: number
 }
📝 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
type CollectionItem = {
id: string,
title: string,
author: string,
duration: string
authorId: string,
albumId?: string,
plays?: number
}
type CollectionItem = {
id: string,
title: string,
author: string,
duration: string,
authorId: string,
albumId?: string,
plays?: number
}
🤖 Prompt for AI Agents
In netlify/edge-functions/syncBulkTracks.ts around lines 5 to 13, the TypeScript
type CollectionItem is missing a comma after the property declaration duration:
string which causes a compilation syntax error; fix it by adding a trailing
comma after duration: string so the property list is properly separated (then
re-run type checking to confirm the error is resolved).

Comment on lines +25 to +27
// Access the relevant stores
const metaStore = getStore('meta');
const trackStore = getStore('tracks');
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Store initialization outside try-catch could cause unhandled exceptions.

The metaStore and trackStore are initialized outside the main try-catch block. If getStore throws (e.g., Netlify Blobs not configured), the function will crash without returning a proper error response.

+    let metaStore, trackStore;
+    try {
+        metaStore = getStore('meta');
+        trackStore = getStore('tracks');
+    } catch (storeError) {
+        console.error("Failed to initialize stores:", storeError);
+        return new Response(JSON.stringify({
+            error: 'Netlify Blobs configuration error',
+            details: 'Could not initialize required stores.',
+            rawError: String(storeError)
+        }), {
+            status: 500,
+            headers: { 'Content-Type': 'application/json' }
+        });
+    }
+
-    // Access the relevant stores
-    const metaStore = getStore('meta');
-    const trackStore = getStore('tracks');
📝 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
// Access the relevant stores
const metaStore = getStore('meta');
const trackStore = getStore('tracks');
let metaStore, trackStore;
try {
metaStore = getStore('meta');
trackStore = getStore('tracks');
} catch (storeError) {
console.error("Failed to initialize stores:", storeError);
return new Response(JSON.stringify({
error: 'Netlify Blobs configuration error',
details: 'Could not initialize required stores.',
rawError: String(storeError)
}), {
status: 500,
headers: { 'Content-Type': 'application/json' }
});
}
🤖 Prompt for AI Agents
In netlify/edge-functions/syncCleanup.ts around lines 25 to 27, the calls to
getStore('meta') and getStore('tracks') are created outside the main try-catch
and can throw, causing an unhandled crash; move those getStore calls into the
try block (or wrap them in their own try/catch) so any exceptions are caught and
return a proper error response (e.g., log the error and return a 500/appropriate
Response) instead of letting the function crash.

Comment on lines +29 to +30
// Array to collect track maps from active users for the GC check
const activeUserTrackMaps: Collection[] = [];
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

activeUserTrackMaps is collected but never used.

The array activeUserTrackMaps is populated with track maps from active users, but it's never used after collection. The comment mentions "GC reference" but no garbage collection logic consumes this data.

Either remove the dead code or implement the intended GC logic:

-    // Array to collect track maps from active users for the GC check
-    const activeUserTrackMaps: Collection[] = [];
     ...
-            // Collect all track references from the user's collections
-            try {
-                // Fetch the user's track map for GC reference
-                const userTrackMap: Collection = await trackStore.get(userIdHash, { type: 'json' }) || {};
-                if (userTrackMap) {
-                    activeUserTrackMaps.push(userTrackMap);
-                }
-
-            } catch (error) {
-                console.error(`Could not process track map for active user ${userIdHash}.`, error);
-            }

Also applies to: 66-75

🤖 Prompt for AI Agents
In netlify/edge-functions/syncCleanup.ts around lines 29-30 (and similarly lines
66-75), the activeUserTrackMaps array is being built but never used; either
remove the dead variable and the pushes that populate it, or implement the
intended GC retention logic by using the collected track maps during the
garbage-collection check (e.g., pass activeUserTrackMaps to the GC routine or
hold references while computing live vs. collectible tracks), and ensure any
dependent code (comments, function signatures) is updated to reflect the chosen
approach.

Comment on lines +5 to +15
type CollectionItem = {
id: string,
title: string,
author: string,
duration: string
authorId: string,
albumId?: string,
plays?: number
}

type Collection = { [index: string]: CollectionItem };
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Duplicated type definitions across edge functions.

CollectionItem and Collection types are duplicated in syncBulkTracks.ts, syncContent.ts, and syncCleanup.ts. This violates DRY and risks divergence. Also, there's a missing comma after duration: string on line 9.

Extract shared types to a common module:

// netlify/edge-functions/types.ts
export type CollectionItem = {
    id: string,
    title: string,
    author: string,
    duration: string,  // Note: add missing comma
    authorId: string,
    albumId?: string,
    plays?: number
}

export type Collection = { [index: string]: CollectionItem };

Then import in each file:

import type { Collection, CollectionItem } from './types';
🤖 Prompt for AI Agents
In netlify/edge-functions/syncContent.ts around lines 5 to 15, the
CollectionItem and Collection type definitions are duplicated across multiple
edge-function files and the CollectionItem type is missing a comma after
duration: string; extract these shared types into a new module
netlify/edge-functions/types.ts exporting CollectionItem (with the missing comma
added) and Collection, then remove the local type definitions in syncContent.ts
and replace them with an import line: import type { Collection, CollectionItem }
from './types'; ensure other files (syncBulkTracks.ts, syncCleanup.ts) do the
same to avoid duplication.

n-ce and others added 3 commits December 2, 2025 14:39
This implementation provides a search handler for the YouTube Music API, enabling users to search for music content based on various parameters. It includes error handling and supports filters for different types of media.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants