style(13-03): apply Prettier formatting across repo
Mechanical reformat — no logic changes. 398 files changed, 19125 insertions(+), 16457 deletions(-). Prettier 3.8.4 with .prettierrc (singleQuote:true, semi:true, tabWidth:2, trailingComma:all, printWidth:100). Isolated per D-13-08 for reviewability.
This commit is contained in:
+44
-50
@@ -25,26 +25,26 @@
|
||||
|
||||
/// <reference lib="webworker" />
|
||||
|
||||
import { precacheAndRoute, createHandlerBoundToURL } from 'workbox-precaching'
|
||||
import { clientsClaim } from 'workbox-core'
|
||||
import { NavigationRoute, registerRoute } from 'workbox-routing'
|
||||
import { precacheAndRoute, createHandlerBoundToURL } from 'workbox-precaching';
|
||||
import { clientsClaim } from 'workbox-core';
|
||||
import { NavigationRoute, registerRoute } from 'workbox-routing';
|
||||
|
||||
declare const self: ServiceWorkerGlobalScope
|
||||
declare const self: ServiceWorkerGlobalScope;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// AutoUpdate behavior: replace old SW immediately on install/activate.
|
||||
// Equivalent to the former generateSW autoUpdate: 'prompt' → 'autoUpdate' path.
|
||||
// ---------------------------------------------------------------------------
|
||||
// skipWaiting() resolves when the SW is installed; fire-and-forget is the correct pattern here
|
||||
void self.skipWaiting()
|
||||
clientsClaim()
|
||||
void self.skipWaiting();
|
||||
clientsClaim();
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Precache the app shell.
|
||||
// self.__WB_MANIFEST is injected by vite-plugin-pwa injectManifest at build time.
|
||||
// At dev time this is an empty array; the real manifest is injected in production.
|
||||
// ---------------------------------------------------------------------------
|
||||
precacheAndRoute(self.__WB_MANIFEST)
|
||||
precacheAndRoute(self.__WB_MANIFEST);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Navigation denylist (T-03-20 — CRITICAL).
|
||||
@@ -56,7 +56,7 @@ precacheAndRoute(self.__WB_MANIFEST)
|
||||
//
|
||||
// Re-implements the former workbox.navigateFallbackDenylist from vite.config.ts.
|
||||
// ---------------------------------------------------------------------------
|
||||
const navHandler = createHandlerBoundToURL('/index.html')
|
||||
const navHandler = createHandlerBoundToURL('/index.html');
|
||||
registerRoute(
|
||||
new NavigationRoute(navHandler, {
|
||||
denylist: [
|
||||
@@ -65,7 +65,7 @@ registerRoute(
|
||||
/^\/health/, // Health endpoint
|
||||
],
|
||||
}),
|
||||
)
|
||||
);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Push handler (D-11, NOTIF-01/02/03).
|
||||
@@ -79,14 +79,14 @@ registerRoute(
|
||||
// Legacy (iOS 16.4–18.3 + Android): { title, body, tag, data: { url } }
|
||||
// ---------------------------------------------------------------------------
|
||||
self.addEventListener('push', (event: PushEvent) => {
|
||||
let title = 'FamilySync'
|
||||
let body = 'You have a new notification'
|
||||
let tag = 'familysync-notification'
|
||||
let url = '/'
|
||||
let title = 'FamilySync';
|
||||
let body = 'You have a new notification';
|
||||
let tag = 'familysync-notification';
|
||||
let url = '/';
|
||||
|
||||
try {
|
||||
if (event.data) {
|
||||
const payload = event.data.json() as Record<string, unknown>
|
||||
const payload = event.data.json() as Record<string, unknown>;
|
||||
|
||||
// iOS 18.4+ declarative web push format
|
||||
if (
|
||||
@@ -94,23 +94,23 @@ self.addEventListener('push', (event: PushEvent) => {
|
||||
payload.notification &&
|
||||
typeof payload.notification === 'object'
|
||||
) {
|
||||
const notif = payload.notification as Record<string, unknown>
|
||||
if (typeof notif.title === 'string') title = notif.title
|
||||
if (typeof notif.body === 'string') body = notif.body
|
||||
if (typeof notif.navigate === 'string') url = notif.navigate
|
||||
const notif = payload.notification as Record<string, unknown>;
|
||||
if (typeof notif.title === 'string') title = notif.title;
|
||||
if (typeof notif.body === 'string') body = notif.body;
|
||||
if (typeof notif.navigate === 'string') url = notif.navigate;
|
||||
// Use navigate as tag for coalescing duplicate pushes
|
||||
tag = `familysync-${url}`
|
||||
tag = `familysync-${url}`;
|
||||
} else {
|
||||
// Legacy format: top-level title/body/tag/data
|
||||
if (typeof payload.title === 'string') title = payload.title
|
||||
if (typeof payload.body === 'string') body = payload.body
|
||||
if (typeof payload.tag === 'string') tag = payload.tag
|
||||
if (typeof payload.title === 'string') title = payload.title;
|
||||
if (typeof payload.body === 'string') body = payload.body;
|
||||
if (typeof payload.tag === 'string') tag = payload.tag;
|
||||
if (
|
||||
payload.data &&
|
||||
typeof payload.data === 'object' &&
|
||||
typeof (payload.data as Record<string, unknown>).url === 'string'
|
||||
) {
|
||||
url = (payload.data as Record<string, string>).url
|
||||
url = (payload.data as Record<string, string>).url;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,11 +134,9 @@ self.addEventListener('push', (event: PushEvent) => {
|
||||
badge: '/icon-192.png',
|
||||
renotify: true,
|
||||
vibrate: [200, 100, 200],
|
||||
} as NotificationOptions
|
||||
event.waitUntil(
|
||||
self.registration.showNotification(title, options),
|
||||
)
|
||||
})
|
||||
} as NotificationOptions;
|
||||
event.waitUntil(self.registration.showNotification(title, options));
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// notificationclick handler (D-14 — deep-link on tap).
|
||||
@@ -155,35 +153,31 @@ self.addEventListener('push', (event: PushEvent) => {
|
||||
// Using any existing window + navigate() satisfies D-14 on both Android and iOS.
|
||||
// ---------------------------------------------------------------------------
|
||||
self.addEventListener('notificationclick', (event: NotificationEvent) => {
|
||||
event.notification.close()
|
||||
event.notification.close();
|
||||
|
||||
// Notification.data is typed as 'any' in the ServiceWorker lib; we validate with typeof
|
||||
// before using the value so the access is safe despite the lack of static types.
|
||||
let url = '/'
|
||||
let url = '/';
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- Notification.data is 'any' per webworker lib; typeof guard on the right-hand side validates this access
|
||||
if (typeof event.notification.data?.url === 'string') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- Notification.data is 'any'; typeof check above validates this access
|
||||
url = event.notification.data.url as string
|
||||
url = event.notification.data.url as string;
|
||||
}
|
||||
|
||||
event.waitUntil(
|
||||
self.clients
|
||||
.matchAll({ type: 'window', includeUncontrolled: true })
|
||||
.then((clientList) => {
|
||||
// Focus any existing window on this origin and navigate it to the target URL.
|
||||
// We don't match on client.url — the deep-link URL will almost always differ
|
||||
// from the current window location (query string with event uid / date).
|
||||
for (const client of clientList) {
|
||||
if ('focus' in client) {
|
||||
return client.focus().then(() =>
|
||||
client.navigate(url)
|
||||
)
|
||||
}
|
||||
self.clients.matchAll({ type: 'window', includeUncontrolled: true }).then((clientList) => {
|
||||
// Focus any existing window on this origin and navigate it to the target URL.
|
||||
// We don't match on client.url — the deep-link URL will almost always differ
|
||||
// from the current window location (query string with event uid / date).
|
||||
for (const client of clientList) {
|
||||
if ('focus' in client) {
|
||||
return client.focus().then(() => client.navigate(url));
|
||||
}
|
||||
// No existing window — open a new one at the deep-link URL
|
||||
if (self.clients.openWindow) {
|
||||
return self.clients.openWindow(url)
|
||||
}
|
||||
}),
|
||||
)
|
||||
})
|
||||
}
|
||||
// No existing window — open a new one at the deep-link URL
|
||||
if (self.clients.openWindow) {
|
||||
return self.clients.openWindow(url);
|
||||
}
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user