mirror of
https://github.com/jjbrunton/Sauci.git
synced 2026-10-31 18:19:43 +00:00
- Add design guidelines to CLAUDE.md - Redesign navigation with boutique styling - Add video support to chat with compression - Update matches/dares/quiz screens with gold/rose accents - Improve packs browsing with category tabs - Add SwipeCardPremium component - Update theme with premium color palette - Add video cleanup edge function and migration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
92 lines
3.3 KiB
TypeScript
92 lines
3.3 KiB
TypeScript
import "jsr:@supabase/functions-js/edge-runtime.d.ts";
|
|
import { createClient } from "jsr:@supabase/supabase-js@2";
|
|
|
|
/**
|
|
* Cleanup expired videos from storage.
|
|
* This function is called by pg_cron daily at 3 AM UTC.
|
|
* It finds videos where media_expires_at has passed, deletes the files from storage,
|
|
* and marks the messages as expired.
|
|
*/
|
|
Deno.serve(async (req) => {
|
|
// Only allow POST requests (from cron) or GET (for manual testing)
|
|
if (req.method !== "POST" && req.method !== "GET") {
|
|
return new Response("Method not allowed", { status: 405 });
|
|
}
|
|
|
|
const supabase = createClient(
|
|
Deno.env.get("SUPABASE_URL")!,
|
|
Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!
|
|
);
|
|
|
|
try {
|
|
// Get expired videos that still have files
|
|
const { data: expiredVideos, error: fetchError } = await supabase
|
|
.from("messages")
|
|
.select("id, media_path")
|
|
.eq("media_type", "video")
|
|
.eq("media_expired", false)
|
|
.not("media_path", "is", null)
|
|
.lt("media_expires_at", new Date().toISOString());
|
|
|
|
if (fetchError) {
|
|
console.error("Error fetching expired videos:", fetchError);
|
|
return new Response(
|
|
JSON.stringify({ error: fetchError.message }),
|
|
{ status: 500, headers: { "Content-Type": "application/json" } }
|
|
);
|
|
}
|
|
|
|
if (!expiredVideos || expiredVideos.length === 0) {
|
|
return new Response(
|
|
JSON.stringify({ deleted: 0, message: "No expired videos found" }),
|
|
{ headers: { "Content-Type": "application/json" } }
|
|
);
|
|
}
|
|
|
|
// Delete files from storage
|
|
const paths = expiredVideos.map((v) => v.media_path).filter(Boolean) as string[];
|
|
|
|
if (paths.length > 0) {
|
|
const { error: storageError } = await supabase.storage
|
|
.from("chat-media")
|
|
.remove(paths);
|
|
|
|
if (storageError) {
|
|
console.error("Error deleting from storage:", storageError);
|
|
// Continue anyway to mark as expired - files may already be deleted
|
|
}
|
|
}
|
|
|
|
// Mark messages as expired
|
|
const ids = expiredVideos.map((v) => v.id);
|
|
const { error: updateError } = await supabase
|
|
.from("messages")
|
|
.update({ media_expired: true, media_path: null })
|
|
.in("id", ids);
|
|
|
|
if (updateError) {
|
|
console.error("Error marking messages as expired:", updateError);
|
|
return new Response(
|
|
JSON.stringify({ error: updateError.message }),
|
|
{ status: 500, headers: { "Content-Type": "application/json" } }
|
|
);
|
|
}
|
|
|
|
console.log(`Cleaned up ${expiredVideos.length} expired videos`);
|
|
|
|
return new Response(
|
|
JSON.stringify({
|
|
deleted: expiredVideos.length,
|
|
paths: paths,
|
|
}),
|
|
{ headers: { "Content-Type": "application/json" } }
|
|
);
|
|
} catch (err) {
|
|
console.error("Unexpected error:", err);
|
|
return new Response(
|
|
JSON.stringify({ error: "Internal server error" }),
|
|
{ status: 500, headers: { "Content-Type": "application/json" } }
|
|
);
|
|
}
|
|
});
|