Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export async function enablePushNotifications(
kind: 'http' as const,
app_id: clientConfig.pushNotificationDetails?.webPushAppID,
pushkey: keys.p256dh,
app_display_name: 'Cinny',
app_display_name: 'Sable',
device_display_name: 'This Browser',
lang: navigator.language || 'en',
data: {
Expand Down Expand Up @@ -104,7 +104,7 @@ export async function enablePushNotifications(
kind: 'http' as const,
app_id: clientConfig.pushNotificationDetails?.webPushAppID,
pushkey: keys.p256dh,
app_display_name: 'Cinny',
app_display_name: 'Sable',
device_display_name:
(await mx.getDevice(mx.getDeviceId() ?? '')).display_name ?? 'Unknown Device',
lang: navigator.language || 'en',
Expand Down
26 changes: 24 additions & 2 deletions src/app/pages/client/ClientRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ export function ClientRoot({ children }: ClientRootProps) {
log.log('initClient for', activeSession.userId);
const newMx = await initClient(activeSession);
loadedUserIdRef.current = activeSession.userId;
pushSessionToSW(activeSession.baseUrl, activeSession.accessToken);
pushSessionToSW(activeSession.baseUrl, activeSession.accessToken, activeSession.userId);
return newMx;
}, [activeSession, activeSessionId, setActiveSessionId])
);
Expand Down Expand Up @@ -234,7 +234,7 @@ export function ClientRoot({ children }: ClientRootProps) {
activeSession.userId,
'— reloading client'
);
pushSessionToSW(activeSession.baseUrl, activeSession.accessToken);
pushSessionToSW(activeSession.baseUrl, activeSession.accessToken, activeSession.userId);
if (mx?.clientRunning) {
stopClient(mx);
}
Expand All @@ -259,6 +259,28 @@ export function ClientRoot({ children }: ClientRootProps) {
useLogoutListener(mx);
useAppVisibility(mx);

// Keep the SW session warm so media fetches and push notifications work
// reliably after iOS kills and restarts the SW in the background.
// - Immediate resync whenever the tab comes back to the foreground.
// - Periodic heartbeat (10 min) keeps the persisted session up to date
// while the app is running.
const swSessionBaseUrl = activeSession?.baseUrl;
const swSessionAccessToken = activeSession?.accessToken;
const swSessionUserId = activeSession?.userId;
useEffect(() => {
if (!swSessionBaseUrl || !swSessionAccessToken) return undefined;
const resync = () => pushSessionToSW(swSessionBaseUrl, swSessionAccessToken, swSessionUserId);
const handleVisibility = () => {
if (document.visibilityState === 'visible') resync();
};
document.addEventListener('visibilitychange', handleVisibility);
const timer = setInterval(resync, 10 * 60 * 1000);
return () => {
document.removeEventListener('visibilitychange', handleVisibility);
clearInterval(timer);
};
}, [swSessionBaseUrl, swSessionAccessToken, swSessionUserId]);

useEffect(
() => () => {
if (mx?.clientRunning) {
Expand Down
8 changes: 8 additions & 0 deletions src/client/initMatrix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -802,5 +802,13 @@ export const clearLoginData = async () => {
if (name) window.indexedDB.deleteDatabase(name);
});
window.localStorage.clear();

// Unregister all service workers so the next load starts fresh.
// Especially important on iOS/mobile where stale SWs can persist.
if ('serviceWorker' in navigator) {
const registrations = await navigator.serviceWorker.getRegistrations();
await Promise.all(registrations.map((r) => r.unregister()));
}

window.location.reload();
};
Loading