import { useEffect } from "react"; import { supabase } from "../lib/supabase"; import type { RealtimeChannel } from "@supabase/supabase-js"; import { useDevicesStore } from "../stores/devices"; /** * Realtime-Subscription auf `rebreak.user_devices` für den eingeloggten User. * * Trigger-Fall: Die Magic-Desktop-App (Mac/Windows) ruft serverseitig * /api/magic/register → neues UserDevice-INSERT. Diese Subscription lässt die * Geräte-Liste in den Settings sofort nachladen, ohne dass der User pullt. * * Spiegelt [[useProtectedDevicesRealtime]]: publication-only (keine RLS), wir * reagieren auf jedes Event und reloaden den Store — keine Abhängigkeit von * payload.old (REPLICA IDENTITY irrelevant). */ export function useUserDevicesRealtime(enabled: boolean = true) { useEffect(() => { if (!enabled) return; let channel: RealtimeChannel | null = null; let cancelled = false; let reconnectTimer: ReturnType | null = null; async function subscribe() { const { data } = await supabase.auth.getSession(); const session = data.session; if (!session?.access_token || cancelled) return; const userId = session.user.id; channel = supabase .channel(`user-devices:${userId}:${Date.now()}`) .on( "postgres_changes", { event: "*", schema: "rebreak", table: "user_devices", filter: `user_id=eq.${userId}`, }, () => { useDevicesStore.getState().loadDevices(); }, ) .subscribe((status: string) => { if (status === "CHANNEL_ERROR" || status === "TIMED_OUT") { cleanup(); if (reconnectTimer) clearTimeout(reconnectTimer); reconnectTimer = setTimeout(() => { if (!cancelled) subscribe(); }, 3000); } }); } function cleanup() { if (channel) { supabase.removeChannel(channel); channel = null; } } subscribe(); return () => { cancelled = true; if (reconnectTimer) clearTimeout(reconnectTimer); cleanup(); }; }, [enabled]); }