phanpy/public/sw.js

221 lines
5.7 KiB
JavaScript
Raw Normal View History

import { CacheableResponsePlugin } from 'workbox-cacheable-response';
import { ExpirationPlugin } from 'workbox-expiration';
import { RegExpRoute, registerRoute, Route } from 'workbox-routing';
2023-01-10 09:08:10 +00:00
import {
CacheFirst,
NetworkFirst,
StaleWhileRevalidate,
} from 'workbox-strategies';
self.__WB_DISABLE_DEV_LOGS = true;
2023-09-14 15:21:43 +00:00
const assetsRoute = new Route(
({ request, sameOrigin }) => {
const isAsset =
request.destination === 'style' || request.destination === 'script';
const hasHash = /-[0-9a-f]{4,}\./i.test(request.url);
return sameOrigin && isAsset && hasHash;
},
new NetworkFirst({
cacheName: 'assets',
networkTimeoutSeconds: 5,
plugins: [
new CacheableResponsePlugin({
statuses: [0, 200],
}),
],
}),
);
registerRoute(assetsRoute);
const imageRoute = new Route(
({ request, sameOrigin }) => {
const isRemote = !sameOrigin;
const isImage = request.destination === 'image';
const isAvatar = request.url.includes('/avatars/');
2024-02-29 10:18:40 +00:00
const isCustomEmoji = request.url.includes('/custom/_emojis');
const isEmoji = request.url.includes('/emoji/');
2024-02-29 10:18:40 +00:00
return isRemote && isImage && (isAvatar || isCustomEmoji || isEmoji);
},
new CacheFirst({
cacheName: 'remote-images',
plugins: [
new ExpirationPlugin({
2023-02-25 02:31:50 +00:00
maxEntries: 50,
maxAgeSeconds: 3 * 24 * 60 * 60, // 3 days
purgeOnQuotaError: true,
}),
new CacheableResponsePlugin({
statuses: [0, 200],
}),
],
}),
);
registerRoute(imageRoute);
const iconsRoute = new Route(
({ request, sameOrigin }) => {
const isIcon = request.url.includes('/icons/');
return sameOrigin && isIcon;
},
new CacheFirst({
cacheName: 'icons',
plugins: [
new ExpirationPlugin({
2024-05-15 11:38:28 +00:00
maxEntries: 300,
maxAgeSeconds: 3 * 24 * 60 * 60, // 3 days
purgeOnQuotaError: true,
}),
new CacheableResponsePlugin({
statuses: [0, 200],
}),
],
}),
);
registerRoute(iconsRoute);
2023-02-23 12:54:23 +00:00
// 1-day cache for
// - /api/v1/instance
// - /api/v1/custom_emojis
// - /api/v1/preferences
// - /api/v1/lists/:id
2023-05-21 00:36:59 +00:00
// - /api/v1/announcements
const apiExtendedRoute = new RegExpRoute(
2023-05-21 00:36:59 +00:00
/^https?:\/\/[^\/]+\/api\/v\d+\/(instance|custom_emojis|preferences|lists\/\d+|announcements)$/,
new StaleWhileRevalidate({
cacheName: 'api-extended',
plugins: [
new ExpirationPlugin({
maxAgeSeconds: 24 * 60 * 60, // 1 day
}),
new CacheableResponsePlugin({
statuses: [0, 200],
}),
],
}),
);
registerRoute(apiExtendedRoute);
const apiIntermediateRoute = new RegExpRoute(
// Matches:
// - trends/*
// - timelines/link
/^https?:\/\/[^\/]+\/api\/v\d+\/(trends|timelines\/link)/,
new StaleWhileRevalidate({
cacheName: 'api-intermediate',
plugins: [
new ExpirationPlugin({
maxAgeSeconds: 10 * 60, // 10 minutes
}),
new CacheableResponsePlugin({
statuses: [0, 200],
}),
],
}),
);
registerRoute(apiIntermediateRoute);
2023-01-02 06:23:00 +00:00
const apiRoute = new RegExpRoute(
// Matches:
// - statuses/:id/context - some contexts are really huge
/^https?:\/\/[^\/]+\/api\/v\d+\/(statuses\/\d+\/context)/,
2023-01-09 17:28:52 +00:00
new NetworkFirst({
2023-01-02 06:23:00 +00:00
cacheName: 'api',
2023-01-09 17:28:52 +00:00
networkTimeoutSeconds: 5,
2023-01-02 06:23:00 +00:00
plugins: [
new ExpirationPlugin({
maxAgeSeconds: 5 * 60, // 5 minutes
}),
new CacheableResponsePlugin({
statuses: [0, 200],
}),
],
}),
);
registerRoute(apiRoute);
// PUSH NOTIFICATIONS
// ==================
self.addEventListener('push', (event) => {
const { data } = event;
if (data) {
const payload = data.json();
console.log('PUSH payload', payload);
const {
access_token,
title,
body,
icon,
notification_id,
notification_type,
preferred_locale,
} = payload;
if (!!navigator.setAppBadge) {
if (notification_type === 'mention') {
navigator.setAppBadge(1);
}
}
event.waitUntil(
self.registration.showNotification(title, {
body,
icon,
dir: 'auto',
badge: '/logo-badge-72.png',
lang: preferred_locale,
tag: notification_id,
timestamp: Date.now(),
data: {
access_token,
notification_type,
},
}),
);
}
});
self.addEventListener('notificationclick', (event) => {
const payload = event.notification;
console.log('NOTIFICATION CLICK payload', payload);
const { badge, body, data, dir, icon, lang, tag, timestamp, title } = payload;
const { access_token, notification_type } = data;
const url = `/#/notifications?id=${tag}&access_token=${btoa(access_token)}`;
event.waitUntil(
(async () => {
const clients = await self.clients.matchAll({
type: 'window',
includeUncontrolled: true,
});
console.log('NOTIFICATION CLICK clients 1', clients);
if (clients.length && 'navigate' in clients[0]) {
console.log('NOTIFICATION CLICK clients 2', clients);
const bestClient =
clients.find(
(client) => client.focused || client.visibilityState === 'visible',
) || clients[0];
console.log('NOTIFICATION CLICK navigate', url);
if (bestClient) {
console.log('NOTIFICATION CLICK postMessage', bestClient);
2023-10-19 09:45:27 +00:00
bestClient.focus();
bestClient.postMessage?.({
type: 'notification',
id: tag,
accessToken: access_token,
});
} else {
console.log('NOTIFICATION CLICK openWindow', url);
await self.clients.openWindow(url);
}
// }
} else {
console.log('NOTIFICATION CLICK openWindow', url);
await self.clients.openWindow(url);
}
2023-10-16 13:38:14 +00:00
await event.notification.close();
})(),
);
});