{"id":20901574,"url":"https://github.com/willfarrell/workbee","last_synced_at":"2026-04-26T09:32:34.293Z","repository":{"id":142528803,"uuid":"551116990","full_name":"willfarrell/workbee","owner":"willfarrell","description":"A tiny ServiceWorker for secure web applications.","archived":false,"fork":false,"pushed_at":"2026-04-20T11:03:01.000Z","size":1160,"stargazers_count":5,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-20T13:13:43.968Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://workbee.js.org","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/willfarrell.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["willfarrell"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2022-10-13T21:40:50.000Z","updated_at":"2026-04-18T23:01:19.000Z","dependencies_parsed_at":null,"dependency_job_id":"6b3bed58-f840-47ac-bee8-a28145130f9d","html_url":"https://github.com/willfarrell/workbee","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/willfarrell/workbee","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/willfarrell%2Fworkbee","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/willfarrell%2Fworkbee/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/willfarrell%2Fworkbee/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/willfarrell%2Fworkbee/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/willfarrell","download_url":"https://codeload.github.com/willfarrell/workbee/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/willfarrell%2Fworkbee/sbom","scorecard":{"id":1245980,"data":{"date":"2026-04-12T15:23:40Z","repo":{"name":"github.com/willfarrell/workbee","commit":"aafa6f291e8cd855fee76361f60b03bceacbfc55"},"scorecard":{"version":"v5.3.0","commit":"c22063e786c11f9dd714d777a687ff7c4599b600"},"score":8.8,"checks":[{"name":"Maintained","score":10,"reason":"30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#maintained"}},{"name":"Dependency-Update-Tool","score":10,"reason":"update tool detected","details":["Info: detected update tool: Dependabot: .github/dependabot.yml:1"],"documentation":{"short":"Determines if the project uses a dependency update tool.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#dependency-update-tool"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#dangerous-workflow"}},{"name":"Pinned-Dependencies","score":10,"reason":"all dependencies are pinned","details":["Info:  33 out of  33 GitHub-owned GitHubAction dependencies pinned","Info:   6 out of   6 third-party GitHubAction dependencies pinned","Info:   9 out of   9 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#binary-artifacts"}},{"name":"Code-Review","score":10,"reason":"all changesets reviewed","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#code-review"}},{"name":"Security-Policy","score":10,"reason":"security policy file detected","details":["Info: security policy file detected: SECURITY.md:1","Info: Found linked content: SECURITY.md:1","Info: Found disclosure, vulnerability, and/or timelines in security policy: SECURITY.md:1","Info: Found text in security policy: SECURITY.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#security-policy"}},{"name":"Token-Permissions","score":10,"reason":"GitHub workflow tokens follow principle of least privilege","details":["Info: jobLevel 'contents' permission set to 'read': .github/workflows/release.yml:23","Warn: jobLevel 'contents' permission set to 'write': .github/workflows/release.yml:75","Info: jobLevel 'contents' permission set to 'read': .github/workflows/release.yml:104","Info: jobLevel 'actions' permission set to 'read': .github/workflows/test-sast.yml:101","Info: jobLevel 'contents' permission set to 'read': .github/workflows/test-sast.yml:102","Warn: jobLevel 'contents' permission set to 'write': .github/workflows/website-cloudflare-pages.yml:23","Info: topLevel permissions set to 'read-all': .github/workflows/ossf-scorecard.yml:19","Info: topLevel 'contents' permission set to 'read': .github/workflows/release.yml:14","Info: topLevel 'contents' permission set to 'read': .github/workflows/test-dast.yml:10","Info: topLevel 'contents' permission set to 'read': .github/workflows/test-dco.yml:7","Info: topLevel 'contents' permission set to 'read': .github/workflows/test-lint.yml:10","Info: topLevel 'contents' permission set to 'read': .github/workflows/test-perf.yml:10","Info: topLevel 'contents' permission set to 'read': .github/workflows/test-sast.yml:13","Info: topLevel 'contents' permission set to 'read': .github/workflows/test-types.yml:10","Info: topLevel 'contents' permission set to 'read': .github/workflows/test-unit.yml:10","Info: topLevel 'contents' permission set to 'read': .github/workflows/website-cloudflare-pages.yml:16"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#cii-best-practices"}},{"name":"SAST","score":10,"reason":"SAST tool is run on all commits","details":["Info: SAST configuration detected: CodeQL","Info: all commits (30) are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#sast"}},{"name":"Packaging","score":10,"reason":"packaging workflow detected","details":["Info: Project packages its releases by way of GitHub Actions.: .github/workflows/release.yml:98"],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#packaging"}},{"name":"Vulnerabilities","score":0,"reason":"12 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-2crg-3p73-43xp","Warn: Project is vulnerable to: GHSA-3f6h-2hrp-w5wx","Warn: Project is vulnerable to: GHSA-3p68-rc4w-qgx5","Warn: Project is vulnerable to: GHSA-fvcv-3m26-pcqx","Warn: Project is vulnerable to: GHSA-f886-m6hf-6m8v","Warn: Project is vulnerable to: GHSA-pxg6-pf52-xh8x","Warn: Project is vulnerable to: GHSA-jvff-x2qm-6286","Warn: Project is vulnerable to: GHSA-3v7f-55p6-f55p","Warn: Project is vulnerable to: GHSA-c2c7-rcm5-vvqj","Warn: Project is vulnerable to: GHSA-4w7w-66w2-5vf9","Warn: Project is vulnerable to: GHSA-p9ff-h696-f583","Warn: Project is vulnerable to: GHSA-v2wj-q39q-566r"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":10,"reason":"project is fuzzed","details":["Info: JavaScriptPropertyBasedTesting integration found: fixtures/fuzz.fuzz.js:4","Info: JavaScriptPropertyBasedTesting integration found: fixtures/fuzz.fuzz.js:4"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#signed-releases"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#license"}},{"name":"Branch-Protection","score":10,"reason":"branch protection is fully enabled on development and all release branches","details":["Info: 'allow deletion' disabled on branch 'main'","Info: 'force pushes' disabled on branch 'main'","Info: 'branch protection settings apply to administrators' is required to merge on branch 'main'","Info: 'stale review dismissal' is required to merge on branch 'main'","Info: required approving review count is 2 on branch 'main'","Info: codeowner review is required on branch 'main'","Info: 'last push approval' is required to merge on branch 'main'","Info: 'up-to-date branches' is required to merge on branch 'main'","Info: status check found to merge onto on branch 'main'","Info: PRs are required in order to make changes on branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#branch-protection"}},{"name":"Contributors","score":3,"reason":"project has 1 contributing companies or organizations -- score normalized to 3","details":["Info: found contributions from: middyjs"],"documentation":{"short":"Determines if the project has a set of contributors from multiple organizations (e.g., companies).","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#contributors"}},{"name":"CI-Tests","score":10,"reason":"4 out of 4 merged PRs checked by a CI test -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project runs tests before pull requests are merged.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#ci-tests"}}]},"last_synced_at":"2026-04-13T13:09:35.943Z","repository_id":142528803,"created_at":"2026-04-13T13:09:35.944Z","updated_at":"2026-04-13T13:09:35.944Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32292870,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T08:29:33.829Z","status":"ssl_error","status_checked_at":"2026-04-26T08:29:18.366Z","response_time":129,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-18T11:36:05.711Z","updated_at":"2026-04-26T09:32:34.288Z","avatar_url":"https://github.com/willfarrell.png","language":"JavaScript","readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg alt=\"workbee logo\" src=\"https://raw.githubusercontent.com/willfarrell/workbee/main/docs/img/workbee-logo.svg\"/\u003e\n  \u003cp\u003e\u003cstrong\u003eA tiny ServiceWorker for secure web applications.\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\n  \u003ca href=\"https://github.com/willfarrell/workbee/actions/workflows/test-unit.yml\"\u003e\u003cimg src=\"https://github.com/willfarrell/workbee/actions/workflows/test-unit.yml/badge.svg\" alt=\"GitHub Actions unit test status\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/willfarrell/workbee/actions/workflows/test-dast.yml\"\u003e\u003cimg src=\"https://github.com/willfarrell/workbee/actions/workflows/test-dast.yml/badge.svg\" alt=\"GitHub Actions dast test status\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/willfarrell/workbee/actions/workflows/test-perf.yml\"\u003e\u003cimg src=\"https://github.com/willfarrell/workbee/actions/workflows/test-perf.yml/badge.svg\" alt=\"GitHub Actions perf test status\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/willfarrell/workbee/actions/workflows/test-sast.yml\"\u003e\u003cimg src=\"https://github.com/willfarrell/workbee/actions/workflows/test-sast.yml/badge.svg\" alt=\"GitHub Actions SAST test status\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/willfarrell/workbee/actions/workflows/test-lint.yml\"\u003e\u003cimg src=\"https://github.com/willfarrell/workbee/actions/workflows/test-lint.yml/badge.svg\" alt=\"GitHub Actions lint test status\"\u003e\u003c/a\u003e\n  \u003cbr/\u003e\n  \u003ca href=\"https://www.npmjs.com/package/@work-bee/core\"\u003e\u003cimg alt=\"npm version\" src=\"https://img.shields.io/npm/v/@work-bee/core.svg\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://packagephobia.com/result?p=@work-bee/core\"\u003e\u003cimg src=\"https://packagephobia.com/badge?p=@work-bee/core\" alt=\"npm install size\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/@work-bee/core\"\u003e\u003cimg alt=\"npm weekly downloads\" src=\"https://img.shields.io/npm/dw/@work-bee/core.svg\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/@work-bee/core#provenance\"\u003e\n  \u003cimg alt=\"npm provenance\" src=\"https://img.shields.io/badge/provenance-Yes-brightgreen\"\u003e\u003c/a\u003e\n  \u003cbr/\u003e\n  \u003ca href=\"https://scorecard.dev/viewer/?uri=github.com/willfarrell/workbee\"\u003e\u003cimg src=\"https://api.scorecard.dev/projects/github.com/willfarrell/workbee/badge\" alt=\"Open Source Security Foundation (OpenSSF) Scorecard\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://slsa.dev\"\u003e\u003cimg src=\"https://slsa.dev/images/gh-badge-level3.svg\" alt=\"SLSA 3\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/willfarrell/workbee/blob/main/CONTRIBUTING.md\"\u003e\u003cimg src=\"https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://biomejs.dev\"\u003e\u003cimg alt=\"Checked with Biome\" src=\"https://img.shields.io/badge/Checked_with-Biome-60a5fa?style=flat\u0026logo=biome\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://conventionalcommits.org\"\u003e\u003cimg alt=\"Conventional Commits\" src=\"https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196?logo=conventionalcommits\u0026logoColor=white\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\u003cp\u003eYou can read the documentation at: \u003ca href=\"https://workbee.js.org\"\u003ehttps://workbee.js.org\u003c/a\u003e\u003c/p\u003e\n\u003c/div\u003e\n\n## Features\n\n- Free to use under MIT license\n- Small and modular (up to 1KB minify + brotli)\n- Tree-shaking supported\n- Zero (0) dependencies\n- GDPR Compliant\n\n## Browser Support\n\nWorkBee requires [ServiceWorker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) and [Cache API](https://developer.mozilla.org/en-US/docs/Web/API/Cache) support.\n\n| Browser | Minimum Version |\n|---------|----------------|\n| Chrome  | 85+            |\n| Edge    | 85+            |\n| Firefox | 80+            |\n| Safari  | 15.4+          |\n| Opera   | 71+            |\n\nThe `@work-bee/offline` package additionally requires [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) (supported in all browsers listed above).\n\n## Getting Started\n\n### Install\n\n```bash\nnpm install @work-bee/core\n```\n\n### Basic Setup\n\n```js\nimport { compileConfig, eventInstall, eventActivate, eventFetch, strategyCacheFirst } from '@work-bee/core'\n\nconst config = compileConfig({\n  cachePrefix: '1-',\n  //precache: ['/path/to/file.ext'],\n  routes: [\n    {\n      methods: ['GET'],\n      pathPattern: new RegExp('/img/(.+)$'),\n      cacheName: 'img',\n      strategy: strategyCacheFirst\n    },\n    ...\n  ]\n})\n\naddEventListener('install', (event) =\u003e {\n  eventInstall(event, config)\n})\n\naddEventListener('activate', (event) =\u003e {\n  eventActivate(event, config)\n})\n\naddEventListener('fetch', (event) =\u003e {\n  eventFetch(event, config)\n})\n\n```\n\n## Events\n\n### Install\n\nHandles pre-caching of resources.\n\n### Activate\n\nCleans up old caches.\n\n### Fetch\n\nRoutes requests through configured strategies and middleware.\n\n### Push (future)\n\n### BackgroundFetch (future)\n\n```js\nimport { backgroundFetchSuccessEvent, backgroundFetchFailEvent } from '@work-bee/core'\n\n...\n\nself.addEventListener('backgroundfetchsuccess', (event) =\u003e {\n  backgroundFetchSuccessEvent(event)\n})\n\nself.addEventListener('backgroundfetchfail', (event) =\u003e {\n  backgroundFetchFailEvent(event)\n})\n```\n\n## Strategies\n\n### Network Only\n\n```mermaid\nsequenceDiagram\n    participant Page\n    participant ServiceWorker\n    participant Cache\n    participant Network\n    autonumber\n    Page-\u003e\u003eServiceWorker: request\n    ServiceWorker-\u003e\u003eNetwork: fetch\n\tNetwork-\u003e\u003eServiceWorker: 200: OK\n\tServiceWorker-\u003e\u003ePage: response\n```\n\n### Cache Only\n\n```mermaid\nsequenceDiagram\n    participant Page\n    participant ServiceWorker\n    participant Cache\n    participant Network\n    autonumber\n    Page-\u003e\u003eServiceWorker: request\n    ServiceWorker-\u003e\u003eCache: match\n    Cache-\u003e\u003eServiceWorker: resolve\n\tServiceWorker-\u003e\u003ePage: response\n```\n\n### Network First\n\n```mermaid\nsequenceDiagram\n    participant Page\n    participant ServiceWorker\n    participant Cache\n    participant Network\n    autonumber\n    Page-\u003e\u003eServiceWorker: request\n    ServiceWorker-\u003e\u003eNetwork: fetch\n    Network--\u003e\u003eServiceWorker: 404: Not Found\n    ServiceWorker-\u003e\u003eCache: match\n    Cache-\u003e\u003eServiceWorker: resolve\n    ServiceWorker-\u003e\u003ePage: response\n```\n\n### Cache First\n\n```mermaid\nsequenceDiagram\n    participant Page\n    participant ServiceWorker\n    participant Cache\n    participant Network\n    autonumber\n    Page-\u003e\u003eServiceWorker: request\n    ServiceWorker-\u003e\u003eCache: Cache: Not Found\n    ServiceWorker-\u003e\u003eNetwork: fetch\n\tNetwork-\u003e\u003eServiceWorker: 200: OK\n\tServiceWorker-\u003e\u003ePage: response\n```\n\n### Ignore\n\nAlways returns a synthetic `504 Gateway Timeout` response without hitting cache or network. Useful for cheaply short-circuiting a route you do not want the ServiceWorker to handle.\n\n```javascript\nimport { strategyIgnore } from '@work-bee/core'\n\nconst config = {\n  strategy: strategyIgnore\n}\n```\n\n### Cache First Ignore\n\nTries the cache; if the entry is missing or expired, returns the same synthetic `504` as `strategyIgnore` instead of hitting the network. Use when you want to serve only primed cache and fail fast otherwise.\n\n```javascript\nimport { strategyCacheFirstIgnore } from '@work-bee/core'\n\nconst config = {\n  strategy: strategyCacheFirstIgnore\n}\n```\n\n### Static\n\nReturns a pre-built `Response` (cloned on each call) for every request. Passing an `Error` instead makes the strategy reject — the failure flows through the normal error-path middleware.\n\n```javascript\nimport { strategyStatic } from '@work-bee/core'\n\nconst offlineResponse = new Response('offline', {\n  status: 503,\n  headers: { 'Content-Type': 'text/plain' }\n})\n\nconst config = {\n  strategy: strategyStatic(offlineResponse)\n}\n```\n\n### StaleWhileRevalidate\n\n```mermaid\nsequenceDiagram\n    participant Page\n    participant ServiceWorker\n    participant Cache\n    participant Network\n    autonumber\n    Page-\u003e\u003eServiceWorker: request\n    par\n        ServiceWorker-\u003e\u003estrategyCacheFirst: fetch\n        strategyCacheFirst-\u003e\u003eServiceWorker: 200: OK\n\t      ServiceWorker-\u003e\u003ePage: response\n    and Revalidate\n        ServiceWorker-\u003e\u003estrategy: fetch\n        strategy-\u003e\u003eServiceWorker: 200: OK\n        ServiceWorker-\u003e\u003eCache: put\n    end\n```\n\n### Partition\n\n```mermaid\nsequenceDiagram\n    participant Page\n    participant ServiceWorker\n    participant Cache\n    participant Network\n    autonumber\n    Page-\u003e\u003eServiceWorker: request\n    par routes[0]\n        ServiceWorker-\u003e\u003estrategy: fetch\n        strategy-\u003e\u003eServiceWorker: 200: OK\n    and routes[...]\n        ServiceWorker-\u003e\u003estrategy: fetch\n        strategy-\u003e\u003eServiceWorker: 200: OK\n    end\n    ServiceWorker-\u003e\u003ePage: response\n```\n\n### HTML Partitioning\n\nBreaks a page into parts that can each have their own strategy. ie `\u003chead\u003e`, `\u003cheader\u003e`, `\u003cmain\u003e`, and `\u003cfooter\u003e` where only the `\u003cmain\u003e` may need to be requested when multiple pages are being viewed (`\u003cmain\u003e` in this case should bootstrap the `\u003chead\u003e` using js).\n\n```mermaid\nsequenceDiagram\n    participant Page\n    participant ServiceWorker\n    participant Cache\n    participant Network\n    autonumber\n    Page-\u003e\u003eServiceWorker: request\n    par header.html\n        ServiceWorker-\u003e\u003eCache: match\n        Cache-\u003e\u003eServiceWorker: resolve\n    and main.html\n        ServiceWorker-\u003e\u003eNetwork: fetch\n        Network-\u003e\u003eServiceWorker: 200: OK\n    and footer.html\n        ServiceWorker-\u003e\u003eCache: match\n        Cache-\u003e\u003eServiceWorker: resolve\n    end\n\tServiceWorker-\u003e\u003ePage: response\n```\n\n### Request Partitioning\n\n```javascript\nimport { compileConfig, eventInstall, eventActivate, eventFetch, strategyCacheFirst, strategyPartition } from '@work-bee/core'\n\nconst config = compileConfig({\n  cachePrefix: 'sw-VERSION-',\n  routes: [\n    {\n      methods: ['GET'],\n      pathPattern: new RegExp('/api/data$'),\n      cacheName: 'data',\n      strategy: strategyPartition(compileConfig({\n        strategy: strategyCacheFirst,\n        cacheName: 'strategyPartition',\n        makeRequests: () =\u003e []\n      })),\n      cacheControlMaxAge: -1\n    },\n    ...\n  ]\n})\n\naddEventListener('install', (event) =\u003e {\n  eventInstall(event, config)\n})\n\naddEventListener('activate', (event) =\u003e {\n  eventActivate(event, config)\n})\n\naddEventListener('fetch', (event) =\u003e {\n  eventFetch(event, config)\n})\n\n```\n\n```mermaid\nsequenceDiagram\n    participant Page\n    participant ServiceWorker\n    participant Cache\n    participant Network\n    autonumber\n    Page-\u003e\u003eServiceWorker: request\n    par ?year=2000\n        ServiceWorker-\u003e\u003eCache: match\n        Cache-\u003e\u003eServiceWorker: resolve\n    and ?year=2001\n        ServiceWorker-\u003e\u003eCache: no-match\n        ServiceWorker-\u003e\u003eNetwork: fetch\n        Network-\u003e\u003eServiceWorker: 200: OK\n    end\n\tServiceWorker-\u003e\u003ePage: response\n```\n\n## Middleware\n\n### SaveData\n\nChoose strategy based on if Save-Data is enabled.\n\n### Session Management\n\nSee [@work-bee/session](https://workbee.js.org/docs/packages/session) for authentication token management, session expiry, and inactivity detection.\n\n### Offline Request Enqueue\n\n## Examples\n\nhttps://serviceworke.rs\nhttps://github.com/mdn/serviceworker-cookbook\n\n### Caching strategies\n\n#### [Network or cache](https://serviceworke.rs/strategy-network-or-cache.html)\n\n```javascript\n/* eslint-env: serviceworker */\nimport { strategyNetworkFirst } from '@work-bee/core'\n\nconst config = {\n  strategy: strategyNetworkFirst\n}\n\naddEventListener('install', (event) =\u003e {\n  eventInstall(event, config)\n})\n\naddEventListener('activate', (event) =\u003e {\n  eventActivate(event, config)\n})\n\naddEventListener('fetch', (event) =\u003e {\n  eventFetch(event, config)\n})\n```\n\n#### [Cache only](https://serviceworke.rs/strategy-cache-only.html)\n\n```javascript\n/* eslint-env: serviceworker */\nimport { strategyCacheOnly } from '@work-bee/core'\n\nconst config = {\n  strategy: strategyCacheOnly\n}\n\naddEventListener('install', (event) =\u003e {\n  eventInstall(event, config)\n})\n\naddEventListener('activate', (event) =\u003e {\n  eventActivate(event, config)\n})\n\naddEventListener('fetch', (event) =\u003e {\n  eventFetch(event, config)\n})\n```\n\n#### [Cache and update](https://serviceworke.rs/strategy-cache-and-update.html)\n\n```javascript\n/* eslint-env: serviceworker */\nimport { strategyStaleWhileRevalidate } from '@work-bee/core'\n\nconst config = {\n  strategy: strategyStaleWhileRevalidate\n}\n\naddEventListener('install', (event) =\u003e {\n  eventInstall(event, config)\n})\n\naddEventListener('activate', (event) =\u003e {\n  eventActivate(event, config)\n})\n\naddEventListener('fetch', (event) =\u003e {\n  eventFetch(event, config)\n})\n```\n\n#### Stale if error\n\nTries the network, caches successful responses gated by `Cache-Control` max-age, and on a thrown error or 5xx response falls back to any cached copy (even expired). Throws the original error only when both network and cache fail.\n\n```javascript\n/* eslint-env: serviceworker */\nimport { strategyStaleIfError } from '@work-bee/core'\n\nconst config = {\n  strategy: strategyStaleIfError\n}\n\naddEventListener('install', (event) =\u003e {\n  eventInstall(event, config)\n})\n\naddEventListener('activate', (event) =\u003e {\n  eventActivate(event, config)\n})\n\naddEventListener('fetch', (event) =\u003e {\n  eventFetch(event, config)\n})\n```\n\n#### [Cache, update and refresh](https://serviceworke.rs/strategy-cache-update-and-refresh.html)\n\nNot yet implemented.\n\n#### [Embedded fallback](https://serviceworke.rs/strategy-embedded-fallback.html)\n\n```javascript\n/* eslint-env: serviceworker */\nimport { strategyNetworkOnly, strategyCacheOnly } from '@work-bee/core'\nimport fallbackMiddleware from '@work-bee/fallback'\n\nconst fallback = fallbackMiddleware({ path: '/path/to/fallback' })\nconst config = {\n  precache: {\n    routes: [\n      {\n        path: '/path/to/fallback'\n      }\n    ],\n    strategy: strategyCacheOnly\n  },\n  strategy: strategyNetworkOnly,\n  after: [fallback.after]\n}\n\naddEventListener('install', (event) =\u003e {\n  eventInstall(event, config)\n})\n\naddEventListener('activate', (event) =\u003e {\n  eventActivate(event, config)\n})\n\naddEventListener('fetch', (event) =\u003e {\n  eventFetch(event, config)\n})\n```\n\n### Offline\n\n#### [Offline fallback](https://serviceworke.rs/offline-fallback.html)\n\n```javascript\n/* eslint-env: serviceworker */\nimport { strategyNetworkOnly, strategyCacheOnly } from '@work-bee/core'\nimport fallbackMiddleware from '@work-bee/fallback'\n\nconst fallback = fallbackMiddleware({\n  path: '/path/to/offline',\n  statusCodes: [503, 504] // or Error\n})\nconst config = {\n  precache: {\n    routes: [\n      {\n        path: '/path/to/offline'\n      }\n    ],\n    strategy: strategyCacheOnly\n  },\n  strategy: strategyNetworkOnly,\n  after: [fallback.after]\n}\n\naddEventListener('install', (event) =\u003e {\n  eventInstall(event, config)\n})\n\naddEventListener('activate', (event) =\u003e {\n  eventActivate(event, config)\n})\n\naddEventListener('fetch', (event) =\u003e {\n  eventFetch(event, config)\n})\n```\n\n#### [Offline Status](https://serviceworke.rs/offline-status.html)\n\n```javascript\n/* eslint-env: serviceworker */\nimport { strategyCacheFirst, strategyCacheOnly } from '@work-bee/core'\n\nconst config = {\n  precache: {\n    routes: [\n      {\n        path: '/path/to/required'\n      },\n      ...\n    ],\n    eventType: 'precache'\n  },\n  strategy: strategyCacheFirst\n}\n\naddEventListener('install', (event) =\u003e {\n  eventInstall(event, config)\n})\n\naddEventListener('activate', (event) =\u003e {\n  eventActivate(event, config)\n})\n\naddEventListener('fetch', (event) =\u003e {\n  eventFetch(event, config)\n})\n```\n\n#### [JSON Cache](https://serviceworke.rs/json-cache.html)\n\n```javascript\n/* eslint-env: serviceworker */\nimport { strategyCacheFirst, strategyCacheOnly } from '@work-bee/core'\n\nconst config = {\n  precache: {\n    routes: '/path/to/precache.json',\n  },\n  strategy: strategyCacheFirst\n}\n\naddEventListener('install', (event) =\u003e {\n  eventInstall(event, config)\n})\n\naddEventListener('activate', (event) =\u003e {\n  eventActivate(event, config)\n})\n\naddEventListener('fetch', (event) =\u003e {\n  eventFetch(event, config)\n})\n```\n\n### Beyond Offline\n\n#### [Local Download](https://serviceworke.rs/local-download.html)\n\nNot yet implemented.\n\n#### [Virtual Server](https://serviceworke.rs/virtual-server.html)\n\n#### [API Analytics](https://serviceworke.rs/api-analytics.html)\n\nNot yet implemented.\n\n#### [Load balancer](https://serviceworke.rs/load-balancer.html)\n\nNot yet implemented.\n\n#### [Cache from ZIP](https://serviceworke.rs/cache-from-zip.html)\n\nNot yet implemented.\n\n#### [Dependency Injection](https://serviceworke.rs/dependency-injector.html)\n\nNot yet implemented.\n\n#### [Request Deferrer](https://serviceworke.rs/request-deferrer.html)\n\n```javascript\n/* eslint-env: serviceworker */\nimport { strategyCacheFirst } from '@work-bee/core'\nimport offlineMiddleware from '@work-bee/offline'\n\nconst offline = offlineMiddleware({ pollDelay: 0 })\nconst config = {\n  strategy: strategyCacheFirst,\n  middlewares: [offline]\n}\n\naddEventListener('install', (event) =\u003e {\n  eventInstall(event, config)\n})\n\naddEventListener('activate', (event) =\u003e {\n  eventActivate(event, config)\n})\n\naddEventListener('fetch', (event) =\u003e {\n  eventFetch(event, config)\n})\n\naddEventListener('message', (event) =\u003e {\n  const { data } = event\n  event.waitUntil(messageEvents[data.type](data))\n})\nconst messageEvents = {\n  online: offline.postMessageEvent\n}\n```\n\n### Performance\n\n#### [Cache then Network](https://serviceworke.rs/cache-then-network.html)\n\n```javascript\n/* eslint-env: serviceworker */\nimport { strategyCacheFirst } from '@work-bee/core'\n\nconst config = {\n  strategy: strategyCacheFirst\n}\n\naddEventListener('install', (event) =\u003e {\n  eventInstall(event, config)\n})\n\naddEventListener('activate', (event) =\u003e {\n  eventActivate(event, config)\n})\n\naddEventListener('fetch', (event) =\u003e {\n  eventFetch(event, config)\n})\n```\n\n#### [Render Store](https://serviceworke.rs/render-store.html)\n\n```javascript\n/* eslint-env: serviceworker */\nimport {\n  compileConfig,\n  eventInstall,\n  eventActivate,\n  eventFetch,\n  cacheOverrideEvent\n} from '@work-bee/core'\n\nconst config = compileConfig({\n  strategy: strategyNetworkFirst\n})\n\naddEventListener('install', (event) =\u003e {\n  eventInstall(event, config)\n})\n\naddEventListener('activate', (event) =\u003e {\n  eventActivate(event, config)\n})\n\naddEventListener('fetch', (event) =\u003e {\n  eventFetch(event, config)\n})\n\naddEventListener('message', (event) =\u003e {\n  const { data } = event\n  /* data = {\n    type: 'cache',\n    request: new Request('/path/to/template', {method:'GET'}),\n    response: new Response('')\n  }*/\n  event.waitUntil(messageEvents[data.type](data))\n})\nconst messageEvents = {\n  cache: cacheOverrideEvent(config)\n}\n```\n\n## License\n\nLicensed under [MIT License](LICENSE). Copyright (c) 2026 [will Farrell](https://github.com/willfarrell) and the [Workbee contributors](https://github.com/willfarrell/workbee/graphs/contributors).\n","funding_links":["https://github.com/sponsors/willfarrell"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwillfarrell%2Fworkbee","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwillfarrell%2Fworkbee","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwillfarrell%2Fworkbee/lists"}