import sb from "../../sb.server"; export interface UserNotifications { created_at: string; updated_at: string; user_id: number; subscription: JSON; fingerprint: string; } const subscriptionEndpoint = (subscription: JSON) => { if (typeof subscription !== "object" || subscription === null) return null; return "endpoint" in subscription && typeof subscription.endpoint === "string" && subscription.endpoint.length ? subscription.endpoint : null; }; export const getUserSubscription = async (userId: number) => await sb.from("user_notifications").select("*").eq("user_id", userId); export const getUserSubscriptions = async () => { const { data, error } = await sb.from("user_notifications").select("*"); if (error) return []; return data as UserNotifications[]; }; export const deleteUserSubscription = async ( userId: number, fingerprint: string, ) => await sb .from("user_notifications") .delete() .eq("user_id", userId) .eq("fingerprint", fingerprint); export const setUserSubscription = async ( userId: number, subscription: JSON, fingerprint: string, ) => { const endpoint = subscriptionEndpoint(subscription); if (endpoint) { const { data } = await sb .from("user_notifications") .select("fingerprint, subscription") .eq("user_id", userId); const staleFingerprints = data ?.filter( (existing) => existing.fingerprint !== fingerprint && subscriptionEndpoint(existing.subscription as JSON) === endpoint, ) .map((existing) => existing.fingerprint) ?? []; await Promise.all( staleFingerprints.map(async (staleFingerprint) => { await deleteUserSubscription(userId, staleFingerprint); }), ); } return await sb.from("user_notifications").upsert( { user_id: userId, updated_at: new Date().toISOString(), subscription: subscription, fingerprint, }, { onConflict: "user_id,fingerprint" }, ); };