@budarin/pluggable-serviceworker 1.5.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -440,6 +440,7 @@ function authPlugin(config: {
440
440
  if (protectedPaths.some((p) => path.startsWith(p))) {
441
441
  if (needsAuth(event.request)) {
442
442
  logger.warn('auth: unauthorized', event.request.url);
443
+
443
444
  return new Response('Unauthorized', { status: 401 }); // Прерывает цепочку
444
445
  }
445
446
  }
@@ -454,7 +455,7 @@ function authPlugin(config: {
454
455
  **Почему последовательно:**
455
456
 
456
457
  - **fetch**: Нужен только один ответ на текущий запрос браузера, первый успешный прерывает цепочку. Если никто не вернул ответ — выполняется `fetch(event.request)`
457
- - **push**: Плагин может вернуть `PushNotificationPayload`, `false` (не показывать) или `undefined` (решение отдаётся библиотеке). Библиотека вызывает `showNotification` для каждого payload. Не показываем, если все вернули `false` или смесь без payload. Библиотека показывает одно только когда **все** вернули `undefined`.
458
+ - **push**: Плагин может вернуть `PushNotificationPayload`, `false` (не показывать) или `undefined` (решение отдаётся библиотеке). Библиотека вызывает `showNotification` для каждого payload. Не показываем, если все вернули `false` или смесь без payload. Библиотека показывает нотификацию и в случае когда **все** плагины вернули `undefined`.
458
459
 
459
460
  ### 📋 Сводная таблица
460
461
 
@@ -479,19 +480,19 @@ function authPlugin(config: {
479
480
  | Название | Событие | Описание |
480
481
  | ------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------- |
481
482
  | `precache*(config)` | `install` | Кеширует список ресурсов из `config.assets` в кеш `config.cacheName`. |
482
- | `precacheAndNotify(config)` | install | Как **precache**, затем отправляет активным клиентам сообщение `{ type: config.messageType }` (по умолчанию `SW_INSTALLED`). |
483
+ | `precacheAndNotify(config)` | `install` | Как **precache**, затем отправляет активным клиентам сообщение `{ type: config.messageType }` (по умолчанию `SW_INSTALLED`). |
483
484
  | `precacheMissing(config)` | `install` | Добавляет в кеш только те ресурсы из `config.assets`, которых ещё нет в кеше. |
484
485
  | `pruneStaleCache(config)` | `activate` | Удаляет из кеша записи, чей URL не входит в `config.assets`. |
485
- | `skipWaiting | `install` | Вызывает `skipWaiting()`. |
486
+ | `skipWaiting` | `install` | Вызывает `skipWaiting()`. |
486
487
  | `claim` | `activate` | Вызывает `clients.claim()`. |
487
488
  | `reloadClients` | `activate` | Перезагружает все окна-клиенты через `client.navigate(client.url)`. |
488
489
  | `claimAndReloadClients` | `activate` | Композиция **claim** + **reloadClients**: сначала claim, затем перезагрузка (порядок гарантирован — один плагин). |
489
490
  | `skipWaitingOnMessage(config?)` | `message` | При сообщении с `event.data.type === 'SW_MSG_SKIP_WAITING'` вызывает `skipWaiting()`. |
490
491
  | `serveFromCache(config)` | `fetch` | Отдаёт ресурс из кеша `config.cacheName`; при отсутствии его в кэше — undefined. |
491
492
  | `restoreAssetToCache(config)` | `fetch` | Для URL из `config.assets`: отдам ресурс из кеша или запрашиваем по сети, затем в кладем кго в кеш. Иначе — undefined. |
492
- | cacheFirst(config)` | `fetch` | Отдаем ресурс из кэша `config.cacheName`: при отсутствии его в кэше — делаем запрос на сервер и затем кладем ответ в кэш. |
493
+ | `cacheFirst(config)` | `fetch` | Отдаем ресурс из кэша `config.cacheName`: при отсутствии его в кэше — делаем запрос на сервер и затем кладем ответ в кэш. |
493
494
  | `networkFirst(config)` | `fetch` | Делаем запрос на сервер, при успехе — кладем его в кэш. При ошибке — отдаем из кэша. Иначе - `undefined`. |
494
- | `staleWhileRevalidate(config)` | fetch | Отдаёт из кэша, в фоне обновляет кэш. |
495
+ | `staleWhileRevalidate(config)` | `fetch` | Отдаёт из кэша, в фоне обновляет кэш. |
495
496
 
496
497
  #### Композиция примитивов
497
498
 
@@ -499,32 +500,29 @@ function authPlugin(config: {
499
500
 
500
501
  **Пример: claimAndReloadClients как композиция двух примитивов**
501
502
 
502
- Плагин **claimAndReloadClients** из коробки выполняет в `activate` последовательно: `clients.claim()`, затем перезагрузка всех окон.
503
+ Плагин **claimAndReloadClients** вызывает существующие примитивы **claim** и **reloadClients** по очереди:
503
504
 
504
505
  ```typescript
505
- // Реализация плагина claimAndReloadClients (из @budarin/pluggable-serviceworker/plugins)
506
- activate: () =>
507
- self.clients.claim().then(() =>
508
- self.clients
509
- .matchAll({ type: 'window' })
510
- .then((list) =>
511
- Promise.all(list.map((client) => client.navigate(client.url)))
512
- )
513
- ),
514
- ```
506
+ import { claim } from '@budarin/pluggable-serviceworker/plugins';
507
+ import { reloadClients } from '@budarin/pluggable-serviceworker/plugins';
515
508
 
516
- Два плагина **claim** и **reloadClients** в стеке выполняют `activate` **параллельно** (см. «Логика выполнения обработчиков»), порядок завершения операций не гарантирован. Для строгой последовательности «сначала claim, потом reload» используйте один плагин **claimAndReloadClients**.
509
+ const claimPlugin = claim();
510
+ const reloadPlugin = reloadClients();
517
511
 
518
- ```typescript
519
- initServiceWorker([claim, reloadClients], options); // оба activate — параллельно
512
+ activate: (event, logger) =>
513
+ Promise.resolve(claimPlugin.activate(event, logger)).then(() =>
514
+ reloadPlugin.activate(event, logger)
515
+ ),
520
516
  ```
521
517
 
522
518
  **Пример: кастомный кэш и логика по URL**
523
519
 
524
- Фабрика `postsSwrPlugin(config)` возвращает плагин, который применяет stale-while-revalidate только к запросам, подходящим под `pathPattern`. Логика SWR инлайнована в обработчик `fetch`.
520
+ Фабрика `postsSwrPlugin(config)` возвращает плагин, который применяет `stale-while-revalidate`(SWR) только к запросам, подходящим под `pathPattern`.
525
521
 
526
522
  ```typescript
523
+ // postsSwrPlugin.ts
527
524
  import type { Plugin } from '@budarin/pluggable-serviceworker';
525
+
528
526
  import {
529
527
  precache,
530
528
  serveFromCache,
@@ -536,28 +534,39 @@ function postsSwrPlugin(config: {
536
534
  pathPattern?: RegExp;
537
535
  }): Plugin {
538
536
  const { cacheName, pathPattern = /\/api\/posts(\/|$)/ } = config;
537
+
539
538
  return {
540
539
  name: 'postsSwr',
541
540
  order: 0,
541
+
542
542
  fetch: async (event) => {
543
- if (!pathPattern.test(new URL(event.request.url).pathname))
543
+ if (!pathPattern.test(new URL(event.request.url).pathname)) {
544
544
  return undefined;
545
+ }
546
+
545
547
  const cache = await caches.open(cacheName);
546
548
  const cached = await cache.match(event.request);
547
549
  const revalidate = fetch(event.request).then(async (response) => {
548
- if (response.ok)
550
+ if (response.ok) {
549
551
  await cache.put(event.request, response.clone());
552
+ }
553
+
550
554
  return response;
551
555
  });
556
+
552
557
  if (cached) {
553
558
  void revalidate;
554
559
  return cached;
555
560
  }
561
+
556
562
  return revalidate;
557
563
  },
558
564
  };
559
565
  }
566
+ ```
560
567
 
568
+ ```typescript
569
+ // sw.ts
561
570
  const staticCache = 'static-v1';
562
571
  const assets = ['/', '/main.js'];
563
572
 
@@ -580,7 +589,6 @@ initServiceWorker(
580
589
  | `offlineFirst(config)` | `precache(config) + serveFromCache(config)` | Статика из кеша, при отсутствии ресурса в кэше — делаем запрос к серверу. |
581
590
 
582
591
  Конфиг пресета: `OfflineFirstConfig` (cacheName, assets). Импорт из `@budarin/pluggable-serviceworker/presets`.
583
-
584
592
  Стратегии **networkFirst**, **staleWhileRevalidate** и др. доступны как примитивы — собирайте свой кастомный сервис-воркер из примитивов и пресетов.
585
593
 
586
594
  ### Типовые сервис-воркеры (из коробки)
@@ -1,10 +1,10 @@
1
+ import { claim } from './claim.js';
2
+ import { reloadClients } from './reloadClients.js';
1
3
  export function claimAndReloadClients() {
4
+ const claimPlugin = claim();
5
+ const reloadPlugin = reloadClients();
2
6
  return {
3
7
  name: 'claimAndReloadClients',
4
- activate: () => self.clients
5
- .claim()
6
- .then(() => self.clients
7
- .matchAll({ type: 'window' })
8
- .then((list) => Promise.all(list.map((client) => client.navigate(client.url))))),
8
+ activate: (event, logger) => Promise.resolve(claimPlugin.activate(event, logger)).then(() => reloadPlugin.activate(event, logger)),
9
9
  };
10
10
  }
@@ -4,8 +4,9 @@ export function skipWaitingOnMessage(config = {}) {
4
4
  return {
5
5
  name: 'skipWaitingOnMessage',
6
6
  message: (event) => {
7
- if (event.data?.type !== messageType)
7
+ if (event.data?.type !== messageType) {
8
8
  return;
9
+ }
9
10
  self.skipWaiting();
10
11
  },
11
12
  };
@@ -1,5 +1,5 @@
1
1
  import type { ServiceWorkerInitOptions } from '../index.js';
2
- import { type OfflineFirstConfig } from '../presets/offlineFirst.js';
2
+ import type { OfflineFirstConfig } from '../presets/offlineFirst.js';
3
3
  export interface ActivateImmediatelyOptions extends ServiceWorkerInitOptions, OfflineFirstConfig {
4
4
  }
5
5
  export declare function activateImmediatelyServiceWorker(options: ActivateImmediatelyOptions): void;
@@ -1,7 +1,7 @@
1
+ import { claim } from '../plugins/claim.js';
1
2
  import { initServiceWorker } from '../index.js';
2
- import { offlineFirst, } from '../presets/offlineFirst.js';
3
3
  import { skipWaiting } from '../plugins/skipWaiting.js';
4
- import { claim } from '../plugins/claim.js';
4
+ import { offlineFirst } from '../presets/offlineFirst.js';
5
5
  export function activateImmediatelyServiceWorker(options) {
6
6
  initServiceWorker([...offlineFirst(options), skipWaiting, claim], options);
7
7
  }
@@ -1,5 +1,5 @@
1
1
  import type { ServiceWorkerInitOptions } from '../index.js';
2
- import { type OfflineFirstConfig } from '../presets/offlineFirst.js';
2
+ import type { OfflineFirstConfig } from '../presets/offlineFirst.js';
3
3
  export interface ActivateOnNextVisitOptions extends ServiceWorkerInitOptions, OfflineFirstConfig {
4
4
  }
5
5
  export declare function activateOnNextVisitServiceWorker(options: ActivateOnNextVisitOptions): void;
@@ -1,5 +1,5 @@
1
1
  import { initServiceWorker } from '../index.js';
2
- import { offlineFirst, } from '../presets/offlineFirst.js';
2
+ import { offlineFirst } from '../presets/offlineFirst.js';
3
3
  export function activateOnNextVisitServiceWorker(options) {
4
4
  initServiceWorker(offlineFirst(options), options);
5
5
  }
@@ -0,0 +1,4 @@
1
+ export declare function openCacheAndMatch(cacheName: string, request: Request): Promise<{
2
+ cache: Cache;
3
+ cached: Response | undefined;
4
+ }>;
@@ -0,0 +1,5 @@
1
+ export async function openCacheAndMatch(cacheName, request) {
2
+ const cache = await caches.open(cacheName);
3
+ const cached = await cache.match(request);
4
+ return { cache, cached: cached ?? undefined };
5
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@budarin/pluggable-serviceworker",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "description": "Extensible via plugins service worker",
5
5
  "keywords": [
6
6
  "serviceworker",