anydrop/web/src/sw.ts
ordinarthur fd249abbf1
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m1s
feat: push notifications + background transfer alerts
- Web Push API for offline device notifications
- Custom service worker with push event handling
- Local notifications for background tab transfers
- VAPID keys in K8s config
- Persistent deviceId per device
2026-04-14 12:03:43 +02:00

70 lines
2.0 KiB
TypeScript

/// <reference lib="webworker" />
import { precacheAndRoute } from "workbox-precaching";
import { registerRoute, NavigationRoute } from "workbox-routing";
import { NetworkFirst } from "workbox-strategies";
import type { PushPayload } from "@anydrop/shared";
declare const self: ServiceWorkerGlobalScope;
// Workbox injects the precache manifest here
precacheAndRoute(self.__WB_MANIFEST);
// Navigation: always try network first (so deploys are visible immediately)
registerRoute(new NavigationRoute(new NetworkFirst()));
// Activate immediately, take control of all clients
self.addEventListener("install", () => {
self.skipWaiting();
});
self.addEventListener("activate", (event) => {
event.waitUntil(self.clients.claim());
});
// ── Push notifications ──
self.addEventListener("push", (event) => {
if (!event.data) return;
let payload: PushPayload;
try {
payload = event.data.json();
} catch {
return;
}
if (payload.type === "peer-nearby") {
const deviceEmoji = payload.deviceType === "phone" ? "📱" : payload.deviceType === "tablet" ? "📱" : "💻";
event.waitUntil(
self.registration.showNotification("AnyDrop", {
body: `${deviceEmoji} ${payload.displayName} est à proximité`,
icon: "/icon-192.png",
badge: "/icon-192.png",
tag: "peer-nearby",
data: { url: "/" },
} as NotificationOptions),
);
}
});
// Click on notification → open/focus AnyDrop
self.addEventListener("notificationclick", (event) => {
event.notification.close();
const url = event.notification.data?.url || "/";
event.waitUntil(
self.clients.matchAll({ type: "window", includeUncontrolled: true }).then((clients) => {
// Focus existing tab if open
for (const client of clients) {
if (new URL(client.url).pathname === url && "focus" in client) {
return client.focus();
}
}
// Otherwise open new tab
return self.clients.openWindow(url);
}),
);
});