@adventurelabs/scout-core
Version:
Core utilities and helpers for Adventure Labs Scout applications
99 lines (98 loc) • 3.95 kB
JavaScript
"use server";
import { newServerClient } from "../supabase/server";
import { BUCKET_NAME_SCOUT } from "../constants/db";
/**
* Generates a signed URL for a file in Supabase storage
* @param filePath - The path to the file in storage (e.g., "events/123/image.jpg")
* @param expiresIn - Number of seconds until the URL expires (default: 3600 = 1 hour)
* @param supabaseClient - Optional Supabase client (will create new one if not provided)
* @returns Promise<string | null> - The signed URL or null if error
*/
export async function generateSignedUrl(filePath, expiresIn = 3600, supabaseClient) {
try {
const supabase = supabaseClient || (await newServerClient());
const { data, error } = await supabase.storage
.from(BUCKET_NAME_SCOUT)
.createSignedUrl(filePath, expiresIn);
if (error) {
console.error("Error generating signed URL:", error.message);
return null;
}
return data.signedUrl;
}
catch (error) {
console.error("Error in generateSignedUrl:", error);
return null;
}
}
export async function generateSignedUrlsBatch(filePaths, expiresIn = 3600, supabaseClient) {
try {
const supabase = supabaseClient || (await newServerClient());
const urlMap = new Map();
const signedUrlPromises = filePaths.map(async (filePath) => {
try {
const { data, error } = await supabase.storage
.from(BUCKET_NAME_SCOUT)
.createSignedUrl(filePath, expiresIn);
if (error) {
console.error(`Error generating signed URL for ${filePath}:`, error.message);
return { filePath, signedUrl: null };
}
return { filePath, signedUrl: data.signedUrl };
}
catch (error) {
console.error(`Error in generateSignedUrl for ${filePath}:`, error);
return { filePath, signedUrl: null };
}
});
const results = await Promise.all(signedUrlPromises);
results.forEach(({ filePath, signedUrl }) => {
urlMap.set(filePath, signedUrl);
});
return urlMap;
}
catch (error) {
console.error("Error in generateSignedUrlsBatch:", error);
return new Map();
}
}
export async function addSignedUrlsToEventsBatch(events, supabaseClient) {
const filePaths = events
.map((event) => event.file_path)
.filter((path) => path)
.filter((path, index, array) => array.indexOf(path) === index);
if (filePaths.length === 0) {
return events;
}
const urlMap = await generateSignedUrlsBatch(filePaths, 3600, supabaseClient);
return events.map((event) => {
if (event.file_path && urlMap.has(event.file_path)) {
const signedUrl = urlMap.get(event.file_path);
return {
...event,
media_url: signedUrl || event.media_url,
};
}
return event;
});
}
export async function addSignedUrlsToEvents(events, supabaseClient) {
return addSignedUrlsToEventsBatch(events, supabaseClient);
}
/**
* Generates a signed URL for a single event and sets it as media_url
* @param event - Event object that may have file_path
* @param supabaseClient - Optional Supabase client (will create new one if not provided)
* @returns Promise<Object> - Event with signed URL set as media_url
*/
export async function addSignedUrlToEvent(event, supabaseClient) {
// If event has a file_path, generate a signed URL and set it as media_url
if (event.file_path) {
const signedUrl = await generateSignedUrl(event.file_path, 3600, supabaseClient);
return {
...event,
media_url: signedUrl || event.media_url, // Fall back to existing media_url if signed URL fails
};
}
return event;
}