Bug (diagnosed by backyard, see project_session_2026-05-15_push.md): - Manual `supabase.realtime.setAuth()` calls in subscribe-hooks set `_manuallySetToken=true` internally, blocking the automatic token-refresh on heartbeat. After ~1h the cached access_token expires → Postgres-Changes silently stop arriving (channel still shows "joined" but no events). - Plus: no AppState handler → no Foreground-Reconnect trigger after Background-kill of WebSocket. Fix A — lib/supabase.ts: createClient now passes a `realtime.accessToken` async callback that returns the current session token. Heartbeat picks fresh tokens automatically, no manual setAuth needed. Fix A — all 5 manual `supabase.realtime.setAuth()` calls removed from useChatRealtime, useCommunityRealtime, useDomainSubmissionRealtime, stores/notifications. Token is handled by the callback now. Fix B — _layout.tsx: AppState listener calls supabase.auth.startAutoRefresh()/stopAutoRefresh() — official Supabase RN pattern. On Foreground-Return, onAuthStateChange fires TOKEN_REFRESHED → realtime.setAuth gets called internally. Required for upcoming Auto-Detect protected-device handshake (Realtime channel listens on protected_devices status transitions pending→active). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
38 lines
1.4 KiB
TypeScript
38 lines
1.4 KiB
TypeScript
import "react-native-url-polyfill/auto";
|
|
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
import { createClient } from "@supabase/supabase-js";
|
|
import Constants from "expo-constants";
|
|
|
|
const supabaseUrl = Constants.expoConfig?.extra?.supabaseUrl as string;
|
|
const supabaseAnonKey = Constants.expoConfig?.extra?.supabaseAnonKey as string;
|
|
|
|
if (!supabaseUrl || !supabaseAnonKey) {
|
|
throw new Error(
|
|
"Supabase URL und Anon Key müssen in app.config.ts (extra) gesetzt sein. " +
|
|
"EXPO_PUBLIC_SUPABASE_URL + EXPO_PUBLIC_SUPABASE_ANON_KEY in env.",
|
|
);
|
|
}
|
|
|
|
export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
|
|
auth: {
|
|
storage: AsyncStorage,
|
|
autoRefreshToken: true,
|
|
persistSession: true,
|
|
detectSessionInUrl: false,
|
|
},
|
|
realtime: {
|
|
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;
|
|
},
|
|
},
|
|
});
|