PWA token extend

This commit is contained in:
binwiederhier
2026-05-28 21:58:01 -04:00
parent 85abd40658
commit ef0dde8aa4
3 changed files with 25 additions and 19 deletions
+13 -12
View File
@@ -12,8 +12,9 @@ import {
EVENT_MESSAGE, EVENT_MESSAGE,
EVENT_MESSAGE_CLEAR, EVENT_MESSAGE_CLEAR,
EVENT_MESSAGE_DELETE, EVENT_MESSAGE_DELETE,
WEBPUSH_EVENT_MESSAGE, SW_PERIODIC_SYNC_EXTEND_TOKEN_TAG,
WEBPUSH_EVENT_SUBSCRIPTION_EXPIRING, SW_WEBPUSH_EVENT_MESSAGE,
SW_WEBPUSH_EVENT_SUBSCRIPTION_EXPIRING,
} from "../src/app/events"; } from "../src/app/events";
/** /**
@@ -88,11 +89,11 @@ const handlePushMessage = async (data) => {
// Broadcast the message to potentially play a sound // Broadcast the message to potentially play a sound
broadcastChannel.postMessage(message); broadcastChannel.postMessage(message);
await extendToken(); await maybeExtendToken();
}; };
const refreshThreshold = 1000 * 60 * 60; // 1 hour const refreshTokenThreshold = 1000 * 60 * 60; // 1 hour
const extendToken = async () => { const maybeExtendToken = async () => {
if (import.meta.env.DEV) { if (import.meta.env.DEV) {
console.warn("[ServiceWorker] Skipping token extension in development since no config.base_url exists"); console.warn("[ServiceWorker] Skipping token extension in development since no config.base_url exists");
return; return;
@@ -107,7 +108,7 @@ const extendToken = async () => {
const lastExtendedAt = await session.lastExtendedAtAsync(); const lastExtendedAt = await session.lastExtendedAtAsync();
const now = Date.now(); const now = Date.now();
if (lastExtendedAt && now - lastExtendedAt < refreshThreshold) { if (lastExtendedAt && now - lastExtendedAt < refreshTokenThreshold) {
console.debug(`[ServiceWorker] Token extended ${Math.floor((now - lastExtendedAt) / 1000 / 60)} minutes ago, skipping`); console.debug(`[ServiceWorker] Token extended ${Math.floor((now - lastExtendedAt) / 1000 / 60)} minutes ago, skipping`);
return; return;
} }
@@ -138,7 +139,7 @@ const extendToken = async () => {
}; };
/** /**
* Registers a periodic-sync listener for `extend-token` (see hooks.js). * Registers a periodic-sync listener for `extend_token` (see hooks.js).
* This extends the token regardless of whether the browser is open. * This extends the token regardless of whether the browser is open.
* *
* CAVEATS: * CAVEATS:
@@ -147,9 +148,9 @@ const extendToken = async () => {
* - Only when notifications are granted * - Only when notifications are granted
*/ */
self.addEventListener("periodicsync", (event) => { self.addEventListener("periodicsync", (event) => {
if (event.tag === "extend-token") { if (event.tag === SW_PERIODIC_SYNC_EXTEND_TOKEN_TAG) {
console.log('[ServiceWorker] Received periodicsync event "extend-token"'); console.log(`[ServiceWorker] Received periodicsync event "${SW_PERIODIC_SYNC_EXTEND_TOKEN_TAG}"`);
event.waitUntil(extendToken()); event.waitUntil(maybeExtendToken());
} }
}); });
@@ -263,7 +264,7 @@ const handlePush = async (data) => {
// - Web app: hooks.js:handleNotification() // - Web app: hooks.js:handleNotification()
// - Web app: sw.js:handleMessage(), sw.js:handleMessageClear(), ... // - Web app: sw.js:handleMessage(), sw.js:handleMessageClear(), ...
if (data.event === WEBPUSH_EVENT_MESSAGE) { if (data.event === SW_WEBPUSH_EVENT_MESSAGE) {
const { message } = data; const { message } = data;
if (message.event === EVENT_MESSAGE) { if (message.event === EVENT_MESSAGE) {
return await handlePushMessage(data); return await handlePushMessage(data);
@@ -272,7 +273,7 @@ const handlePush = async (data) => {
} else if (message.event === EVENT_MESSAGE_CLEAR) { } else if (message.event === EVENT_MESSAGE_CLEAR) {
return await handlePushMessageClear(data); return await handlePushMessageClear(data);
} }
} else if (data.event === WEBPUSH_EVENT_SUBSCRIPTION_EXPIRING) { } else if (data.event === SW_WEBPUSH_EVENT_SUBSCRIPTION_EXPIRING) {
return await handlePushSubscriptionExpiring(data); return await handlePushSubscriptionExpiring(data);
} }
+4 -2
View File
@@ -8,8 +8,10 @@ export const EVENT_MESSAGE_DELETE = "message_delete";
export const EVENT_MESSAGE_CLEAR = "message_clear"; export const EVENT_MESSAGE_CLEAR = "message_clear";
export const EVENT_POLL_REQUEST = "poll_request"; export const EVENT_POLL_REQUEST = "poll_request";
export const WEBPUSH_EVENT_MESSAGE = "message"; export const SW_WEBPUSH_EVENT_MESSAGE = "message";
export const WEBPUSH_EVENT_SUBSCRIPTION_EXPIRING = "subscription_expiring"; export const SW_WEBPUSH_EVENT_SUBSCRIPTION_EXPIRING = "subscription_expiring";
export const SW_PERIODIC_SYNC_EXTEND_TOKEN_TAG = "extend_token";
// Check if an event is a notification event (message, delete, or read) // Check if an event is a notification event (message, delete, or read)
export const isNotificationEvent = (event) => event === EVENT_MESSAGE || event === EVENT_MESSAGE_DELETE || event === EVENT_MESSAGE_CLEAR; export const isNotificationEvent = (event) => event === EVENT_MESSAGE || event === EVENT_MESSAGE_DELETE || event === EVENT_MESSAGE_CLEAR;
+8 -5
View File
@@ -13,7 +13,7 @@ import versionChecker from "../app/VersionChecker";
import { UnauthorizedError } from "../app/errors"; import { UnauthorizedError } from "../app/errors";
import notifier from "../app/Notifier"; import notifier from "../app/Notifier";
import prefs from "../app/Prefs"; import prefs from "../app/Prefs";
import { EVENT_MESSAGE_DELETE, EVENT_MESSAGE_CLEAR } from "../app/events"; import { EVENT_MESSAGE_DELETE, EVENT_MESSAGE_CLEAR, SW_PERIODIC_SYNC_EXTEND_TOKEN_TAG } from "../app/events";
/** /**
* Wire connectionManager and subscriptionManager so that subscriptions are updated when the connection * Wire connectionManager and subscriptionManager so that subscriptions are updated when the connection
@@ -284,13 +284,16 @@ export const useStandaloneWebPushAutoSubscribe = () => {
}; };
/** /**
* Registers a periodicsync listener for `extend-token` (see sw.js). * Registers a periodicsync listener for `extend_token` (see sw.js).
* This extends the token regardless of whether the browser is open. * This extends the token regardless of whether the browser is open.
* *
* CAVEATS: * CAVEATS:
* - Chromium-only * - Chromium-only
* - Only when the PWA is _installed_ (not just running in a browser tab) * - Only when the PWA is _installed_ (not just running in a browser tab)
* - Only when notifications are granted * - Only when notifications are granted
*
* This is an experimental feature:
* https://developer.mozilla.org/en-US/docs/Web/API/Web_Periodic_Background_Synchronization_API
*/ */
const usePeriodicTokenExtend = () => { const usePeriodicTokenExtend = () => {
const isLaunchedPWA = useIsLaunchedPWA(); const isLaunchedPWA = useIsLaunchedPWA();
@@ -315,9 +318,9 @@ const usePeriodicTokenExtend = () => {
return; return;
} }
console.log(`[usePeriodicTokenExtend] Turning on periodicsync "extend-token"`); console.log(`[usePeriodicTokenExtend] Turning on periodicsync "${SW_PERIODIC_SYNC_EXTEND_TOKEN_TAG}"`);
await registration.periodicSync.register("extend-token", { await registration.periodicSync.register(SW_PERIODIC_SYNC_EXTEND_TOKEN_TAG, {
minInterval: 24 * 60 * 60 * 1000, // 24 hours minInterval: 60 * 1000 // 24 * 60 * 60 * 1000 // 24 hours
}); });
} catch (error) { } catch (error) {
console.log("[usePeriodicTokenExtend] Periodic Sync could not be registered", error); console.log("[usePeriodicTokenExtend] Periodic Sync could not be registered", error);