// File: --- title: Documentation description: WorkBee documentation - a tiny ServiceWorker for secure web applications. --- # WorkBee Documentation WorkBee is a tiny, modular ServiceWorker library for secure web applications. ## Features - **Small and modular** - up to 1KB minified + brotli - **Tree-shaking supported** - only include what you use - **Zero dependencies** - no external dependencies - **GDPR Compliant** - privacy-first design - **MIT Licensed** - free to use ## Architecture WorkBee is split into a core package that provides caching strategies and event handling, plus middleware packages that add specific functionality. ### Core The `@work-bee/core` package provides: - **Strategies** - CacheFirst, CacheOnly, NetworkFirst, NetworkOnly, StaleWhileRevalidate, Partition, HTMLPartition - **Events** - install, activate, fetch event handlers - **Configuration** - `compileConfig()` for building route configurations ### Middleware Middleware packages hook into the request/response lifecycle with `before`, `beforeNetwork`, `afterNetwork`, and `after` hooks: - `@work-bee/cache-control` - Respects HTTP Cache-Control headers - `@work-bee/fallback` - Provides fallback responses - `@work-bee/inactivity` - Detects user inactivity - `@work-bee/logger` - Logs requests and responses - `@work-bee/offline` - Queues requests when offline - `@work-bee/save-data` - Respects the Save-Data header - `@work-bee/session` - Session management // File: concepts/ --- title: Concepts description: Architecture and core concepts of WorkBee. --- # Concepts ## Request Flow When a ServiceWorker intercepts a fetch event, WorkBee processes it through this pipeline: 1. **Route matching** — `fetchEvent` finds the first route where `pathPattern` matches the request URL and `methods` includes the request method. 2. **Middleware `before`** — Each middleware's `before` hook runs in order, receiving and potentially modifying the request. 3. **Middleware `beforeNetwork`** — Each middleware's `beforeNetwork` hook runs before the strategy makes a network request. 4. **Strategy execution** — The configured strategy (e.g. `strategyCacheFirst`) handles the actual fetch/cache logic. 5. **Middleware `afterNetwork`** — Each middleware's `afterNetwork` hook runs after the network response, and can modify the response. 6. **Middleware `after`** — Each middleware's `after` hook runs last, and can replace the response (e.g. with a fallback). ## Strategies Strategies determine how a request is fulfilled: | Strategy | Behavior | |----------|----------| | `strategyNetworkOnly` | Always fetches from network | | `strategyCacheOnly` | Only returns cached responses | | `strategyNetworkFirst` | Tries network, falls back to cache | | `strategyCacheFirst` | Tries cache, falls back to network | | `strategyStaleWhileRevalidate` | Returns cache immediately, revalidates in background | | `strategyIgnore` | Returns a 408 response | | `strategyCacheFirstIgnore` | Tries cache, returns 408 if not cached | | `strategyStatic(response)` | Always returns the given static response | | `strategyHTMLPartition(options)` | Breaks HTML into parts with individual strategies | | `strategyPartition(options)` | Breaks request into sub-requests with individual strategies | ## Configuration `compileConfig()` merges your partial config with defaults and normalizes the structure. It: - Ensures all middleware arrays (`before`, `beforeNetwork`, `afterNetwork`, `after`) are populated from the `middlewares` array - Applies the same normalization to each route in `routes` - Sets up `precache` configuration ```js import { compileConfig, strategyCacheFirst } from "@work-bee/core"; const config = compileConfig({ cachePrefix: "v1-", routes: [ { pathPattern: new RegExp("/api/(.+)$"), cacheName: "api", strategy: strategyCacheFirst, }, ], }); ``` ## Middleware Middleware packages return objects with lifecycle hooks. Add them to a route's `middlewares` array and `compileConfig` distributes them to the correct phase: ```js import loggerMiddleware from "@work-bee/logger"; import fallbackMiddleware from "@work-bee/fallback"; const config = compileConfig({ strategy: strategyNetworkFirst, middlewares: [ loggerMiddleware(), fallbackMiddleware({ path: "/offline.html" }), ], }); ``` Some middleware also returns a `postMessageEvent` handler that must be wired up to the ServiceWorker's `message` event: ```js import offlineMiddleware from "@work-bee/offline"; const offline = offlineMiddleware({ pollDelay: 0 }); addEventListener("message", (event) => { const { data } = event; if (data.type === "offline") { event.waitUntil(offline.postMessageEvent()); } }); ``` ## Precache Resources listed in `precache.routes` are cached during the `install` event: ```js const config = compileConfig({ precache: { routes: ["/offline.html", "/styles.css"], strategy: strategyCacheOnly, eventType: "precache", // posts progress to clients (false to disable) }, }); ``` ## postMessage Communication WorkBee uses `postMessage` for ServiceWorker-to-client communication: ```js import { postMessageToAll, postMessageToFocused } from "@work-bee/core"; // Notify all open tabs await postMessageToAll({ type: "cache-updated", url: "/data" }); // Notify only the focused tab await postMessageToFocused({ type: "session-expired" }); ``` // File: packages/cache-control/ --- title: "@work-bee/cache-control" description: HTTP Cache-Control header middleware for WorkBee. --- # @work-bee/cache-control Middleware that respects HTTP `Cache-Control` headers to determine caching behavior. ## Install ```bash npm install @work-bee/cache-control ``` ## Usage ```js import { compileConfig, strategyCacheFirst } from "@work-bee/core"; import cacheControlMiddleware from "@work-bee/cache-control"; const cacheControl = cacheControlMiddleware({ cacheControl: "max-age=60", }); const config = compileConfig({ strategy: strategyCacheFirst, middlewares: [cacheControl], }); ``` ## Options | Option | Type | Required | Description | |--------|------|----------|-------------| | `cacheControl` | `string` | Yes | Cache-Control header value (e.g. `"max-age=60"`, `"no-cache"`) | ## Returns `{ afterNetwork }` ## Behavior - `max-age=0` or `no-cache` - bypasses cache, fetches from network - `max-age=N` - uses cached response if not expired - No `Cache-Control` header - falls through to default strategy // File: packages/core/ --- title: "@work-bee/core" description: Core WorkBee package with caching strategies and event handlers. --- # @work-bee/core The core package provides caching strategies and ServiceWorker event handlers. ## Install ```bash npm install @work-bee/core ``` ## Strategies ### Network Only Fetches from network, never uses cache. ```js import { strategyNetworkOnly } from "@work-bee/core"; ``` ### Cache Only Returns cached response, never fetches from network. ```js import { strategyCacheOnly } from "@work-bee/core"; ``` ### Network First Tries network first, falls back to cache on failure. ```js import { strategyNetworkFirst } from "@work-bee/core"; ``` ### Cache First Checks cache first, fetches from network if not found. ```js import { strategyCacheFirst } from "@work-bee/core"; ``` ### Stale While Revalidate Returns cached response immediately, then updates cache from network in the background. ```js import { strategyStaleWhileRevalidate } from "@work-bee/core"; ``` ### Partition Breaks a request into multiple sub-requests, each with their own strategy. ```js import { strategyPartition } from "@work-bee/core"; ``` ### HTML Partition Breaks an HTML page into parts (head, header, main, footer) that can each have their own caching strategy. ```js import { strategyHTMLPartition } from "@work-bee/core"; ``` ## Events ### compileConfig(options) Compiles a route configuration object. ```js import { compileConfig } from "@work-bee/core"; const config = compileConfig({ cachePrefix: "sw-1-", routes: [...], precache: { routes: [...], strategy: strategyCacheOnly }, middlewares: [...], }); ``` ### installEvent(event, config) Handles the ServiceWorker `install` event. Pre-caches resources if configured. ### activateEvent(event, config) Handles the `activate` event. Cleans up old caches. ### fetchEvent(event, config) Handles the `fetch` event. Routes requests to the appropriate strategy. ## RouteConfig Each route in the `routes` array can have these properties: | Property | Type | Default | Description | |----------|------|---------|-------------| | `pathPattern` | `RegExp` | — | Pattern to match request URLs | | `methods` | `string[]` | `["GET"]` | HTTP methods this route handles | | `cacheName` | `string` | — | Name for the cache storage | | `cachePrefix` | `string` | `""` | Prefix prepended to cache names | | `cacheControlMaxAge` | `number` | — | Max age in seconds for cache entries | | `strategy` | `Strategy` | — | Caching strategy for this route | | `middlewares` | `Middleware[]` | `[]` | Middleware to apply to this route | ## Middleware Lifecycle Middleware hooks run in this order for each request: 1. **`before`** — Runs before anything else. Can modify the request. 2. **`beforeNetwork`** — Runs before the network fetch (if the strategy fetches). 3. *Strategy executes* (fetch from network/cache) 4. **`afterNetwork`** — Runs after the network response is received. Can modify the response. 5. **`after`** — Runs last. Can modify the final response (e.g. fallback on error). ## Precache Configure precaching in the top-level config: ```js const config = compileConfig({ precache: { routes: ["/path/to/file.html", { path: "/other/file.js" }], strategy: strategyCacheOnly, eventType: "precache", // postMessage event type (false to disable) }, }); ``` ## postMessage Utilities ```js import { postMessageToAll, postMessageToFocused } from "@work-bee/core"; ``` - `postMessageToAll(message)` — Posts a message to all controlled window clients - `postMessageToFocused(message)` — Posts a message to the focused window client // File: packages/fallback/ --- title: "@work-bee/fallback" description: Fallback response middleware for WorkBee. --- # @work-bee/fallback Middleware that provides a fallback response when the primary strategy fails. ## Install ```bash npm install @work-bee/fallback ``` ## Usage ```js import { compileConfig, strategyNetworkOnly, strategyCacheOnly, } from "@work-bee/core"; import fallbackMiddleware from "@work-bee/fallback"; const fallback = fallbackMiddleware({ path: "/offline.html", statusCodes: [503, 504], }); const config = compileConfig({ precache: { routes: [{ path: "/offline.html" }], strategy: strategyCacheOnly, }, strategy: strategyNetworkOnly, middlewares: [fallback], }); ``` ## Options | Option | Type | Default | Description | |--------|------|---------|-------------| | `path` | `string` | — | Path to the fallback resource (should be pre-cached) | | `pathPattern` | `RegExp` | — | Pattern to match for fallback (alternative to `path`) | | `statusCodes` | `number[]` | Error responses | HTTP status codes that trigger the fallback | | `fallbackStrategy` | `Strategy` | `strategyCacheFirst` | Strategy used to fetch the fallback resource | ## Returns `{ after }` // File: packages/inactivity/ --- title: "@work-bee/inactivity" description: User inactivity detection middleware for WorkBee. --- # @work-bee/inactivity Middleware that detects user inactivity and can trigger actions like cache cleanup. ## Install ```bash npm install @work-bee/inactivity ``` ## Usage ```js import { compileConfig, strategyCacheFirst } from "@work-bee/core"; import inactivityMiddleware from "@work-bee/inactivity"; const inactivity = inactivityMiddleware({ inactivityAllowedInMin: 30, }); const config = compileConfig({ strategy: strategyCacheFirst, middlewares: [inactivity], }); addEventListener("message", (event) => { const { data } = event; if (data.type === "inactivity") { inactivity.postMessageEvent(); } }); ``` ## Options | Option | Type | Default | Description | |--------|------|---------|-------------| | `inactivityAllowedInMin` | `number` | — | Minutes of inactivity before triggering the event | | `inactivityEvent` | `() => void` | — | Callback fired when inactivity threshold is reached | ## Returns `{ before, after, postMessageEvent }` ## Client Integration Import and initialize the client-side script to send activity events to the ServiceWorker: ```js import initInactivityClient from "@work-bee/inactivity/client.js"; // Use default events (keypress, mousedown, mousemove, scroll, touch, etc.) initInactivityClient(); // Or specify custom events initInactivityClient(["keypress", "mousedown", "scroll"]); ``` This listens for user interaction events and posts `{ type: "inactivity" }` messages to the ServiceWorker. // File: packages/logger/ --- title: "@work-bee/logger" description: Logging middleware for WorkBee. --- # @work-bee/logger Middleware that logs ServiceWorker requests and responses for debugging. ## Install ```bash npm install @work-bee/logger ``` ## Usage ```js import { compileConfig, strategyCacheFirst } from "@work-bee/core"; import loggerMiddleware from "@work-bee/logger"; const logger = loggerMiddleware(); const config = compileConfig({ strategy: strategyCacheFirst, middlewares: [logger], }); ``` ## Options | Option | Type | Default | Description | |--------|------|---------|-------------| | `logger` | `(when, request, response, event, config) => void` | `console.log` | Custom logging function | | `runOnBefore` | `boolean` | `true` | Log during the `before` middleware phase | | `runOnBeforeNetwork` | `boolean` | `true` | Log during the `beforeNetwork` phase | | `runOnAfterNetwork` | `boolean` | `true` | Log during the `afterNetwork` phase | | `runOnAfter` | `boolean` | `true` | Log during the `after` phase | ## Returns `{ before, beforeNetwork, afterNetwork, after }` (each is `false` when disabled) // File: packages/offline/ --- title: "@work-bee/offline" description: Offline request queueing middleware for WorkBee. --- # @work-bee/offline Middleware that queues failed requests when offline and replays them when connectivity returns. ## Install ```bash npm install @work-bee/offline ``` ## Usage ### ServiceWorker ```js import { compileConfig, strategyCacheFirst } from "@work-bee/core"; import offlineMiddleware from "@work-bee/offline"; const offline = offlineMiddleware({ pollDelay: 0 }); const config = compileConfig({ strategy: strategyCacheFirst, middlewares: [offline], }); addEventListener("message", (event) => { const { data } = event; event.waitUntil(messageEvents[data.type](data)); }); const messageEvents = { online: offline.postMessageEvent, }; ``` ### Client When the browser comes back online, notify the ServiceWorker: ```js navigator.serviceWorker.controller.postMessage({ type: "online" }); ``` ## Options | Option | Type | Default | Description | |--------|------|---------|-------------| | `methods` | `string[]` | — | HTTP methods to queue when offline | | `statusCodes` | `number[]` | — | Status codes that indicate offline state | | `pollDelay` | `number` | — | Delay in ms between retry polls (0 to disable) | | `postMessage` | `(message) => Promise` | `postMessageToAll` | Function to send messages to clients | | `enqueueEventType` | `string` | — | Event type posted when a request is enqueued | | `quotaExceededEventType` | `string` | — | Event type posted when IndexedDB quota exceeded | | `dequeueEventType` | `string` | — | Event type posted when requests are dequeued | | `objectStoreName` | `string` | — | IndexedDB object store name | ## Returns `{ afterNetwork, postMessageEvent }` ## Utility Exports ```js import { idbSerializeRequest, idbDeserializeRequest } from "@work-bee/offline"; ``` - `idbSerializeRequest(request)` — Serializes a Request for IndexedDB storage - `idbDeserializeRequest(data)` — Deserializes stored data back into a Request ## Client Integration ```js import initOfflineClient from "@work-bee/offline/client.js"; initOfflineClient(); ``` This listens for the browser's `online` event and posts `{ type: "online" }` to the ServiceWorker when connectivity returns. // File: packages/save-data/ --- title: "@work-bee/save-data" description: Save-Data header middleware for WorkBee. --- # @work-bee/save-data Middleware that adjusts caching strategy based on the `Save-Data` request header. ## Install ```bash npm install @work-bee/save-data ``` ## Usage ```js import { compileConfig, strategyCacheFirst, strategyCacheOnly, } from "@work-bee/core"; import saveDataMiddleware from "@work-bee/save-data"; const saveData = saveDataMiddleware({ saveDataStrategy: strategyCacheOnly, }); const config = compileConfig({ strategy: strategyCacheFirst, middlewares: [saveData], }); ``` ## Options | Option | Type | Required | Description | |--------|------|----------|-------------| | `saveDataStrategy` | `Strategy` | Yes | The strategy to use when `Save-Data: on` header is present | ## Returns `{ before }` ## Behavior When the `Save-Data: on` header is present, the middleware can switch to a more cache-heavy strategy to reduce network usage. // File: packages/session/ --- title: "@work-bee/session" description: Session management middleware for WorkBee. --- # @work-bee/session Middleware for managing user sessions within the ServiceWorker. ## Install ```bash npm install @work-bee/session ``` ## Usage ```js import { compileConfig, strategyCacheFirst } from "@work-bee/core"; import sessionMiddleware, { getTokenAuthorization, getExpiryJWT, setTokenAuthorization, } from "@work-bee/session"; const session = sessionMiddleware({ authnMethods: ["POST"], authnPathPattern: /\/auth\/login$/, authnGetToken: getTokenAuthorization, authnGetExpiry: getExpiryJWT, authzPathPattern: /\/api\//, authzSetToken: setTokenAuthorization, }); const config = compileConfig({ strategy: strategyCacheFirst, middlewares: [session], }); ``` ## Options | Option | Type | Default | Description | |--------|------|---------|-------------| | `authnMethods` | `string[]` | — | HTTP methods for authentication requests | | `authnPathPattern` | `RegExp` | — | Pattern matching authentication endpoints | | `authnGetToken` | `(response) => string` | — | Extract auth token from response | | `authnGetExpiry` | `(response, token) => number` | — | Extract token expiry timestamp | | `authzPathPattern` | `RegExp` | — | Pattern matching endpoints that need authorization | | `authzSetToken` | `(request, token) => Request` | — | Attach auth token to outgoing request | | `inactivityPromptEventType` | `string` | — | Event type posted before session expiry | | `postMessage` | `(message) => Promise` | — | Function to send messages to clients | | `unauthnPathPattern` | `RegExp` | — | Pattern matching logout/unauthenticate endpoints | | `expiryEventType` | `string` | — | Event type posted when session expires | ## Returns `{ before, afterNetwork, after, activityEvent }` ## Helper Exports ```js import { getTokenAuthorization, getExpiryJWT, getExpiryPaseto, setTokenAuthorization, } from "@work-bee/session"; ``` - `getTokenAuthorization(response)` — Extracts Bearer token from Authorization header - `getExpiryJWT(response, token)` — Extracts expiry from a JWT token - `getExpiryPaseto(response, token)` — Extracts expiry from a PASETO token - `setTokenAuthorization(request, token)` — Sets the Authorization Bearer header on a request // File: quick-start/ --- title: Quick Start description: Get started with WorkBee in minutes. --- # Quick Start ## Install ```bash npm install @work-bee/core ``` ## Basic Setup Create a `sw.js` file for your ServiceWorker: ```js import { compileConfig, eventInstall, eventActivate, eventFetch, strategyCacheFirst } from "@work-bee/core"; const config = compileConfig({ cachePrefix: "sw-", routes: [ { methods: ["GET"], pathPattern: new RegExp("/img/(.+)$"), cacheName: "img", strategy: strategyCacheFirst, }, ], }); addEventListener("install", (event) => { eventInstall(event, config); }); addEventListener("activate", (event) => { eventActivate(event, config); }); addEventListener("fetch", (event) => { eventFetch(event, config); }); ``` ## Register the ServiceWorker In your main application code: ```js if ("serviceWorker" in navigator) { navigator.serviceWorker.register("/sw.js"); } ``` ## Adding Middleware Install a middleware package and add it to your config: ```bash npm install @work-bee/fallback ``` ```js import { strategyNetworkOnly, strategyCacheOnly } from "@work-bee/core"; import fallbackMiddleware from "@work-bee/fallback"; const fallback = fallbackMiddleware({ path: "/offline.html" }); const config = compileConfig({ precache: { routes: [{ path: "/offline.html" }], strategy: strategyCacheOnly, }, strategy: strategyNetworkOnly, middlewares: [fallback], }); ```