@@ -25,14 +25,31 @@ function requireSupabase() {
2525}
2626
2727/** Resuelve URLs firmadas en lote para varios paths de una vez (1h de validez). */
28+ // media_url puede ser un path de Storage (fotos propias de cuenta, bucket
29+ // privado course-section-images) O una ruta pública de assets estáticos del
30+ // propio despliegue (esquemas genéricos de Folvy, /formacion/*.svg servidos
31+ // por Vercel desde public/) — estas últimas se devuelven TAL CUAL, sin pasar
32+ // por Storage: createSignedUrls fallaría porque el objeto no vive ahí.
33+ function isPublicUrl ( path : string ) : boolean {
34+ return path . startsWith ( '/' ) || path . startsWith ( 'http://' ) || path . startsWith ( 'https://' )
35+ }
36+
2837export async function getSignedSectionImageUrls ( paths : string [ ] ) : Promise < Record < string , string > > {
29- const sb = requireSupabase ( )
3038 const unique = Array . from ( new Set ( paths . filter ( Boolean ) ) )
3139 if ( unique . length === 0 ) return { }
32- const { data, error } = await sb . storage . from ( SECTION_IMAGES_BUCKET ) . createSignedUrls ( unique , 3600 )
33- if ( error ) { console . error ( '[courseImagesService] getSignedSectionImageUrls' , error ) ; return { } }
40+
3441 const map : Record < string , string > = { }
35- ; ( data ?? [ ] ) . forEach ( ( d , i ) => { if ( d . signedUrl ) map [ unique [ i ] ] = d . signedUrl } )
42+ const storagePaths : string [ ] = [ ]
43+ for ( const p of unique ) {
44+ if ( isPublicUrl ( p ) ) map [ p ] = p
45+ else storagePaths . push ( p )
46+ }
47+ if ( storagePaths . length === 0 ) return map
48+ if ( ! supabase ) return map
49+
50+ const { data, error } = await supabase . storage . from ( SECTION_IMAGES_BUCKET ) . createSignedUrls ( storagePaths , 3600 )
51+ if ( error ) { console . error ( '[courseImagesService] getSignedSectionImageUrls' , error ) ; return map }
52+ ; ( data ?? [ ] ) . forEach ( ( d , i ) => { if ( d . signedUrl ) map [ storagePaths [ i ] ] = d . signedUrl } )
3653 return map
3754}
3855
0 commit comments