diff --git a/apps/rebreak-native/app/_layout.tsx b/apps/rebreak-native/app/_layout.tsx index 357a391..4be6785 100644 --- a/apps/rebreak-native/app/_layout.tsx +++ b/apps/rebreak-native/app/_layout.tsx @@ -1,4 +1,5 @@ import { useEffect } from 'react'; +import { AppState } from 'react-native'; import { Stack } from 'expo-router'; import { StatusBar } from 'expo-status-bar'; import * as Notifications from 'expo-notifications'; @@ -15,6 +16,7 @@ import { Nunito_700Bold, Nunito_800ExtraBold, } from '@expo-google-fonts/nunito'; +import { supabase } from '../lib/supabase'; import { useAuthStore } from '../stores/auth'; import { useThemeStore } from '../stores/theme'; import { useRealtimeDebugStore } from '../stores/realtimeDebug'; @@ -71,6 +73,21 @@ function RootLayoutInner() { if (__DEV__) initRealtimeDebug(); }, []); + // Supabase-Doku-Pattern für RN: Token-Auto-Refresh nur wenn App aktiv ist. + // Plus Foreground-Reconnect via onAuthStateChange (TOKEN_REFRESHED → + // realtime.setAuth wird intern getriggert). Fixt den Realtime-Disconnect-Bug + // bei lange eingeloggten Usern (siehe `project_session_2026-05-15_push.md`). + useEffect(() => { + const sub = AppState.addEventListener('change', (state) => { + if (state === 'active') { + supabase.auth.startAutoRefresh(); + } else { + supabase.auth.stopAutoRefresh(); + } + }); + return () => sub.remove(); + }, []); + useEffect(() => { if (fontsLoaded && !loading && appLockReady) { SplashScreen.hideAsync(); diff --git a/apps/rebreak-native/hooks/useChatRealtime.ts b/apps/rebreak-native/hooks/useChatRealtime.ts index e0b9934..bea6d42 100644 --- a/apps/rebreak-native/hooks/useChatRealtime.ts +++ b/apps/rebreak-native/hooks/useChatRealtime.ts @@ -22,7 +22,6 @@ export function useDmRealtime( async function subscribe() { const { data } = await supabase.auth.getSession(); if (cancelled || !data.session?.access_token) return; - supabase.realtime.setAuth(data.session.access_token); channel = supabase .channel(`dm:${partnerId}:${Date.now()}`) @@ -83,7 +82,6 @@ export function useRoomRealtime( async function subscribe() { const { data } = await supabase.auth.getSession(); if (cancelled || !data.session?.access_token) return; - supabase.realtime.setAuth(data.session.access_token); channel = supabase .channel(`room:${roomId}:${Date.now()}`) diff --git a/apps/rebreak-native/hooks/useCommunityRealtime.ts b/apps/rebreak-native/hooks/useCommunityRealtime.ts index 4238cda..3901625 100644 --- a/apps/rebreak-native/hooks/useCommunityRealtime.ts +++ b/apps/rebreak-native/hooks/useCommunityRealtime.ts @@ -29,7 +29,6 @@ export function useCommunityRealtime(enabled: boolean = true) { if (!session?.access_token) return; if (cancelled) return; - supabase.realtime.setAuth(session.access_token); const myId = session.user.id; channel = supabase diff --git a/apps/rebreak-native/hooks/useDomainSubmissionRealtime.ts b/apps/rebreak-native/hooks/useDomainSubmissionRealtime.ts index 62d2adb..79695a1 100644 --- a/apps/rebreak-native/hooks/useDomainSubmissionRealtime.ts +++ b/apps/rebreak-native/hooks/useDomainSubmissionRealtime.ts @@ -26,7 +26,6 @@ export function useDomainSubmissionRealtime( if (!session?.access_token) return; if (cancelled) return; - supabase.realtime.setAuth(session.access_token); const myId = session.user.id; channel = supabase diff --git a/apps/rebreak-native/lib/supabase.ts b/apps/rebreak-native/lib/supabase.ts index 3304a52..16ba16b 100644 --- a/apps/rebreak-native/lib/supabase.ts +++ b/apps/rebreak-native/lib/supabase.ts @@ -24,5 +24,14 @@ export const supabase = createClient(supabaseUrl, supabaseAnonKey, { params: { apikey: supabaseAnonKey, }, + // Auto-refresh Token on every heartbeat so Realtime keeps working across + // long sessions. Without this, manual setAuth() calls in subscribe-hooks + // set _manuallySetToken=true which blocks the internal token-refresh — after + // 1h the cached access_token expires and Postgres-Changes silently stop + // arriving. See `project_session_2026-05-15_push.md` for the full root-cause. + accessToken: async () => { + const { data } = await supabase.auth.getSession(); + return data.session?.access_token ?? null; + }, }, }); diff --git a/apps/rebreak-native/stores/notifications.ts b/apps/rebreak-native/stores/notifications.ts index 285e9a7..e2457b2 100644 --- a/apps/rebreak-native/stores/notifications.ts +++ b/apps/rebreak-native/stores/notifications.ts @@ -74,7 +74,6 @@ export const useNotificationStore = create((set, get) => ({ const session = data.session; if (!session?.user?.id) return; - supabase.realtime.setAuth(session.access_token); const myId = session.user.id; realtimeSub = supabase