Full Code of GoogleChrome/workbox for AI

v7 1893b3f6ca3d cached
717 files
1.9 MB
479.1k tokens
723 symbols
1 requests
Download .txt
Showing preview only (2,098K chars total). Download the full file or copy to clipboard to get everything.
Repository: GoogleChrome/workbox
Branch: v7
Commit: 1893b3f6ca3d
Files: 717
Total size: 1.9 MB

Directory structure:
gitextract_424215io/

├── .gitattributes
├── .github/
│   ├── ISSUE_TEMPLATE.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       ├── pull-request.yml
│       └── scorecards-analysis.yml
├── .gitignore
├── .husky/
│   ├── .gitignore
│   ├── pre-commit
│   └── pre-push
├── .ncurc.js
├── .nvmrc
├── .prettierignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── cdn-details.json
├── demos/
│   ├── README.md
│   └── src/
│       ├── workbox-background-sync-demo/
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── public/
│       │   │   └── example.txt
│       │   ├── sw.js
│       │   └── updateServer.js
│       ├── workbox-broadcast-update-demo/
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── sw.js
│       │   └── updateServer.js
│       ├── workbox-cacheable-response/
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── server.js
│       │   └── sw.js
│       ├── workbox-core/
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── sw.js
│       │   └── updateServer.js
│       ├── workbox-expiration/
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── sw.js
│       │   └── updateServer.js
│       ├── workbox-google-analytics/
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── sw.js
│       │   └── updateServer.js
│       ├── workbox-navigation-preload/
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── sw.js
│       │   └── updateServer.js
│       ├── workbox-precaching/
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── public/
│       │   │   ├── hello-world.1234.txt
│       │   │   ├── hello-world.5678.txt
│       │   │   └── test-file.txt
│       │   ├── sw-1.js
│       │   ├── sw-2.js
│       │   └── updateServer.js
│       ├── workbox-range-requests/
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── sw.js
│       │   └── updateServer.js
│       ├── workbox-routing/
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── sw.js
│       │   └── updateServer.js
│       ├── workbox-strategies/
│       │   ├── index.html
│       │   ├── public/
│       │   │   ├── cache-first.txt
│       │   │   ├── network-first.txt
│       │   │   ├── network-only.txt
│       │   │   └── stale-while-revalidate.txt
│       │   ├── sw.js
│       │   └── updateServer.js
│       ├── workbox-streams/
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── server.js
│       │   └── sw.js
│       ├── workbox-sw/
│       │   ├── README.md
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── sw.js
│       │   └── updateServer.js
│       └── workbox-window/
│           ├── index.html
│           ├── package.json
│           ├── sw.js
│           └── updateServer.js
├── gulp-tasks/
│   ├── analyze-properties.js
│   ├── build-node-packages.js
│   ├── build-packages.js
│   ├── build-sw-packages.js
│   ├── build-window-packages.js
│   ├── build.js
│   ├── docs.js
│   ├── lint.js
│   ├── publish-cdn.js
│   ├── publish-github.js
│   ├── publish-glitch.js
│   ├── publish-lerna.js
│   ├── publish.js
│   ├── test-integration.js
│   ├── test-node.js
│   ├── test-server.js
│   ├── test.js
│   ├── transpile-typescript.js
│   └── utils/
│       ├── analyse-properties.js
│       ├── cdn-helper.js
│       ├── constants.js
│       ├── get-packages.js
│       ├── github-helper.js
│       ├── node-projects-babel.config.json
│       ├── output-filename-to-package-map.js
│       ├── package-runner.js
│       ├── pkg-path-to-name.js
│       ├── publish-helpers.js
│       ├── rollup-helper.js
│       ├── version-module.js
│       └── versioned-cdn-url.js
├── gulpfile.js
├── infra/
│   ├── pr-bot/
│   │   └── aggregate-size-plugin.js
│   ├── templates/
│   │   └── reference-docs/
│   │       └── jsdoc/
│   │           ├── lang/
│   │           │   └── en.yaml
│   │           ├── lib/
│   │           │   └── publishjob.js
│   │           ├── publish.js
│   │           ├── static/
│   │           │   └── jsdoc.css
│   │           └── views/
│   │               ├── augments.hbs
│   │               ├── classes-links.hbs
│   │               ├── details-table-row.hbs
│   │               ├── details-table.hbs
│   │               ├── implements.hbs
│   │               ├── index-all.hbs
│   │               ├── index.hbs
│   │               ├── layout.hbs
│   │               ├── params.hbs
│   │               ├── properties.hbs
│   │               ├── see.hbs
│   │               ├── signature.hbs
│   │               ├── symbol-content.hbs
│   │               ├── symbol-detail.hbs
│   │               ├── symbol-header.hbs
│   │               ├── symbol-index-section.hbs
│   │               ├── symbol-index.hbs
│   │               ├── symbol-labels.hbs
│   │               ├── symbol-overview.hbs
│   │               └── toc-yaml.hbs
│   ├── testing/
│   │   ├── activate-and-control.js
│   │   ├── activate-sw-safari.js
│   │   ├── auto-stub-logger.mjs
│   │   ├── clean-sw.js
│   │   ├── comlink/
│   │   │   ├── node-interface.js
│   │   │   ├── sw-interface.js
│   │   │   └── window-interface.js
│   │   ├── confirm-directory-contains.js
│   │   ├── env-it.js
│   │   ├── expectError.js
│   │   ├── generate-variant-tests.js
│   │   ├── helpers/
│   │   │   ├── compareResponses.mjs
│   │   │   ├── extendable-event-utils.mjs
│   │   │   ├── generateOpaqueResponse.mjs
│   │   │   ├── generateUniqueResponse.mjs
│   │   │   └── sleep.mjs
│   │   ├── server/
│   │   │   ├── cross-origin-server.js
│   │   │   ├── index.js
│   │   │   ├── request-counter.js
│   │   │   ├── routes/
│   │   │   │   ├── build-file.js
│   │   │   │   ├── comlink.js
│   │   │   │   ├── integration-html.js
│   │   │   │   ├── sw-bundle.js
│   │   │   │   ├── templates-update.js
│   │   │   │   ├── templates.js
│   │   │   │   ├── test-sw.js
│   │   │   │   ├── test-window.js
│   │   │   │   ├── unique-etag.js
│   │   │   │   └── unique-value.js
│   │   │   ├── static/
│   │   │   │   └── integration.html
│   │   │   ├── template-data.js
│   │   │   └── templates/
│   │   │       ├── integration.html.njk
│   │   │       ├── sw-clients-claim.js.njk
│   │   │       ├── sw-no-skip-waiting.js.njk
│   │   │       ├── sw-script-version.js.njk
│   │   │       ├── sw-skip-waiting-deferred.js.njk
│   │   │       ├── sw-skip-waiting-on-message.js.njk
│   │   │       ├── sw-skip-waiting.js.njk
│   │   │       ├── sw-window-ready.js.njk
│   │   │       ├── test-sw-runner.js.njk
│   │   │       ├── test-sw.html.njk
│   │   │       └── test-window.html.njk
│   │   ├── validator/
│   │   │   └── service-worker-runtime.js
│   │   ├── wait-until.js
│   │   ├── webdriver/
│   │   │   ├── IframeManager.js
│   │   │   ├── executeAsyncAndCatch.js
│   │   │   ├── runUnitTests.js
│   │   │   ├── unregisterAllSWs.js
│   │   │   └── windowLoaded.js
│   │   └── webpack-build-check.js
│   ├── type-overrides.d.ts
│   └── utils/
│       ├── AsyncDebounce.js
│       └── log-helper.js
├── javascript.eslintrc.js
├── jsdoc.conf
├── lerna.json
├── package.json
├── packages/
│   ├── workbox-background-sync/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── BackgroundSyncPlugin.ts
│   │   │   ├── Queue.ts
│   │   │   ├── QueueStore.ts
│   │   │   ├── StorableRequest.ts
│   │   │   ├── _version.ts
│   │   │   ├── index.ts
│   │   │   └── lib/
│   │   │       ├── QueueDb.ts
│   │   │       ├── QueueStore.ts
│   │   │       └── StorableRequest.ts
│   │   └── tsconfig.json
│   ├── workbox-broadcast-update/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── BroadcastCacheUpdate.ts
│   │   │   ├── BroadcastUpdatePlugin.ts
│   │   │   ├── _version.ts
│   │   │   ├── index.ts
│   │   │   ├── responsesAreSame.ts
│   │   │   └── utils/
│   │   │       └── constants.ts
│   │   └── tsconfig.json
│   ├── workbox-build/
│   │   ├── .ncurc.js
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── _types.js
│   │   │   ├── cdn-details.json
│   │   │   ├── generate-sw.ts
│   │   │   ├── get-manifest.ts
│   │   │   ├── index.ts
│   │   │   ├── inject-manifest.ts
│   │   │   ├── lib/
│   │   │   │   ├── additional-manifest-entries-transform.ts
│   │   │   │   ├── bundle.ts
│   │   │   │   ├── cdn-utils.ts
│   │   │   │   ├── copy-workbox-libraries.ts
│   │   │   │   ├── errors.ts
│   │   │   │   ├── escape-regexp.ts
│   │   │   │   ├── get-composite-details.ts
│   │   │   │   ├── get-file-details.ts
│   │   │   │   ├── get-file-hash.ts
│   │   │   │   ├── get-file-manifest-entries.ts
│   │   │   │   ├── get-file-size.ts
│   │   │   │   ├── get-source-map-url.ts
│   │   │   │   ├── get-string-details.ts
│   │   │   │   ├── get-string-hash.ts
│   │   │   │   ├── maximum-size-transform.ts
│   │   │   │   ├── modify-url-prefix-transform.ts
│   │   │   │   ├── module-registry.ts
│   │   │   │   ├── no-revision-for-urls-matching-transform.ts
│   │   │   │   ├── populate-sw-template.ts
│   │   │   │   ├── rebase-path.ts
│   │   │   │   ├── replace-and-update-source-map.ts
│   │   │   │   ├── runtime-caching-converter.ts
│   │   │   │   ├── stringify-without-comments.ts
│   │   │   │   ├── transform-manifest.ts
│   │   │   │   ├── translate-url-to-sourcemap-paths.ts
│   │   │   │   ├── validate-options.ts
│   │   │   │   └── write-sw-using-default-template.ts
│   │   │   ├── rollup-plugin-off-main-thread.d.ts
│   │   │   ├── schema/
│   │   │   │   ├── GenerateSWOptions.json
│   │   │   │   ├── GetManifestOptions.json
│   │   │   │   ├── InjectManifestOptions.json
│   │   │   │   ├── WebpackGenerateSWOptions.json
│   │   │   │   └── WebpackInjectManifestOptions.json
│   │   │   ├── strip-comments.d.ts
│   │   │   ├── templates/
│   │   │   │   └── sw-template.ts
│   │   │   └── types.ts
│   │   └── tsconfig.json
│   ├── workbox-cacheable-response/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── CacheableResponse.ts
│   │   │   ├── CacheableResponsePlugin.ts
│   │   │   ├── _version.ts
│   │   │   └── index.ts
│   │   └── tsconfig.json
│   ├── workbox-cli/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── app.ts
│   │   │   ├── bin.ts
│   │   │   └── lib/
│   │   │       ├── cleanup-stack-trace.ts
│   │   │       ├── constants.ts
│   │   │       ├── errors.ts
│   │   │       ├── help-text.ts
│   │   │       ├── logger.ts
│   │   │       ├── questions/
│   │   │       │   ├── ask-config-location.ts
│   │   │       │   ├── ask-extensions-to-cache.ts
│   │   │       │   ├── ask-questions.ts
│   │   │       │   ├── ask-root-of-web-app.ts
│   │   │       │   ├── ask-start_url-query-params.ts
│   │   │       │   ├── ask-sw-dest.ts
│   │   │       │   └── ask-sw-src.ts
│   │   │       ├── read-config.ts
│   │   │       └── run-wizard.ts
│   │   └── tsconfig.json
│   ├── workbox-core/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── _private/
│   │   │   │   ├── Deferred.ts
│   │   │   │   ├── WorkboxError.ts
│   │   │   │   ├── assert.ts
│   │   │   │   ├── cacheMatchIgnoreParams.ts
│   │   │   │   ├── cacheNames.ts
│   │   │   │   ├── canConstructReadableStream.ts
│   │   │   │   ├── canConstructResponseFromBodyStream.ts
│   │   │   │   ├── dontWaitFor.ts
│   │   │   │   ├── executeQuotaErrorCallbacks.ts
│   │   │   │   ├── getFriendlyURL.ts
│   │   │   │   ├── logger.ts
│   │   │   │   ├── resultingClientExists.ts
│   │   │   │   ├── timeout.ts
│   │   │   │   └── waitUntil.ts
│   │   │   ├── _private.ts
│   │   │   ├── _version.ts
│   │   │   ├── cacheNames.ts
│   │   │   ├── clientsClaim.ts
│   │   │   ├── copyResponse.ts
│   │   │   ├── index.ts
│   │   │   ├── models/
│   │   │   │   ├── messages/
│   │   │   │   │   ├── messageGenerator.ts
│   │   │   │   │   └── messages.ts
│   │   │   │   ├── pluginEvents.ts
│   │   │   │   └── quotaErrorCallbacks.ts
│   │   │   ├── registerQuotaErrorCallback.ts
│   │   │   ├── setCacheNameDetails.ts
│   │   │   ├── skipWaiting.ts
│   │   │   ├── types.ts
│   │   │   └── utils/
│   │   │       ├── pluginUtils.ts
│   │   │       └── welcome.ts
│   │   └── tsconfig.json
│   ├── workbox-expiration/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── CacheExpiration.ts
│   │   │   ├── ExpirationPlugin.ts
│   │   │   ├── _version.ts
│   │   │   ├── index.ts
│   │   │   └── models/
│   │   │       └── CacheTimestampsModel.ts
│   │   └── tsconfig.json
│   ├── workbox-google-analytics/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── _version.ts
│   │   │   ├── index.ts
│   │   │   ├── initialize.ts
│   │   │   └── utils/
│   │   │       └── constants.ts
│   │   └── tsconfig.json
│   ├── workbox-navigation-preload/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── _version.ts
│   │   │   ├── disable.ts
│   │   │   ├── enable.ts
│   │   │   ├── index.ts
│   │   │   └── isSupported.ts
│   │   └── tsconfig.json
│   ├── workbox-precaching/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── PrecacheController.ts
│   │   │   ├── PrecacheFallbackPlugin.ts
│   │   │   ├── PrecacheRoute.ts
│   │   │   ├── PrecacheStrategy.ts
│   │   │   ├── _types.ts
│   │   │   ├── _version.ts
│   │   │   ├── addPlugins.ts
│   │   │   ├── addRoute.ts
│   │   │   ├── cleanupOutdatedCaches.ts
│   │   │   ├── createHandlerBoundToURL.ts
│   │   │   ├── getCacheKeyForURL.ts
│   │   │   ├── index.ts
│   │   │   ├── matchPrecache.ts
│   │   │   ├── precache.ts
│   │   │   ├── precacheAndRoute.ts
│   │   │   └── utils/
│   │   │       ├── PrecacheCacheKeyPlugin.ts
│   │   │       ├── PrecacheInstallReportPlugin.ts
│   │   │       ├── createCacheKey.ts
│   │   │       ├── deleteOutdatedCaches.ts
│   │   │       ├── generateURLVariations.ts
│   │   │       ├── getCacheKeyForURL.ts
│   │   │       ├── getOrCreatePrecacheController.ts
│   │   │       ├── printCleanupDetails.ts
│   │   │       ├── printInstallDetails.ts
│   │   │       └── removeIgnoredSearchParams.ts
│   │   └── tsconfig.json
│   ├── workbox-range-requests/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── RangeRequestsPlugin.ts
│   │   │   ├── _version.ts
│   │   │   ├── createPartialResponse.ts
│   │   │   ├── index.ts
│   │   │   └── utils/
│   │   │       ├── calculateEffectiveBoundaries.ts
│   │   │       └── parseRangeHeader.ts
│   │   └── tsconfig.json
│   ├── workbox-recipes/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── _version.ts
│   │   │   ├── googleFontsCache.ts
│   │   │   ├── imageCache.ts
│   │   │   ├── index.ts
│   │   │   ├── offlineFallback.ts
│   │   │   ├── pageCache.ts
│   │   │   ├── staticResourceCache.ts
│   │   │   └── warmStrategyCache.ts
│   │   └── tsconfig.json
│   ├── workbox-routing/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── NavigationRoute.ts
│   │   │   ├── RegExpRoute.ts
│   │   │   ├── Route.ts
│   │   │   ├── Router.ts
│   │   │   ├── _types.ts
│   │   │   ├── _version.ts
│   │   │   ├── index.ts
│   │   │   ├── registerRoute.ts
│   │   │   ├── setCatchHandler.ts
│   │   │   ├── setDefaultHandler.ts
│   │   │   └── utils/
│   │   │       ├── constants.ts
│   │   │       ├── getOrCreateDefaultRouter.ts
│   │   │       └── normalizeHandler.ts
│   │   └── tsconfig.json
│   ├── workbox-strategies/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── CacheFirst.ts
│   │   │   ├── CacheOnly.ts
│   │   │   ├── NetworkFirst.ts
│   │   │   ├── NetworkOnly.ts
│   │   │   ├── StaleWhileRevalidate.ts
│   │   │   ├── Strategy.ts
│   │   │   ├── StrategyHandler.ts
│   │   │   ├── _version.ts
│   │   │   ├── index.ts
│   │   │   ├── plugins/
│   │   │   │   └── cacheOkAndOpaquePlugin.ts
│   │   │   └── utils/
│   │   │       └── messages.ts
│   │   └── tsconfig.json
│   ├── workbox-streams/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── _types.ts
│   │   │   ├── _version.ts
│   │   │   ├── concatenate.ts
│   │   │   ├── concatenateToResponse.ts
│   │   │   ├── index.ts
│   │   │   ├── isSupported.ts
│   │   │   ├── strategy.ts
│   │   │   └── utils/
│   │   │       └── createHeaders.ts
│   │   └── tsconfig.json
│   ├── workbox-sw/
│   │   ├── README.md
│   │   ├── _types.mjs
│   │   ├── _version.mjs
│   │   ├── controllers/
│   │   │   └── WorkboxSW.mjs
│   │   ├── index.mjs
│   │   └── package.json
│   ├── workbox-webpack-plugin/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── generate-sw.ts
│   │   │   ├── index.ts
│   │   │   ├── inject-manifest.ts
│   │   │   └── lib/
│   │   │       ├── get-asset-hash.ts
│   │   │       ├── get-manifest-entries-from-compilation.ts
│   │   │       ├── get-script-files-for-chunks.ts
│   │   │       ├── get-sourcemap-asset-name.ts
│   │   │       ├── relative-to-output-path.ts
│   │   │       └── resolve-webpack-url.ts
│   │   └── tsconfig.json
│   └── workbox-window/
│       ├── README.md
│       ├── package.json
│       ├── src/
│       │   ├── Workbox.ts
│       │   ├── _version.ts
│       │   ├── index.ts
│       │   ├── messageSW.ts
│       │   └── utils/
│       │       ├── WorkboxEvent.ts
│       │       ├── WorkboxEventTarget.ts
│       │       └── urlsMatch.ts
│       └── tsconfig.json
├── prettier.config.js
├── test/
│   ├── all/
│   │   └── node/
│   │       ├── test-exports.js
│   │       ├── test-jsdocs.js
│   │       ├── test-package.js
│   │       ├── test-prod-builds.js
│   │       └── test-yarn-installation.js
│   ├── workbox-background-sync/
│   │   ├── integration/
│   │   │   └── test-all.js
│   │   ├── static/
│   │   │   └── basic-example/
│   │   │       ├── example.txt
│   │   │       ├── index.html
│   │   │       └── sw.js
│   │   └── sw/
│   │       ├── lib/
│   │       │   ├── test-QueueDb.mjs
│   │       │   ├── test-QueueStore.mjs
│   │       │   └── test-StorableRequest.mjs
│   │       ├── test-BackgroundSyncPlugin.mjs
│   │       └── test-Queue.mjs
│   ├── workbox-broadcast-update/
│   │   ├── integration/
│   │   │   └── test-all.js
│   │   ├── static/
│   │   │   ├── index.html
│   │   │   └── sw.js
│   │   └── sw/
│   │       ├── test-BroadcastCacheUpdate.mjs
│   │       ├── test-BroadcastUpdatePlugin.mjs
│   │       └── test-responsesAreSame.mjs
│   ├── workbox-build/
│   │   ├── node/
│   │   │   ├── dependency-check.js
│   │   │   ├── generate-sw.js
│   │   │   ├── get-manifest.js
│   │   │   ├── inject-manifest.js
│   │   │   └── lib/
│   │   │       ├── additional-manifest-entries-transform.js
│   │   │       ├── bundle.js
│   │   │       ├── cdn-utils.js
│   │   │       ├── copy-workbox-libraries.js
│   │   │       ├── escape-regexp.js
│   │   │       ├── get-composite-details.js
│   │   │       ├── get-file-details.js
│   │   │       ├── get-file-hash.js
│   │   │       ├── get-file-manifest-entries.js
│   │   │       ├── get-file-size.js
│   │   │       ├── get-string-details.js
│   │   │       ├── get-string-hash.js
│   │   │       ├── modify-url-prefix-transform.js
│   │   │       ├── module-registry.js
│   │   │       ├── no-revision-for-urls-matching-transform.js
│   │   │       ├── populate-sw-template.js
│   │   │       ├── replace-and-update-source-map.js
│   │   │       ├── runtime-caching-converter.js
│   │   │       ├── transform-manifest.js
│   │   │       ├── translate-url-to-sourcemap-paths.js
│   │   │       ├── validate-options.js
│   │   │       └── write-sw-using-default-template.js
│   │   └── static/
│   │       ├── example-project-1/
│   │       │   ├── .hidden-directory/
│   │       │   │   ├── hello.html
│   │       │   │   └── hello.js
│   │       │   ├── index.html
│   │       │   ├── page-1.html
│   │       │   ├── page-2.html
│   │       │   ├── styles/
│   │       │   │   ├── stylesheet-1.css
│   │       │   │   └── stylesheet-2.css
│   │       │   └── webpackEntry.js
│   │       └── sw-injections/
│   │           ├── bad-multiple-injection.js
│   │           ├── bad-no-injection.js
│   │           ├── basic-with-invalid-sourcemap.js.nolint
│   │           ├── basic-with-sourcemap-data-url.js.nolint
│   │           ├── basic-with-sourcemap.js.nolint
│   │           ├── basic.js
│   │           ├── custom-injection-point.js
│   │           ├── multiple-calls.js
│   │           ├── precache-and-route-options.js
│   │           └── sample-import.js
│   ├── workbox-cacheable-response/
│   │   ├── integration/
│   │   │   └── test-all.js
│   │   ├── static/
│   │   │   └── cacheable-response-plugin/
│   │   │       ├── example-1.txt
│   │   │       └── sw.js
│   │   └── sw/
│   │       ├── test-CacheableResponse.mjs
│   │       └── test-CacheableResponsePlugin.mjs
│   ├── workbox-cli/
│   │   └── node/
│   │       ├── app.js
│   │       ├── dependency-check.js
│   │       └── lib/
│   │           ├── cleanup-stack-trace.js
│   │           ├── help-text.js
│   │           ├── logger.js
│   │           ├── questions/
│   │           │   ├── ask-config-location.js
│   │           │   ├── ask-extensions-to-cache.js
│   │           │   ├── ask-questions.js
│   │           │   ├── ask-root-of-web-app.js
│   │           │   ├── ask-start_url-query-params.js
│   │           │   ├── ask-sw-dest.js
│   │           │   └── ask-sw-src.js
│   │           └── run-wizard.js
│   ├── workbox-core/
│   │   ├── integration/
│   │   │   └── test-all.js
│   │   ├── static/
│   │   │   ├── core-in-browser/
│   │   │   │   ├── index.html
│   │   │   │   └── sw.js
│   │   │   └── logger.html
│   │   └── sw/
│   │       ├── _private/
│   │       │   ├── test-Deferred.mjs
│   │       │   ├── test-assert.mjs
│   │       │   ├── test-cacheMatchIgnoreParams.mjs
│   │       │   ├── test-executeQuotaErrorCallbacks.mjs
│   │       │   ├── test-getFriendlyURL.mjs
│   │       │   ├── test-logger.mjs
│   │       │   ├── test-resultingClientExists.mjs
│   │       │   ├── test-timeout.mjs
│   │       │   └── test-waitUntil.mjs
│   │       ├── models/
│   │       │   └── messages/
│   │       │       └── test-messageGenerator.mjs
│   │       ├── test-cacheNames.mjs
│   │       ├── test-clientsClaim.mjs
│   │       ├── test-copyResponse.mjs
│   │       ├── test-registerQuotaErrorCallback.mjs
│   │       └── test-skipWaiting.mjs
│   ├── workbox-expiration/
│   │   ├── integration/
│   │   │   └── test-all.js
│   │   ├── static/
│   │   │   ├── expiration-plugin/
│   │   │   │   ├── example-1.txt
│   │   │   │   ├── example-2.txt
│   │   │   │   ├── sw-deletion.js
│   │   │   │   ├── sw-max-age-seconds.js
│   │   │   │   └── sw-max-entries.js
│   │   │   └── isURLExpired.html
│   │   └── sw/
│   │       ├── test-CacheExpiration.mjs
│   │       ├── test-CacheTimestampsModel.mjs
│   │       └── test-ExpirationPlugin.mjs
│   ├── workbox-google-analytics/
│   │   ├── integration/
│   │   │   └── test-all.js
│   │   ├── static/
│   │   │   └── basic-example/
│   │   │       ├── index.html
│   │   │       └── sw.js
│   │   └── sw/
│   │       └── test-initialize.mjs
│   ├── workbox-navigation-preload/
│   │   ├── integration/
│   │   │   ├── test-disable.js
│   │   │   ├── test-enable.js
│   │   │   └── test-sw.js
│   │   ├── static/
│   │   │   ├── sw-custom-header.js
│   │   │   ├── sw-default-header.js
│   │   │   └── sw-disable.js
│   │   └── sw/
│   │       ├── test-disable.mjs
│   │       ├── test-enable.mjs
│   │       └── test-isSupported.mjs
│   ├── workbox-precaching/
│   │   ├── integration/
│   │   │   ├── test-cleanup-outdated-caches.js
│   │   │   ├── test-precache-and-update.js
│   │   │   └── test-sw.js
│   │   ├── static/
│   │   │   ├── addToCacheList.html
│   │   │   ├── cleanup-outdated-caches/
│   │   │   │   ├── sw.js
│   │   │   │   └── test.txt
│   │   │   ├── precache-and-update/
│   │   │   │   ├── hashed-file.abcd1234.txt
│   │   │   │   ├── index.html
│   │   │   │   ├── styles/
│   │   │   │   │   └── index.css
│   │   │   │   ├── sw-1.js
│   │   │   │   └── sw-2.js
│   │   │   ├── precache.html
│   │   │   └── project/
│   │   │       ├── example-2.html
│   │   │       ├── example-a.html
│   │   │       ├── example-b.html
│   │   │       ├── example-timestamp.html
│   │   │       ├── example.html
│   │   │       └── index.html
│   │   └── sw/
│   │       ├── resetDefaultPrecacheController.mjs
│   │       ├── test-PrecacheController.mjs
│   │       ├── test-PrecacheFallbackPlugin.mjs
│   │       ├── test-PrecacheRoute.mjs
│   │       ├── test-PrecacheStrategy.mjs
│   │       ├── test-addPlugins.mjs
│   │       ├── test-addRoute.mjs
│   │       ├── test-cleanupOutdatedCaches.mjs
│   │       ├── test-createHandlerBoundToURL.mjs
│   │       ├── test-getCacheKeyForURL.mjs
│   │       ├── test-matchPrecache.mjs
│   │       ├── test-precache.mjs
│   │       ├── test-precacheAndRoute.mjs
│   │       └── utils/
│   │           ├── test-deleteOutdatedCaches.mjs
│   │           ├── test-printCleanupDetails.mjs
│   │           └── test-printInstallDetails.mjs
│   ├── workbox-range-requests/
│   │   ├── integration/
│   │   │   └── test-all.js
│   │   ├── static/
│   │   │   ├── index.html
│   │   │   └── sw.js
│   │   └── sw/
│   │       ├── test-RangeRequestsPlugin.mjs
│   │       ├── test-createPartialResponse.mjs
│   │       └── utils/
│   │           ├── test-calculateEffectiveBoundaries.mjs
│   │           └── test-parseRangeHeader.mjs
│   ├── workbox-routing/
│   │   ├── integration/
│   │   │   ├── test-navigation-route.js
│   │   │   ├── test-routing-basic.js
│   │   │   ├── test-routing-regex.js
│   │   │   └── test-sw.js
│   │   ├── static/
│   │   │   ├── routing-basic/
│   │   │   │   ├── index.html
│   │   │   │   └── sw.js
│   │   │   ├── routing-navigation/
│   │   │   │   ├── index.html
│   │   │   │   └── sw.js
│   │   │   ├── routing-regex/
│   │   │   │   ├── index.html
│   │   │   │   └── sw.js
│   │   │   ├── routing.html
│   │   │   └── sw.js
│   │   └── sw/
│   │       ├── test-NavigationRoute.mjs
│   │       ├── test-RegExpRoute.mjs
│   │       ├── test-Route.mjs
│   │       ├── test-Router.mjs
│   │       ├── test-registerRoute.mjs
│   │       ├── test-setCatchHandler.mjs
│   │       ├── test-setDefaultHandler.mjs
│   │       └── utils/
│   │           └── test-normalizeHandler.mjs
│   ├── workbox-strategies/
│   │   ├── integration/
│   │   │   ├── test-cacheFirst.js
│   │   │   ├── test-cacheOnly.js
│   │   │   ├── test-networkFirst.js
│   │   │   ├── test-networkOnly.js
│   │   │   ├── test-staleWhileRevalidate.js
│   │   │   └── test-sw.js
│   │   ├── static/
│   │   │   ├── cache-first/
│   │   │   │   ├── example.txt
│   │   │   │   └── sw.js
│   │   │   ├── cache-only/
│   │   │   │   └── sw.js
│   │   │   ├── network-first/
│   │   │   │   └── sw.js
│   │   │   ├── network-only/
│   │   │   │   └── sw.js
│   │   │   └── stale-while-revalidate/
│   │   │       └── sw.js
│   │   └── sw/
│   │       ├── plugins/
│   │       │   └── test-cacheOkAndOpaquePlugin.mjs
│   │       ├── test-CacheFirst.mjs
│   │       ├── test-CacheOnly.mjs
│   │       ├── test-NetworkFirst.mjs
│   │       ├── test-NetworkOnly.mjs
│   │       ├── test-StaleWhileRevalidate.mjs
│   │       ├── test-Strategy.mjs
│   │       ├── test-StrategyHandler.mjs
│   │       └── test-UsageWithRouter.mjs
│   ├── workbox-streams/
│   │   ├── integration/
│   │   │   └── test-all.js
│   │   ├── static/
│   │   │   ├── 4.txt
│   │   │   ├── index.html
│   │   │   └── sw.js
│   │   └── sw/
│   │       ├── test-isSupported.mjs
│   │       └── utils/
│   │           └── test-createHeaders.mjs
│   ├── workbox-sw/
│   │   ├── integration/
│   │   │   └── test-all.js
│   │   ├── static/
│   │   │   ├── example.css
│   │   │   ├── example.js
│   │   │   ├── index.html
│   │   │   ├── integration/
│   │   │   │   ├── index.html
│   │   │   │   ├── invalid-sw.js
│   │   │   │   └── valid-sw.js
│   │   │   └── sw.js
│   │   └── sw/
│   │       └── controllers/
│   │           └── test-WorkboxSW.mjs
│   ├── workbox-webpack-plugin/
│   │   ├── node/
│   │   │   ├── dependency-check.js
│   │   │   ├── v4/
│   │   │   │   ├── generate-sw.js
│   │   │   │   ├── inject-manifest.js
│   │   │   │   └── lib/
│   │   │   │       └── create-webpack-asset-plugin.js
│   │   │   └── v5/
│   │   │       ├── generate-sw.js
│   │   │       ├── inject-manifest.js
│   │   │       └── lib/
│   │   │           └── create-webpack-asset-plugin.js
│   │   └── static/
│   │       ├── bad-multiple-injection.js
│   │       ├── example-project-1/
│   │       │   ├── index.html
│   │       │   ├── page-1.html
│   │       │   ├── page-2.html
│   │       │   ├── splitChunksEntry.js
│   │       │   ├── styles/
│   │       │   │   ├── stylesheet-1.css
│   │       │   │   └── stylesheet-2.css
│   │       │   └── webpackEntry.js
│   │       ├── injected-manifest.js
│   │       ├── injected-manifest.json
│   │       ├── module-import-sw.js
│   │       ├── sw-src-define-plugin.js
│   │       ├── sw-src-missing-sourcemap.js
│   │       ├── sw-src.js
│   │       ├── sw.ts
│   │       └── wasm-project/
│   │           ├── add.wasm
│   │           ├── index.js
│   │           └── worker.js
│   └── workbox-window/
│       ├── integration/
│       │   └── test-all.js
│       ├── static/
│       │   └── index.html
│       └── window/
│           ├── sw-error.js
│           ├── sw-message-reply.js
│           └── test-Workbox.mjs
├── tsconfig.json
└── typescript.eslintrc.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================
*.js text eol=lf
*.mjs text eol=lf

================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
Welcome! Please use this template for reporting bugs or requesting features. For questions about using Workbox, the best place to ask is Stack Overflow, tagged with `[workbox]`: https://stackoverflow.com/questions/ask?tags=workbox

**Library Affected**:
_workbox-sw, workbox-build, etc._

**Browser & Platform**:
_E.g. Google Chrome v51.0.1 for Android, or "all browsers"._

**Issue or Feature Request Description**:
_Your request here._

_When reporting bugs, please include relevant JavaScript Console logs and links to public URLs at which the issue could be reproduced._


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
**Prior to creating a pull request, please follow all the steps in the [contributing guide](https://github.com/GoogleChrome/workbox/blob/v6/CONTRIBUTING.md).**

Fixes #_issue number_

_Description of what's changed/fixed._


================================================
FILE: .github/workflows/pull-request.yml
================================================
name: Test Suite

on: [pull_request]

jobs:
  Node_Tests_Windows:
    runs-on: windows-latest

    steps:
      - uses: actions/checkout@v5

      - uses: actions/setup-node@v6
        with:
          node-version-file: '.nvmrc'

      - name: Get npm cache directory
        id: npm-cache
        run: |
          echo "::set-output name=dir::$(npm config get cache)"
      - uses: actions/cache@v4
        with:
          path: ${{ steps.npm-cache.outputs.dir }}
          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-node-

      - name: Setup
        run: |
          npm ci
          npx gulp build

      - run: npx gulp test_node

  Full_Suite_Mac:
    runs-on: macos-latest

    steps:
      - uses: actions/checkout@v5

      - uses: actions/setup-node@v6
        with:
          node-version-file: '.nvmrc'

      - uses: actions/cache@v4
        with:
          path: ~/.npm
          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-node-

      - uses: actions/cache@v4
        with:
          path: ~/.selenium-assistant
          key: ${{ runner.os }}

      - name: Setup
        run: |
          sudo safaridriver --enable
          npm ci
          npx gulp build

      - run: npx gulp test


================================================
FILE: .github/workflows/scorecards-analysis.yml
================================================
name: Scorecards supply-chain security
on:
  # Only the default branch is supported.
  branch_protection_rule:
  schedule:
    - cron: '33 8 * * 4'
  push:
    branches: [v7]

# Declare default permissions as read only.
permissions: read-all

jobs:
  analysis:
    name: Scorecards analysis
    runs-on: ubuntu-latest
    permissions:
      # Needed to upload the results to code-scanning dashboard.
      security-events: write
      # Used to receive a badge. (Upcoming feature)
      id-token: write
      actions: read
      contents: read

    steps:
      - name: 'Checkout code'
        uses: actions/checkout@v5
        with:
          persist-credentials: false

      - name: 'Run analysis'
        uses: ossf/scorecard-action@v2.4.3
        with:
          results_file: results.sarif
          results_format: sarif
          # Read-only PAT token. To create it,
          # follow the steps in https://github.com/ossf/scorecard-action#pat-token-creation.
          repo_token: ${{ secrets.SCORECARD_READ_TOKEN }}
          # Publish the results to enable scorecard badges. For more details, see
          # https://github.com/ossf/scorecard-action#publishing-results.
          # For private repositories, `publish_results` will automatically be set to `false`, regardless
          # of the value entered here.
          publish_results: true

      # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
      # format to the repository Actions tab.
      - name: 'Upload artifact'
        uses: actions/upload-artifact@v5
        with:
          name: SARIF file
          path: results.sarif
          retention-days: 5

      # Upload the results to GitHub's code scanning dashboard.
      - name: 'Upload to code-scanning'
        uses: github/codeql-action/upload-sarif@v4
        with:
          sarif_file: results.sarif


================================================
FILE: .gitignore
================================================
.DS_Store
build
lerna-debug.log
node_modules
npm-debug.log
packages/**/LICENSE
temp
tmp-*
!packages/workbox-cli/test/static/example-project-1/node_modules
coverage/
generated-release-files/
workbox-*.json
.esm-cache/
.nyc_output/
.rpt2_cache/
docs
local-builds/
firebase-debug.log
.firebase

# Generated TypeScript files and build data
tsconfig.tsbuildinfo
packages/workbox-*/**/*.d.ts
!packages/workbox-*/src/**/*.d.ts
packages/workbox-*/**/*.js
!packages/workbox-build/**/*.js
!packages/workbox-webpack-plugin/**/*.js

# Individual package ignores during TypeScript migration
packages/workbox-background-sync/**/*.mjs
packages/workbox-broadcast-update/**/*.mjs
packages/workbox-cacheable-response/**/*.mjs
packages/workbox-core/**/*.mjs
packages/workbox-expiration/**/*.mjs
packages/workbox-google-analytics/**/*.mjs
packages/workbox-navigation-preload/**/*.mjs
packages/workbox-precaching/**/*.mjs
packages/workbox-range-requests/**/*.mjs
packages/workbox-recipes/**/*.mjs
packages/workbox-routing/**/*.mjs
packages/workbox-strategies/**/*.mjs
packages/workbox-streams/**/*.mjs
packages/workbox-window/**/*.mjs


================================================
FILE: .husky/.gitignore
================================================
_


================================================
FILE: .husky/pre-commit
================================================
#!/bin/sh

# Please see https://typicode.github.io/husky/#/?id=command-not-found
# if you have trouble running this command.

. "$(dirname "$0")/_/husky.sh"

npm run lint-staged


================================================
FILE: .husky/pre-push
================================================
#!/bin/sh

# Please see https://typicode.github.io/husky/#/?id=command-not-found
# if you have trouble running this command.

. "$(dirname "$0")/_/husky.sh"

npm run lint


================================================
FILE: .ncurc.js
================================================
// We use `npx npm-check-updates` to find updates to dependencies.
// Some dependencies have breaking changes that we can't resolve.
// This config file excludes those dependencies from the checks
// until we're able to remediate our code to deal with them.

module.exports = {
  reject: [
    // See https://github.com/GoogleChrome/workbox/issues/2479
    'service-worker-mock',
  ],
};


================================================
FILE: .nvmrc
================================================
20


================================================
FILE: .prettierignore
================================================
_version.ts
.nyc_output
.vscode
*.hbs
*.log
build
coverage
docs
generated-release-files
node_modules
package-lock.json
packages/**/*.d.ts
packages/**/*.js
packages/**/*.mjs
packages/workbox-build/src/schema/*.json
temp
test/workbox-webpack-plugin/static/injected-manifest.json


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Code of Conduct

All Google open source projects are covered by our [community guidelines](https://opensource.google/conduct/) which define the kind of respectful behavior we expect of all participants.


================================================
FILE: CONTRIBUTING.md
================================================
# How to become a contributor and submit your own code

## Contributor License Agreements

We'd love to accept your patches! Before we can take them, we have to jump a couple of legal hurdles.

Please fill out either the individual or corporate Contributor License Agreement (CLA).

- If you are an individual writing original source code and you're sure you own the intellectual property, then you'll need to sign an [individual CLA](https://developers.google.com/open-source/cla/individual).
- If you work for a company that wants to allow you to contribute your work, then you'll need to sign a [corporate CLA](https://developers.google.com/open-source/cla/corporate).

Follow either of the two links above to access the appropriate CLA and instructions for how to sign and return it. Once we receive it, we'll be able to
accept your pull requests.

## Contributing A Patch

1. Submit an issue describing your proposed change to the repo in question.
1. The repo owner will respond to your issue promptly.
1. If your proposed change is accepted, and you haven't already done so, sign a Contributor License Agreement (see details above).
1. Fork the repo, develop and test your code changes (see details below).
1. Ensure that your code adheres to the existing style in the sample to which you are contributing.
1. Submit a pull request.

## Setting up your environment

Workbox uses [`node`](https://nodejs.org/) and its related toolchain (`npm`, etc.) to install dependencies and run the build and test processes. Please ensure that you have a working `node` installation before proceeding.

Workbox uses `git` hooks via [`husky`](https://typicode.github.io/husky/#/) to automatically run code formatters and linters when committing and pushing code to GitHub. If you're running into issues with the `git` hooks, you may need to [create a `~/.huskyrc` file](https://typicode.github.io/husky/#/?id=command-not-found) to set up your `$PATH` correctly.

It's expected that the Workbox development environment should work on Windows, macOS, and Linux. If you encounter any platform-specific issues, please [open a bug](https://github.com/GoogleChrome/workbox/issues/new).

## Testing your contribution

When making local changes, you'll probably want to ensure that your code builds and passes our test suite. To do this, run the following in your local clone of the repo:

```sh
$ npm ci

$ npm run gulp build

$ npm run gulp test
```

Note that on Windows, `npm run gulp test` will only run a subset of our test suite. The full test suite will always be run as part of the GitHub continuous integration environment against your pull request.

When you add a new feature or fix a bug, please check the test suite to see if its appropriate to add or modify an existing test to cover the updated functionality.

## Running a subset of the tests

Workbox's test suite is split in two parts: one for the `node`-based tooling (`workbox-cli`, `workbox-build`, `workbox-webpack-plugin`) and one for the browser-based code.

To run the tests for just the `node`-based tooling:

```sh
npm run gulp test_node
```

To interactively run tests for the browser-based code, launch the test server:

```sh
npm run gulp test_server
```

Then open a web browser to http://localhost:3004/ and navigate to the test suite for the package you're interested in. For example, to run the tests for `workbox-strategies`, go to http://localhost:3004/test/workbox-streams/sw/

To do an automated run of the browser-based test suite against the full set of supported browsers, run:

```sh
npm run gulp test_integration
```


================================================
FILE: LICENSE
================================================
Copyright 2018 Google LLC

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.


================================================
FILE: README.md
================================================
<img src='https://user-images.githubusercontent.com/110953/28352645-7a8a66d8-6c0c-11e7-83af-752609e7e072.png' width='500px'/>

# Welcome to Workbox!

Workbox is a collection of JavaScript libraries for
[Progressive Web Apps](https://web.dev/progressive-web-apps/).

## Documentation

- [Overview](https://developer.chrome.com/docs/workbox/)
- [Get started](https://developer.chrome.com/docs/workbox/what-is-workbox)
- [Contribute](CONTRIBUTING.md)

## Maintenance update

Workbox is a powerful library originally developed by members of Chrome's
developer relations team to facilitate the creation of Progressive Web Apps
and to improve the offline experience of web applications. It offers a suite
of tools and strategies for efficiently caching and serving web assets,
managing service workers, and handling offline scenarios. Workbox simplifies
the implementation of common caching patterns and provides developers with a
comprehensive toolkit to build robust, resilient web applications. From now
on, [Chrome's Aurora team](https://developer.chrome.com/docs/aurora) will be
the new owners of Workbox.

## Contributing

Development happens in the open on GitHub. We're thankful to the community for
contributing any improvements.

Please read the [guide to contributing](CONTRIBUTING.md) for information about
setting up your environment and other requirements prior to filing any
pull requests.

## License

MIT. See [LICENSE](LICENSE) for details.


================================================
FILE: cdn-details.json
================================================
{
  "origin": "https://storage.googleapis.com",
  "bucketName": "workbox-cdn",
  "releasesDir": "releases"
}


================================================
FILE: demos/README.md
================================================
# workbox-module-demos

Contains sample demos that are deployed to Glitch at https://glitch.com/@philkrie/workbox-demos and used as examples at https://developers.google.com/web/tools/workbox/modules


================================================
FILE: demos/src/workbox-background-sync-demo/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>workbox-background-sync demo</title>
    <meta
      name="workbox-background-sync demo"
      content="An example to demonstrate the workbox-background-sync module"
    />
    <link
      id="favicon"
      rel="icon"
      href="https://glitch.com/edit/favicon-app.ico"
      type="image/x-icon"
    />
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style>
      body {
        margin-left: 5%;
        font-family: 'Open Sans', sans-serif;
      }
      ol {
        padding-left: 20px;
      }
      li {
        margin-bottom: 5px;
      }
      button {
        margin: 20px 0;
        font-weight: bold;
      }
    </style>
  </head>
  <body>
    <header>
      <div>
        <h1>workbox-background-sync Demo</h1>
      </div>
    </header>

    <ol>
      <li>
        <a href="https://developers.google.com/web/tools/chrome-devtools/#open"
          >Open DevTools.</a
        >
      </li>
      <li>Switch to the Network panel.</li>
      <li>Toggle `Disable cache` checkbox on (it's unchecked by default).</li>
      <li>Click `Make Fetch request` button below.</li>
      <li>Observe that request is successfully completed with status 200.</li>
      <li>
        Disconnect from actual network (DevTools offline doesn't work for
        background sync).
      </li>
      <li>Again, click `Make Fetch request` button below.</li>
      <li>Observe that request is aborted due to no network.</li>
      <li>
        Connect to your network and observe the Network panel in DevTools.
      </li>
      <li>
        Once the network is connected, you will see that the request is retried
        automatically upon the `sync` event.
      </li>
    </ol>

    <button class="fetch">Make fetch request</button>
    <p>
      <script>
        document.querySelector('.fetch').addEventListener('click', () => {
          fetch('example.txt');
        });

        navigator.serviceWorker.register('./sw.js');
      </script>

      <a href="https://developers.google.com/web/tools/workbox/modules"
        >Back to Demos</a
      >
    </p>

    <p>
      <a href="https://developers.google.com/web/tools/workbox">Docs</a> |
      <a href="https://github.com/googlechrome/workbox">GitHub</a> |
      <a href="https://twitter.com/workboxjs">@workboxjs</a>
    </p>
  </body>
</html>


================================================
FILE: demos/src/workbox-background-sync-demo/package.json
================================================
{
  "name": "workbox-background-sync",
  "version": "1.0.0",
  "description": "Workbox Background Sync Demo Git Listener",
  "scripts": {
    "start": "node updateServer.js"
  },
  "dependencies": {
    "express": "^4.17.1"
  },
  "engines": {
    "node": "8.x"
  },
  "license": "MIT"
}


================================================
FILE: demos/src/workbox-background-sync-demo/public/example.txt
================================================
example text

================================================
FILE: demos/src/workbox-background-sync-demo/sw.js
================================================
importScripts(
  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',
);

// Note: Ignore the error that Glitch raises about workbox being undefined.
workbox.setConfig({
  debug: true,
});

const bgSyncPlugin = new workbox.backgroundSync.BackgroundSyncPlugin(
  'myQueueName',
);

workbox.routing.registerRoute(
  ({url}) => url.pathname === '/example.txt',
  new workbox.strategies.NetworkOnly({
    plugins: [bgSyncPlugin],
  }),
);

workbox.core.skipWaiting();
workbox.core.clientsClaim();


================================================
FILE: demos/src/workbox-background-sync-demo/updateServer.js
================================================
const express = require('express');
const app = express();
const path = require('path');

app.get('/', (request, response) => {
  response.sendFile(path.resolve('index.html'));
});

app.get('/sw.js', (request, response) => {
  response.sendFile(path.resolve('sw.js'));
});

app.use(express.static('public'));

/* /////////////////////////////////////////////////////////////////////////////
 The code below this comment is unrelated to the demo and used for maintenance
 vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
/////////////////////////////////////////////////////////////////////////////*/

const {execSync} = require('child_process');
const bodyParser = require('body-parser');

app.use(bodyParser.json());

app.post('/deploy', (request, response) => {
  if (request.query.secret !== process.env.SECRET) {
    response.status(401).send();
    return;
  }

  const repoUrl = request.query.repo;
  execSync(
    `git checkout -- ./ && git pull -X theirs ${repoUrl} ` +
      `glitch && refresh && git branch -D glitch`,
  );
  response.status(200).send();
});

const listener = app.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + listener.address().port);
});


================================================
FILE: demos/src/workbox-broadcast-update-demo/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>workbox-broadcast-update demo</title>
    <meta
      name="workbox-broadcast-update demo"
      content="An example to demonstrate the workbox-broadcast-update module"
    />
    <link
      id="favicon"
      rel="icon"
      href="https://glitch.com/edit/favicon-app.ico"
      type="image/x-icon"
    />
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style>
      body {
        margin-left: 5%;
        font-family: 'Open Sans', sans-serif;
      }
      ol {
        padding-left: 20px;
      }
      li {
        margin-bottom: 5px;
      }
      button {
        margin: 20px 0;
        font-weight: bold;
      }
    </style>
  </head>
  <body>
    <header>
      <div>
        <h1>workbox-broadcast-update Demo</h1>
      </div>
    </header>

    <ol>
      <li>Open DevTools</li>
      <li>Go to the Console</li>
      <li>
        Click any of the buttons below and view the logs:
        <ul>
          <li>
            <p>
              <button class="trigger-broadcast">Trigger a Broadcast</button>
            </p>
          </li>
        </ul>
      </li>
    </ol>

    <script>
      const triggerBroadcast = document.querySelector('.trigger-broadcast');

      window.addEventListener('load', () => {
        navigator.serviceWorker.register('./sw.js').then((reg) => {
          triggerBroadcast.addEventListener('click', () => {
            const message = {
              command: 'trigger-broadcast',
            };
            reg.active.postMessage(message);
          });

          navigator.serviceWorker.addEventListener('message', (event) => {
            console.log(`Received a message from workbox-broadcast-update.`);
            console.log(event.data);
          });
        });
      });
    </script>

    <a href="https://developers.google.com/web/tools/workbox/modules"
      >Back to Demos</a
    >

    <p>
      <a href="https://developers.google.com/web/tools/workbox">Docs</a> |
      <a href="https://github.com/googlechrome/workbox">GitHub</a> |
      <a href="https://twitter.com/workboxjs">@workboxjs</a>
    </p>
  </body>
</html>


================================================
FILE: demos/src/workbox-broadcast-update-demo/package.json
================================================
{
  "name": "workbox-broadcast-update",
  "version": "1.0.0",
  "description": "Workbox Broadcast Update Demo Git Listener",
  "scripts": {
    "start": "node updateServer.js"
  },
  "dependencies": {
    "express": "^4.17.1"
  },
  "engines": {
    "node": "8.x"
  },
  "license": "MIT"
}


================================================
FILE: demos/src/workbox-broadcast-update-demo/sw.js
================================================
importScripts(
  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',
);

workbox.setConfig({
  debug: true,
});

const broadcastUpdate = new workbox.broadcastUpdate.BroadcastCacheUpdate(
  'broadcast-update-demo',
);

const initialResponse = new Response('Response 1', {
  headers: {
    'last-modified': Date.now().toString(),
  },
});

self.addEventListener('message', (event) => {
  switch (event.data.command) {
    case 'trigger-broadcast': {
      const secondResponse = new Response('Response 2', {
        headers: {
          'last-modified': Date.now().toString(),
        },
      });

      broadcastUpdate.notifyIfUpdated({
        oldResponse: initialResponse,
        newResponse: secondResponse,
        request: new Request('exampleUrl'),
        url: 'exampleUrl',
        cacheName: 'exampleCacheName',
      });
      break;
    }

    default:
      console.log(`Unknown command received in the service worker: `, event);
  }
});

workbox.core.skipWaiting();
workbox.core.clientsClaim();


================================================
FILE: demos/src/workbox-broadcast-update-demo/updateServer.js
================================================
const express = require('express');
const app = express();
const path = require('path');

app.get('/', (request, response) => {
  response.sendFile(path.resolve('index.html'));
});

app.get('/sw.js', (request, response) => {
  response.sendFile(path.resolve('sw.js'));
});

app.use(express.static('public'));

/* /////////////////////////////////////////////////////////////////////////////
 The code below this comment is unrelated to the demo and used for maintenance
 vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
/////////////////////////////////////////////////////////////////////////////*/

const {execSync} = require('child_process');
const bodyParser = require('body-parser');

app.use(bodyParser.json());

app.post('/deploy', (request, response) => {
  if (request.query.secret !== process.env.SECRET) {
    response.status(401).send();
    return;
  }

  const repoUrl = request.query.repo;
  execSync(
    `git checkout -- ./ && git pull -X theirs ${repoUrl} ` +
      `glitch && refresh && git branch -D glitch`,
  );
  response.status(200).send();
});

const listener = app.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + listener.address().port);
});


================================================
FILE: demos/src/workbox-cacheable-response/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>workbox-cacheable-response demo</title>
    <meta
      name="workbox-cacheable-response demo"
      content="An example to demonstrate the workbox-cacheable-response module"
    />
    <link
      id="favicon"
      rel="icon"
      href="https://glitch.com/edit/favicon-app.ico"
      type="image/x-icon"
    />
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style>
      body {
        margin-left: 5%;
        font-family: 'Open Sans', sans-serif;
      }
      ol {
        padding-left: 20px;
      }
      li {
        margin-bottom: 5px;
      }
      button {
        margin: 20px 0;
        font-weight: bold;
      }
    </style>
  </head>
  <body>
    <header>
      <div>
        <h1>workbox-cacheable-response Demo</h1>
      </div>
    </header>

    <ol>
      <li>Open DevTools</li>
      <li>Go to the Console</li>
      <li>
        Click any of the buttons below and view the logs and network responses:
        <ul>
          <li>
            <p>
              <button class="with-good-header">
                With 'X-Is-Cacheable: true' Header
              </button>
            </p>
          </li>
          <li>
            <p>
              <button class="with-bad-header">
                With 'X-Is-Cacheable: false' Header
              </button>
            </p>
          </li>
          <li>
            <p>
              <button class="without-header">
                Without 'X-Is-Cacheable' Header
              </button>
            </p>
          </li>
        </ul>
      </li>
    </ol>

    <script>
      const withGoodHeaderBtn = document.querySelector('.with-good-header');
      const withBadHeaderBtn = document.querySelector('.with-bad-header');
      const withoutHeaderBtn = document.querySelector('.without-header');

      const DEMO_REQUEST_URL = '/api/is-response-cacheable';

      window.addEventListener('load', () => {
        navigator.serviceWorker.register('./sw.js').then(() => {
          withGoodHeaderBtn.addEventListener('click', () => {
            fetch(DEMO_REQUEST_URL, {
              headers: {
                'X-Is-Cacheable': true,
              },
            });
          });

          withBadHeaderBtn.addEventListener('click', () => {
            fetch(DEMO_REQUEST_URL, {
              headers: {
                'X-Is-Cacheable': false,
              },
            });
          });

          withoutHeaderBtn.addEventListener('click', () => {
            fetch(DEMO_REQUEST_URL);
          });
        });
      });
    </script>

    <a href="https://developers.google.com/web/tools/workbox/modules"
      >Back to Demos</a
    >

    <p>
      <a href="https://developers.google.com/web/tools/workbox">Docs</a> |
      <a href="https://github.com/googlechrome/workbox">GitHub</a> |
      <a href="https://twitter.com/workboxjs">@workboxjs</a>
    </p>
  </body>
</html>


================================================
FILE: demos/src/workbox-cacheable-response/package.json
================================================
{
  "name": "workbox-cacheable-response",
  "version": "1.0.0",
  "description": "Workbox Cacheable Response Demo Listener",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "express": "^4.17.1"
  },
  "engines": {
    "node": "8.x"
  },
  "license": "MIT"
}


================================================
FILE: demos/src/workbox-cacheable-response/server.js
================================================
// server.js
// where your node app starts

// init project
const express = require('express');
const app = express();

// we've started you off with Express,
// but feel free to use whatever libs or frameworks you'd like through `package.json`.

// http://expressjs.com/en/starter/basic-routing.html
app.get('/', function (request, response) {
  response.sendFile(__dirname + '/index.html');
});

app.get('/sw.js', function (request, response) {
  response.sendFile(__dirname + '/sw.js');
});

// listen for requests :)
const listener = app.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + listener.address().port);
});

app.get('/api/is-response-cacheable', function (req, res) {
  if (req.headers['x-is-cacheable']) {
    const value = req.headers['x-is-cacheable'];
    res.set('X-Is-Cacheable', value);
    res.send(`This response has 'X-Is-Cacheable' header set to '${value}'`);
  } else {
    res.send(`This response has no 'X-Is-Cacheable' header`);
  }
});

/* /////////////////////////////////////////////////////////////////////////////
 The code below this comment is unrelated to the demo and used for maintenance
 vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
/////////////////////////////////////////////////////////////////////////////*/

const {execSync} = require('child_process');
const bodyParser = require('body-parser');

app.use(bodyParser.json());

app.post('/deploy', (request, response) => {
  if (request.query.secret !== process.env.SECRET) {
    response.status(401).send();
    return;
  }

  const repoUrl = request.query.repo;
  execSync(
    `git checkout -- ./ && git pull -X theirs ${repoUrl} ` +
      `glitch && refresh && git branch -D glitch`,
  );
  response.status(200).send();
});


================================================
FILE: demos/src/workbox-cacheable-response/sw.js
================================================
importScripts(
  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',
);

workbox.setConfig({
  debug: true,
});

const cacheable = new workbox.cacheableResponse.CacheableResponse({
  statuses: [200],
  headers: {
    'X-Is-Cacheable': 'true',
  },
});

const handleCachableResponse = (event) => {
  return fetch(event.request).then((response) => {
    if (cacheable.isResponseCacheable(response)) {
      console.log('Response meets the criteria');
    } else {
      console.log('Response does NOT meet the criteria');
    }

    return response;
  });
};

self.addEventListener('fetch', (event) => {
  switch (new URL(event.request.url).pathname) {
    case '/api/is-response-cacheable':
      event.respondWith(handleCachableResponse(event));
      break;
  }
});

workbox.core.skipWaiting();
workbox.core.clientsClaim();


================================================
FILE: demos/src/workbox-core/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>workbox-core demo</title>
    <meta
      name="workbox-core demo"
      content="An example to demonstrate the workbox-core module"
    />
    <link
      id="favicon"
      rel="icon"
      href="https://glitch.com/edit/favicon-app.ico"
      type="image/x-icon"
    />
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style>
      body {
        margin-left: 5%;
        font-family: 'Open Sans', sans-serif;
      }
      ol {
        padding-left: 20px;
      }
      li {
        margin-bottom: 5px;
      }
      button {
        margin: 20px 0;
        font-weight: bold;
      }
    </style>
  </head>
  <body>
    <header>
      <div>
        <h1>workbox-core demo</h1>
      </div>
    </header>

    <ol>
      <li>Open DevTools</li>
      <li>Go to the Console</li>
      <li>
        Click this button:<br /><button class="install-sw">
          Install Service Worker
        </button>
      </li>
      <li>Checkout the logs for info on Workbox and getting started.</li>
      <li>
        Click this button to print out various types of logs:<br /><button
          class="show-logs"
        >
          Show Me Workbox Logs
        </button>
      </li>
      <li>
        Click this button to print out the Workbox Cache Names:<br /><button
          class="show-cache-names"
        >
          Show Me Workbox Cache Names
        </button>
      </li>
    </ol>

    <script>
      const installSWBtn = document.querySelector('.install-sw');
      const showLogsBtn = document.querySelector('.show-logs');
      const cacheNamesBtn = document.querySelector('.show-cache-names');

      installSWBtn.addEventListener('click', () => {
        console.log('Installing service worker');
        navigator.serviceWorker.register('/sw.js').then((reg) => {
          showLogsBtn.addEventListener('click', () => {
            const message = {
              command: 'printLogs',
            };
            reg.active.postMessage(message);
          });
          cacheNamesBtn.addEventListener('click', () => {
            const message = {
              command: 'printCacheNames',
            };
            reg.active.postMessage(message);
          });
        });
      });
    </script>

    <a href="https://developers.google.com/web/tools/workbox/modules"
      >Back to Demos</a
    >

    <p>
      <a href="https://developers.google.com/web/tools/workbox">Docs</a> |
      <a href="https://github.com/googlechrome/workbox">GitHub</a> |
      <a href="https://twitter.com/workboxjs">@workboxjs</a>
    </p>
  </body>
</html>


================================================
FILE: demos/src/workbox-core/package.json
================================================
{
  "name": "workbox-core",
  "version": "1.0.0",
  "description": "Workbox Core Demo Git Listener",
  "scripts": {
    "start": "node updateServer.js"
  },
  "dependencies": {
    "express": "^4.17.1"
  },
  "engines": {
    "node": "8.x"
  },
  "license": "MIT"
}


================================================
FILE: demos/src/workbox-core/sw.js
================================================
importScripts(
  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',
);

// Note: Ignore the error that Glitch raises about workbox being undefined.
workbox.setConfig({
  debug: true,
});

// To avoid async issues, we load core before we call it in the callback
workbox.loadModule('workbox-core');

const printLogs = () => {
  // ☠️ You should never so this - this is just so we can show off our logging.
  workbox.core._private.logger.debug(`🐛 Oh hai! I'm a debug message.`);
  workbox.core._private.logger.log(`🔧 Good ole log message.`);
  workbox.core._private.logger.warn(`⚠️ Uh Oh.... I'm a warning.`);
  workbox.core._private.logger.error(`☠️ Stuff is breaking. I'm an error.`);
};

const printCacheNames = () => {
  workbox.core._private.logger.log(`The caches used by Workbox are...`);
  const cacheNames = workbox.core.cacheNames;
  Object.keys(cacheNames).forEach((cacheId) => {
    console.log(`    ${cacheId}: ${cacheNames[cacheId]}`);
  });
};

self.addEventListener('message', (event) => {
  switch (event.data.command) {
    case 'printLogs':
      printLogs();
      break;
    case 'printCacheNames':
      printCacheNames();
      break;
    default:
      console.log(`Unknown command received in the service worker: `, event);
  }
});


================================================
FILE: demos/src/workbox-core/updateServer.js
================================================
const express = require('express');
const app = express();
const path = require('path');

app.get('/', (request, response) => {
  response.sendFile(path.resolve('index.html'));
});

app.get('/sw.js', (request, response) => {
  response.sendFile(path.resolve('sw.js'));
});

/* /////////////////////////////////////////////////////////////////////////////
 The code below this comment is unrelated to the demo and used for maintenance
 vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
///////////////////////////////////////////////////////////////////////////// */

const {execSync} = require('child_process');
const bodyParser = require('body-parser');

app.use(bodyParser.json());

app.post('/deploy', (request, response) => {
  if (request.query.secret !== process.env.SECRET) {
    response.status(401).send();
    return;
  }

  const repoUrl = request.query.repo;
  execSync(
    `git checkout -- ./ && git pull -X theirs ${repoUrl} ` +
      `glitch && refresh && git branch -D glitch`,
  );
  response.status(200).send();
});

const listener = app.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + listener.address().port);
});


================================================
FILE: demos/src/workbox-expiration/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>workbox-expiration demo</title>
    <meta
      name="workbox-expiration demo"
      content="An example to demonstrate the workbox-expiration module"
    />
    <link
      id="favicon"
      rel="icon"
      href="https://glitch.com/edit/favicon-app.ico"
      type="image/x-icon"
    />
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style>
      body {
        margin-left: 5%;
        font-family: 'Open Sans', sans-serif;
      }
      ol {
        padding-left: 20px;
      }
      li {
        margin-bottom: 5px;
      }
      button {
        margin: 20px 0;
        font-weight: bold;
      }
    </style>
  </head>
  <body>
    <header>
      <div>
        <h1>workbox-expiration Demo</h1>
      </div>
    </header>

    <ol>
      <li>Open DevTools</li>
      <li>Go to the Console</li>
      <li>
        Click the following buttons and look at the Cache and IndexedDB entries.
        <ol>
          <li>
            <button class="entry-1">Entry 1</button> (Expires in:
            <span class="entry-expire-1">Not Added Yet</span>)
          </li>
          <li>
            <button class="entry-2">Entry 2</button> (Expires in:
            <span class="entry-expire-2">Not Added Yet</span>)
          </li>
          <li>
            <button class="entry-3">Entry 3</button> (Expires in:
            <span class="entry-expire-3">Not Added Yet</span>)
          </li>
          <li>
            <button class="entry-4">Entry 4</button> (Expires in:
            <span class="entry-expire-4">Not Added Yet</span>)
          </li>
          <li>
            <button class="entry-5">Entry 5</button> (Expires in:
            <span class="entry-expire-5">Not Added Yet</span>)
          </li>
        </ol>
      </li>
      <li>
        To remove any expired entries click here:
        <p><button class="expire">Expire Entries</button></p>
      </li>
    </ol>

    <script>
      const expireBtn = document.querySelector('.expire');

      const TIMEOUT_IN_SECS = 30;
      const MAX_ENTRIES = 3;

      var entryQueue = [];

      const setupTimeout = (btnElement, textElement) => {
        textElement.textContent = `${btnElement.__workbox_timeoutCount}s`;
        btnElement.__workbox_timeoutId = setTimeout(() => {
          // TODO: FIX THIS TO TAKE FIRST ELEMENT OF CLASS LIST AND CHECK AGAIN ENTRY STACK
          if (entryQueue.includes(btnElement.classList[0])) {
            btnElement.__workbox_timeoutCount -= 1;
            if (btnElement.__workbox_timeoutCount > 0) {
              setupTimeout(btnElement, textElement);
            } else {
              textElement.textContent = `Expired (Too Old)`;
            }
          } else {
            textElement.textContent = `Expired (Too Many)`;
          }
        }, 1000);
      };

      window.addEventListener('load', () => {
        navigator.serviceWorker.register('./sw.js').then((reg) => {
          for (let i = 0; i < 5; i++) {
            const entryBtn = document.querySelector(`.entry-${i + 1}`);
            const expireText = document.querySelector(`.entry-expire-${i + 1}`);
            entryBtn.addEventListener('click', () => {
              const message = {
                command: 'update-entry',
                id: i + 1,
              };

              var arrayEntry = `entry-${i + 1}`;

              //If we refresh an entry that has already been added and is not expired
              //we reorder it to the front of the queue
              if (entryQueue.includes(arrayEntry)) {
                entryQueue.splice(entryQueue.indexOf(arrayEntry), 1);
              }
              entryQueue.push(`entry-${i + 1}`);
              if (entryQueue.length >= 4) {
                entryQueue = entryQueue.slice(MAX_ENTRIES * -1);
              }

              reg.active.postMessage(message);

              if (entryBtn.__workbox_timeoutId) {
                clearTimeout(entryBtn.__workbox_timeoutId);
              }

              entryBtn.__workbox_timeoutCount = TIMEOUT_IN_SECS;
              setupTimeout(entryBtn, expireText);
            });
          }

          expireBtn.addEventListener('click', () => {
            const message = {
              command: 'expire-entries',
            };
            reg.active.postMessage(message);
          });
        });
      });
    </script>

    <a href="https://developers.google.com/web/tools/workbox/modules"
      >Back to Demos</a
    >

    <p>
      <a href="https://developers.google.com/web/tools/workbox">Docs</a> |
      <a href="https://github.com/googlechrome/workbox">GitHub</a> |
      <a href="https://twitter.com/workboxjs">@workboxjs</a>
    </p>
  </body>
</html>


================================================
FILE: demos/src/workbox-expiration/package.json
================================================
{
  "name": "workbox-expiration",
  "version": "1.0.0",
  "description": "Workbox Expiration Demo Git Listener",
  "scripts": {
    "start": "node updateServer.js"
  },
  "dependencies": {
    "express": "^4.17.1"
  },
  "engines": {
    "node": "8.x"
  },
  "license": "MIT"
}


================================================
FILE: demos/src/workbox-expiration/sw.js
================================================
importScripts(
  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',
);

// Note: Ignore the error that Glitch raises about workbox being undefined.
workbox.setConfig({
  debug: true,
});

const expirationManager = new workbox.expiration.CacheExpiration(
  'demo-cache-for-expiration',
  {
    maxEntries: 3,
    maxAgeSeconds: 30,
  },
);

const updateEntry = async (entryID) => {
  const openCache = await caches.open('demo-cache-for-expiration');

  openCache.put(
    `example-entry-${entryID}`,
    new Response(`Hello from entry number ${entryID}`),
  );

  expirationManager.updateTimestamp(`example-entry-${entryID}`);
};

self.addEventListener('message', (event) => {
  switch (event.data.command) {
    case 'update-entry':
      updateEntry(event.data.id);
      break;
    case 'expire-entries':
      expirationManager.expireEntries();
      break;
    default:
      console.log(`Unknown command received in the service worker: `, event);
  }
});


================================================
FILE: demos/src/workbox-expiration/updateServer.js
================================================
const express = require('express');
const app = express();
const path = require('path');

app.get('/', (request, response) => {
  response.sendFile(path.resolve('index.html'));
});

app.get('/sw.js', (request, response) => {
  response.sendFile(path.resolve('sw.js'));
});

app.use(express.static('public'));

/* /////////////////////////////////////////////////////////////////////////////
 The code below this comment is unrelated to the demo and used for maintenance
 vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
/////////////////////////////////////////////////////////////////////////////*/

const {execSync} = require('child_process');
const bodyParser = require('body-parser');

app.use(bodyParser.json());

app.post('/deploy', (request, response) => {
  if (request.query.secret !== process.env.SECRET) {
    response.status(401).send();
    return;
  }

  const repoUrl = request.query.repo;
  execSync(
    `git checkout -- ./ && git pull -X theirs ${repoUrl} ` +
      `glitch && refresh && git branch -D glitch`,
  );
  response.status(200).send();
});

const listener = app.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + listener.address().port);
});


================================================
FILE: demos/src/workbox-google-analytics/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>workbox-google-analytics demo</title>
    <meta
      name="workbox-googleAnalytics demo"
      content="An example to demonstrate the workbox-google-analytics module"
    />
    <link
      id="favicon"
      rel="icon"
      href="https://glitch.com/edit/favicon-app.ico"
      type="image/x-icon"
    />
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style>
      body {
        margin-left: 5%;
        font-family: 'Open Sans', sans-serif;
      }
      ol {
        padding-left: 20px;
      }
      li {
        margin-bottom: 5px;
      }
      button {
        margin: 20px 0;
        font-weight: bold;
      }
    </style>
  </head>
  <body>
    <header>
      <div>
        <h1>workbox-google-analytics Demo</h1>
      </div>
    </header>

    <ol>
      <li>Open DevTools</li>
      <li>Go to the Console</li>
      <li>
        Click this button:
        <p><button class="make-analytics-call">Make Analytics Call</button></p>
      </li>
      <li>
        Turn off your machine's connection and press the button again. Of
        course, the requests fail
      </li>
      <li>
        Upon reconnecting to the network, workbox-googleAnalytics will empty the
        request queue
      </li>
    </ol>

    <!-- Global site tag (gtag.js) - Google Analytics -->
    <script
      async
      src="https://www.googletagmanager.com/gtag/js?id=UA-77119321-5"
    ></script>
    <script>
      (function (i, s, o, g, r, a, m) {
        i['GoogleAnalyticsObject'] = r;
        (i[r] =
          i[r] ||
          function () {
            (i[r].q = i[r].q || []).push(arguments);
          }),
          (i[r].l = 1 * new Date());
        (a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]);
        a.async = 1;
        a.src = g;
        m.parentNode.insertBefore(a, m);
      })(
        window,
        document,
        'script',
        'https://www.google-analytics.com/analytics.js',
        'ga',
      );

      ga('create', 'UA-77119321-5', 'auto');
    </script>

    <script>
      const analyticsCallBtn = document.querySelector('.make-analytics-call');

      navigator.serviceWorker.register('./sw.js').then((reg) => {
        analyticsCallBtn.addEventListener('click', () => {
          ga('send', 'pageview');
        });
      });
    </script>

    <a href="https://developers.google.com/web/tools/workbox/modules"
      >Back to Demos</a
    >

    <p>
      <a href="https://developers.google.com/web/tools/workbox">Docs</a> |
      <a href="https://github.com/googlechrome/workbox">GitHub</a> |
      <a href="https://twitter.com/workboxjs">@workboxjs</a>
    </p>
  </body>
</html>


================================================
FILE: demos/src/workbox-google-analytics/package.json
================================================
{
  "name": "workbox-google-analytics",
  "version": "1.0.0",
  "description": "Workbox Google Analytics Demo Git Listener",
  "scripts": {
    "start": "node updateServer.js"
  },
  "dependencies": {
    "express": "^4.17.1"
  },
  "engines": {
    "node": "8.x"
  },
  "license": "MIT"
}


================================================
FILE: demos/src/workbox-google-analytics/sw.js
================================================
importScripts(
  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',
);

workbox.setConfig({
  debug: true,
});

workbox.googleAnalytics.initialize();

workbox.core.skipWaiting();
workbox.core.clientsClaim();


================================================
FILE: demos/src/workbox-google-analytics/updateServer.js
================================================
const express = require('express');
const app = express();
const path = require('path');

app.get('/', (request, response) => {
  response.sendFile(path.resolve('index.html'));
});

app.get('/sw.js', (request, response) => {
  response.sendFile(path.resolve('sw.js'));
});

app.use(express.static('public'));

/* /////////////////////////////////////////////////////////////////////////////
 The code below this comment is unrelated to the demo and used for maintenance
 vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
/////////////////////////////////////////////////////////////////////////////*/

const {execSync} = require('child_process');
const bodyParser = require('body-parser');

app.use(bodyParser.json());

app.post('/deploy', (request, response) => {
  if (request.query.secret !== process.env.SECRET) {
    response.status(401).send();
    return;
  }

  const repoUrl = request.query.repo;
  execSync(
    `git checkout -- ./ && git pull -X theirs ${repoUrl} ` +
      `glitch && refresh && git branch -D glitch`,
  );
  response.status(200).send();
});

const listener = app.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + listener.address().port);
});


================================================
FILE: demos/src/workbox-navigation-preload/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>workbox-navigation-preload demo</title>
    <meta
      name="workbox-navigation-preload demo"
      content="An example to demonstrate the workbox-navigation-preload module"
    />
    <link
      id="favicon"
      rel="icon"
      href="https://glitch.com/edit/favicon-app.ico"
      type="image/x-icon"
    />
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style>
      body {
        margin-left: 5%;
        font-family: 'Open Sans', sans-serif;
      }
      ol {
        padding-left: 20px;
      }
      li {
        margin-bottom: 5px;
      }
      button {
        margin: 20px 0;
        font-weight: bold;
      }
    </style>
  </head>
  <body>
    <header>
      <div>
        <h1>workbox-navigation-preload Demo</h1>
      </div>
    </header>

    <ol>
      <li>
        workbox-navigation-preload enables navigation preload in browsers that
        support it
      </li>
      <li>Open the dev tools console and reload this page</li>
      <li>
        There should be two requests for the HTML document: one initiated by the
        service worker, and one by Preload
      </li>
    </ol>

    <script>
      window.addEventListener('load', () => {
        navigator.serviceWorker.register('./sw.js');
      });
    </script>

    <a href="https://developers.google.com/web/tools/workbox/modules"
      >Back to Demos</a
    >

    <p>
      <a href="https://developers.google.com/web/tools/workbox">Docs</a> |
      <a href="https://github.com/googlechrome/workbox">GitHub</a> |
      <a href="https://twitter.com/workboxjs">@workboxjs</a>
    </p>
  </body>
</html>


================================================
FILE: demos/src/workbox-navigation-preload/package.json
================================================
{
  "name": "workbox-navigation-preload",
  "version": "1.0.0",
  "description": "Workbox Navigation Preload Demo Git Listener",
  "scripts": {
    "start": "node updateServer.js"
  },
  "dependencies": {
    "express": "^4.17.1"
  },
  "engines": {
    "node": "8.x"
  },
  "license": "MIT"
}


================================================
FILE: demos/src/workbox-navigation-preload/sw.js
================================================
importScripts(
  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',
);

workbox.setConfig({
  debug: true,
});

// Enable navigation preload.
workbox.navigationPreload.enable();

// Swap in NetworkOnly, CacheFirst, or StaleWhileRevalidate as needed.
const strategy = new workbox.strategies.NetworkFirst({
  cacheName: 'cached-navigations',
  plugins: [
    // Any plugins, like workbox.expiration, etc.
  ],
});

const navigationRoute = new workbox.routing.NavigationRoute(strategy, {
  // Optionally, provide a allowlist/denylist of RegExps to determine
  // which paths will match this route.
  // allowlist: [],
  // denylist: [],
});

workbox.routing.registerRoute(navigationRoute);

workbox.core.skipWaiting();
workbox.core.clientsClaim();


================================================
FILE: demos/src/workbox-navigation-preload/updateServer.js
================================================
const express = require('express');
const app = express();
const path = require('path');

app.get('/', (request, response) => {
  response.sendFile(path.resolve('index.html'));
});

app.get('/sw.js', (request, response) => {
  response.sendFile(path.resolve('sw.js'));
});

app.use(express.static('public'));

/* /////////////////////////////////////////////////////////////////////////////
 The code below this comment is unrelated to the demo and used for maintenance
 vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
/////////////////////////////////////////////////////////////////////////////*/

const {execSync} = require('child_process');
const bodyParser = require('body-parser');

app.use(bodyParser.json());

app.post('/deploy', (request, response) => {
  if (request.query.secret !== process.env.SECRET) {
    response.status(401).send();
    return;
  }

  const repoUrl = request.query.repo;
  execSync(
    `git checkout -- ./ && git pull -X theirs ${repoUrl} ` +
      `glitch && refresh && git branch -D glitch`,
  );
  response.status(200).send();
});

const listener = app.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + listener.address().port);
});


================================================
FILE: demos/src/workbox-precaching/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>workbox-precaching demo</title>
    <meta
      name="workbox-precaching demo"
      content="An example to demonstrate the workbox-precaching module"
    />
    <link
      id="favicon"
      rel="icon"
      href="https://glitch.com/edit/favicon-app.ico"
      type="image/x-icon"
    />
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style>
      body {
        margin-left: 5%;
        font-family: 'Open Sans', sans-serif;
      }
      ol {
        padding-left: 20px;
      }
      li {
        margin-bottom: 5px;
      }
      button {
        margin: 20px 0;
        font-weight: bold;
      }
    </style>
  </head>
  <body>
    <header>
      <div>
        <h1>workbox-precaching Demo</h1>
      </div>
    </header>

    <ol>
      <li>Open DevTools</li>
      <li>Go to the Console</li>
      <li>
        Click this button:<br /><button class="install-sw-1">
          Install Service Worker
        </button>
      </li>
      <li>Checkout the logs for info on what was precached.</li>
      <li>
        Explore Cache in the "Application" tab in DevTools.
        <i>Note: You may need to right-click and refresh.</i>
      </li>
      <li>
        Click this button:<br /><button class="install-sw-2">
          Install New Service Worker
        </button>
      </li>
      <li>
        Check logs, cache to highlight the new, updated and deleted entry.
      </li>
    </ol>

    <script>
      const firstBtn = document.querySelector('.install-sw-1');
      const secondBtn = document.querySelector('.install-sw-2');

      firstBtn.addEventListener('click', () => {
        navigator.serviceWorker.register('./sw-1.js');
      });
      secondBtn.addEventListener('click', () => {
        navigator.serviceWorker
          .getRegistration()
          .then((reg) => {
            return reg.unregister();
          })
          .then(() => {
            navigator.serviceWorker.register('./sw-2.js');
          });
      });
    </script>

    <a href="https://developers.google.com/web/tools/workbox/modules"
      >Back to Demos</a
    >

    <p>
      <a href="https://developers.google.com/web/tools/workbox">Docs</a> |
      <a href="https://github.com/googlechrome/workbox">GitHub</a> |
      <a href="https://twitter.com/workboxjs">@workboxjs</a>
    </p>
  </body>
</html>


================================================
FILE: demos/src/workbox-precaching/package.json
================================================
{
  "name": "workbox-precaching",
  "version": "1.0.0",
  "description": "Workbox Precaching Demo Git Listener",
  "scripts": {
    "start": "node updateServer.js"
  },
  "dependencies": {
    "express": "^4.17.1"
  },
  "engines": {
    "node": "8.x"
  },
  "license": "MIT"
}


================================================
FILE: demos/src/workbox-precaching/public/hello-world.1234.txt
================================================
Hello, World!

I'm the first version of this file.

================================================
FILE: demos/src/workbox-precaching/public/hello-world.5678.txt
================================================
Hello, World!

I'm the second version of this file.

================================================
FILE: demos/src/workbox-precaching/public/test-file.txt
================================================
#Danger

This file is not revisioned.

================================================
FILE: demos/src/workbox-precaching/sw-1.js
================================================
importScripts(
  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',
);

workbox.setConfig({
  debug: true,
});

workbox.precaching.precacheAndRoute([
  {url: '/', revision: '1'},
  {url: 'test-file.txt', revision: '1'},
  'hello-world.1234.txt',
]);


================================================
FILE: demos/src/workbox-precaching/sw-2.js
================================================
importScripts(
  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',
);

workbox.setConfig({
  debug: true,
});

workbox.precaching.precacheAndRoute([
  {url: '/', revision: '2'},
  {url: 'test-file.txt', revision: '2'},
  'hello-world.5678.txt',
]);


================================================
FILE: demos/src/workbox-precaching/updateServer.js
================================================
const express = require('express');
const app = express();
const path = require('path');

app.get('/', (request, response) => {
  response.sendFile(path.resolve('index.html'));
});

app.get('/sw-1.js', (request, response) => {
  response.sendFile(path.resolve('sw-1.js'));
});

app.get('/sw-2.js', (request, response) => {
  response.sendFile(path.resolve('sw-2.js'));
});

app.use(express.static('public'));

/* /////////////////////////////////////////////////////////////////////////////
 The code below this comment is unrelated to the demo and used for maintenance
 vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
/////////////////////////////////////////////////////////////////////////////*/

const {execSync} = require('child_process');
const bodyParser = require('body-parser');

app.use(bodyParser.json());

app.post('/deploy', (request, response) => {
  if (request.query.secret !== process.env.SECRET) {
    response.status(401).send();
    return;
  }

  const repoUrl = request.query.repo;
  execSync(
    `git checkout -- ./ && git pull -X theirs ${repoUrl} ` +
      `glitch && refresh && git branch -D glitch`,
  );
  response.status(200).send();
});

const listener = app.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + listener.address().port);
});


================================================
FILE: demos/src/workbox-range-requests/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>workbox-range-requests demo</title>
    <meta
      name="workbox-range-requests demo"
      content="An example to demonstrate the workbox-range-requests module"
    />
    <link
      id="favicon"
      rel="icon"
      href="https://glitch.com/edit/favicon-app.ico"
      type="image/x-icon"
    />
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style>
      body {
        margin-left: 5%;
        font-family: 'Open Sans', sans-serif;
      }
      ol {
        padding-left: 20px;
      }
      li {
        margin-bottom: 5px;
      }
      button {
        margin: 20px 0;
        font-weight: bold;
      }
    </style>
  </head>
  <body>
    <header>
      <div>
        <h1>workbox-range-requests Demo</h1>
      </div>
    </header>

    <ol>
      <li>Open DevTools</li>
      <li>Go to the Console</li>
      <li>
        Click this button to request range 1 - 4 of 'hello, world.':<br /><button
          class="make-range-request"
        >
          Make Range Request
        </button>
      </li>
      <li>Checkout the logs for info on the range request that was handled.</li>
    </ol>

    <script>
      const makeRequestBtn = document.querySelector('.make-range-request');

      caches
        .open('range-requests-demo')
        .then((cache) =>
          cache.put('/range-request-example', new Response('hello, world.')),
        );

      navigator.serviceWorker.register('./sw.js').then(() => {
        makeRequestBtn.addEventListener('click', () => {
          fetch(
            new Request('/range-request-example', {
              headers: {
                Range: `bytes=1-4`,
              },
            }),
          )
            .then((response) => response.text())
            .then((responseText) => {
              console.log(`Received response: '${responseText}'`);
            });
        });
      });
    </script>

    <a href="https://developers.google.com/web/tools/workbox/modules"
      >Back to Demos</a
    >

    <p>
      <a href="https://developers.google.com/web/tools/workbox">Docs</a> |
      <a href="https://github.com/googlechrome/workbox">GitHub</a> |
      <a href="https://twitter.com/workboxjs">@workboxjs</a>
    </p>
  </body>
</html>


================================================
FILE: demos/src/workbox-range-requests/package.json
================================================
{
  "name": "workbox-range-requests",
  "version": "1.0.0",
  "description": "Workbox Range Requests Demo Git Listener",
  "scripts": {
    "start": "node updateServer.js"
  },
  "dependencies": {
    "express": "^4.17.1"
  },
  "engines": {
    "node": "8.x"
  },
  "license": "MIT"
}


================================================
FILE: demos/src/workbox-range-requests/sw.js
================================================
importScripts(
  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',
);

workbox.setConfig({
  debug: true,
});

workbox.routing.registerRoute(
  new RegExp('/range-request-example'),
  new workbox.strategies.CacheOnly({
    cacheName: 'range-requests-demo',
    plugins: [new workbox.rangeRequests.RangeRequestsPlugin()],
  }),
);

workbox.core.skipWaiting();
workbox.core.clientsClaim();


================================================
FILE: demos/src/workbox-range-requests/updateServer.js
================================================
const express = require('express');
const app = express();
const path = require('path');

app.get('/', (request, response) => {
  response.sendFile(path.resolve('index.html'));
});

app.get('/sw.js', (request, response) => {
  response.sendFile(path.resolve('sw.js'));
});

app.use(express.static('public'));

/* /////////////////////////////////////////////////////////////////////////////
 The code below this comment is unrelated to the demo and used for maintenance
 vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
/////////////////////////////////////////////////////////////////////////////*/

const {execSync} = require('child_process');
const bodyParser = require('body-parser');

app.use(bodyParser.json());

app.post('/deploy', (request, response) => {
  if (request.query.secret !== process.env.SECRET) {
    response.status(401).send();
    return;
  }

  const repoUrl = request.query.repo;
  execSync(
    `git checkout -- ./ && git pull -X theirs ${repoUrl} ` +
      `glitch && refresh && git branch -D glitch`,
  );
  response.status(200).send();
});

const listener = app.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + listener.address().port);
});


================================================
FILE: demos/src/workbox-routing/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>workbox-precaching demo</title>
    <meta
      name="workbox-precaching demo"
      content="An example to demonstrate the workbox-precaching module"
    />
    <link
      id="favicon"
      rel="icon"
      href="https://glitch.com/edit/favicon-app.ico"
      type="image/x-icon"
    />
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style>
      body {
        margin-left: 5%;
        font-family: 'Open Sans', sans-serif;
      }
      ol {
        padding-left: 20px;
      }
      li {
        margin-bottom: 5px;
      }
      button {
        margin: 20px 0;
        font-weight: bold;
      }
    </style>
  </head>
  <body>
    <header>
      <div>
        <h1>workbox-routing Demo</h1>
      </div>
    </header>

    <ol>
      <li>Open DevTools</li>
      <li>Go to the Console</li>
      <li>
        Click this button:<br /><button class="install-sw">
          Install Service Worker
        </button>
      </li>
      <li><strong>Refresh the page</strong></li>
      <li>
        Notice that the image '/public/demo-img.png' was routed and is now a
        party popper
      </li>
    </ol>

    <img src="demo-img.png" style="width: 300px; height: 300px" />

    <p>
      <script>
        const firstBtn = document.querySelector('.install-sw');

        firstBtn.addEventListener('click', () => {
          navigator.serviceWorker.register('./sw.js');
        });
      </script>

      <a href="https://developers.google.com/web/tools/workbox/modules"
        >Back to Demos</a
      >
    </p>

    <p>
      <a href="https://developers.google.com/web/tools/workbox">Docs</a> |
      <a href="https://github.com/googlechrome/workbox">GitHub</a> |
      <a href="https://twitter.com/workboxjs">@workboxjs</a>
    </p>
  </body>
</html>


================================================
FILE: demos/src/workbox-routing/package.json
================================================
{
  "name": "workbox-routing",
  "version": "1.0.0",
  "description": "Workbox Routing Demo Git Listener",
  "scripts": {
    "start": "node updateServer.js"
  },
  "dependencies": {
    "express": "^4.17.1"
  },
  "engines": {
    "node": "8.x"
  },
  "license": "MIT"
}


================================================
FILE: demos/src/workbox-routing/sw.js
================================================
importScripts(
  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',
);

workbox.setConfig({
  debug: true,
});

// Set logs level to `debug` to view all logs
// workbox.core.setLogLevel(workbox.core.LOG_LEVELS.debug);

// Set up a route to alter the demo-img
const matchCb = ({url, event}) => {
  return url.pathname === '/demo-img.png';
};

const handlerCb = ({url, event, params}) => {
  return fetch('/demo-popper.png');
};

// First parameter can be a string, RegExp, workbox Route, or a match callback (used here)
// Second parameter handles the response and must return a Response promise
workbox.routing.registerRoute(matchCb, handlerCb);

const GLITCH_ICO_URL = 'https://glitch.com/edit/favicon-app.ico';
workbox.routing.registerRoute(GLITCH_ICO_URL, () => {
  // Demonstrating when an error is thrown by a Route.
  throw new Error(`Example error thrown from the default handler`);
});

workbox.routing.setCatchHandler(({event}) => {
  return fetch(event.request);
});


================================================
FILE: demos/src/workbox-routing/updateServer.js
================================================
const express = require('express');
const app = express();
const path = require('path');

app.get('/', (request, response) => {
  response.sendFile(path.resolve('index.html'));
});

app.get('/sw.js', (request, response) => {
  response.sendFile(path.resolve('sw.js'));
});

app.use(express.static('public'));

/* /////////////////////////////////////////////////////////////////////////////
 The code below this comment is unrelated to the demo and used for maintenance
 vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
///////////////////////////////////////////////////////////////////////////// */

const {execSync} = require('child_process');
const bodyParser = require('body-parser');

app.use(bodyParser.json());

app.post('/deploy', (request, response) => {
  if (request.query.secret !== process.env.SECRET) {
    response.status(401).send();
    return;
  }

  const repoUrl = request.query.repo;
  execSync(
    `git checkout -- ./ && git pull -X theirs ${repoUrl} ` +
      `glitch && refresh && git branch -D glitch`,
  );
  response.status(200).send();
});

const listener = app.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + listener.address().port);
});


================================================
FILE: demos/src/workbox-strategies/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>workbox-strategies demo</title>
    <meta
      name="workbox-strategies demo"
      content="An example to demonstrate the workbox-strategies module"
    />
    <link
      id="favicon"
      rel="icon"
      href="https://glitch.com/edit/favicon-app.ico"
      type="image/x-icon"
    />
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style>
      body {
        margin-left: 5%;
        font-family: 'Open Sans', sans-serif;
      }
      ol {
        padding-left: 20px;
      }
      li {
        margin-bottom: 5px;
      }
      button {
        margin: 20px 0;
        font-weight: bold;
      }
    </style>
  </head>
  <body>
    <header>
      <div>
        <h1>workbox-strategies Demo</h1>
      </div>
    </header>

    <ol>
      <li>Open DevTools</li>
      <li>Go to the Console</li>
      <li>
        Click any of the buttons below and view the logs:
        <ul>
          <li>
            <p>This will attempt to get a request from an empty cache.</p>
            <p>
              <button class="cache-only-empty-cache">
                Cache Only Request (To Empty Cache)
              </button>
            </p>
          </li>
          <li>
            <p>
              <button class="cache-only-populated-cache">
                Cache Only Request (To Populated Cache)
              </button>
            </p>
          </li>
          <li>
            <p>
              <button class="cache-first">
                Cache First Request (Try it Several Times)
              </button>
            </p>
          </li>
          <li>
            <p><button class="network-only">Network Only Request</button></p>
          </li>
          <li>
            <p>
              <button class="network-first-valid">
                Network First Request (Valid URL)
              </button>
            </p>
          </li>
          <li>
            <p>
              <button class="network-first-failing">
                Network First Request (Failing URL)
              </button>
            </p>
          </li>
          <li>
            <p>
              <button class="stale-while-revalidate">
                Stale While Revalidate Request
              </button>
            </p>
          </li>
        </ul>
      </li>
    </ol>

    <script>
      const cacheOnlyEmpty = document.querySelector('.cache-only-empty-cache');
      const cacheOnlyPopulated = document.querySelector(
        '.cache-only-populated-cache',
      );
      const cacheFirst = document.querySelector('.cache-first');
      const networkOnly = document.querySelector('.network-only');
      const networkFirstValid = document.querySelector('.network-first-valid');
      const networkFirstFailing = document.querySelector(
        '.network-first-failing',
      );
      const staleWhileRevalidate = document.querySelector(
        '.stale-while-revalidate',
      );

      window.addEventListener('load', () => {
        navigator.serviceWorker.register('./sw.js').then(() => {
          cacheOnlyEmpty.addEventListener('click', () => {
            fetch('cache-only-empty-cache.txt').catch(() => {});
          });

          cacheOnlyPopulated.addEventListener('click', () => {
            fetch('cache-only-populated-cache').then((response) => {
              return response.text();
            });
          });

          cacheFirst.addEventListener('click', () => {
            fetch('cache-first.txt').then((response) => {
              return response.text();
            });
          });

          networkOnly.addEventListener('click', () => {
            fetch('network-only.txt').then((response) => {
              return response.text();
            });
          });

          networkFirstValid.addEventListener('click', () => {
            fetch('network-first.txt').then((response) => {
              return response.text();
            });
          });

          networkFirstFailing.addEventListener('click', () => {
            fetch('network-first-404.txt').catch(() => {});
          });

          staleWhileRevalidate.addEventListener('click', () => {
            fetch('stale-while-revalidate.txt').then((response) => {
              return response.text();
            });
          });
        });
      });
    </script>

    <a href="https://developers.google.com/web/tools/workbox/modules"
      >Back to Demos</a
    >

    <p>
      <a href="https://developers.google.com/web/tools/workbox">Docs</a> |
      <a href="https://github.com/googlechrome/workbox">GitHub</a> |
      <a href="https://twitter.com/workboxjs">@workboxjs</a>
    </p>
  </body>
</html>


================================================
FILE: demos/src/workbox-strategies/public/cache-first.txt
================================================
Hello from CacheFirst

================================================
FILE: demos/src/workbox-strategies/public/network-first.txt
================================================
Hello from NetworkFirst

================================================
FILE: demos/src/workbox-strategies/public/network-only.txt
================================================
Hello from NetworkOnly

================================================
FILE: demos/src/workbox-strategies/public/stale-while-revalidate.txt
================================================
Hello from StaleWhileRevalidate

================================================
FILE: demos/src/workbox-strategies/sw.js
================================================
importScripts(
  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',
);
// To avoid async issues, we load strategies before we call it in the event listener
workbox.loadModule('workbox-strategies');
// Note: Ignore the error that Glitch raises about workbox being undefined.
workbox.setConfig({
  debug: true,
});

self.addEventListener('fetch', (event) => {
  const request = event.request;
  switch (new URL(event.request.url).pathname) {
    case '/cache-only-empty-cache.txt': {
      const cacheOnlyEmpty = new workbox.strategies.CacheOnly();
      event.respondWith(cacheOnlyEmpty.handle({event, request}));
      break;
    }
    case '/cache-only-populated-cache': {
      const cacheOnlyPopulated = new workbox.strategies.CacheOnly();
      event.respondWith(cacheOnlyPopulated.handle({event, request}));
      break;
    }
    case '/cache-first.txt': {
      const cacheFirst = new workbox.strategies.CacheFirst();
      event.respondWith(cacheFirst.handle({event, request}));
      break;
    }
    case '/network-only.txt': {
      const networkOnly = new workbox.strategies.NetworkOnly();
      event.respondWith(networkOnly.handle({event, request}));
      break;
    }
    case '/network-first.txt': {
      const networkFirst = new workbox.strategies.NetworkFirst();
      event.respondWith(networkFirst.handle({event, request}));
      break;
    }
    case '/network-first-404.txt': {
      const networkFirstInvalid = new workbox.strategies.NetworkFirst();
      event.respondWith(networkFirstInvalid.handle({event, request}));
      break;
    }
    case '/stale-while-revalidate.txt': {
      const staleWhileRevalidate =
        new workbox.strategies.StaleWhileRevalidate();
      event.respondWith(staleWhileRevalidate.handle({event, request}));
      break;
    }
  }
});

// This immediately deploys the service worker w/o requiring a refresh
workbox.core.skipWaiting();
workbox.core.clientsClaim();

// Populate the cache to illustrate cache-only-populated-cache route
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(workbox.core.cacheNames.runtime).then((cache) => {
      return cache.put(
        new Request('/cache-only-populated-cache'),
        new Response('Hello from the populated cache.'),
      );
    }),
  );
});


================================================
FILE: demos/src/workbox-strategies/updateServer.js
================================================
const express = require('express');
const app = express();
const path = require('path');

app.get('/', (request, response) => {
  response.sendFile(path.resolve('index.html'));
});

app.get('/sw1.js', (request, response) => {
  response.sendFile(path.resolve('sw1.js'));
});

app.use(express.static('public'));

/* /////////////////////////////////////////////////////////////////////////////
 The code below this comment is unrelated to the demo and used for maintenance
 vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
/////////////////////////////////////////////////////////////////////////////*/

const {execSync} = require('child_process');
const bodyParser = require('body-parser');

app.use(bodyParser.json());

app.post('/deploy', (request, response) => {
  if (request.query.secret !== process.env.SECRET) {
    response.status(401).send();
    return;
  }

  const repoUrl = request.query.repo;
  execSync(
    `git checkout -- ./ && git pull -X theirs ${repoUrl} ` +
      `glitch && refresh && git branch -D glitch`,
  );
  response.status(200).send();
});

const listener = app.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + listener.address().port);
});


================================================
FILE: demos/src/workbox-streams/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>workbox-streams demo</title>
    <meta
      name="workbox-streams demo"
      content="An example to demonstrate the workbox-streams module"
    />
    <link
      id="favicon"
      rel="icon"
      href="https://glitch.com/edit/favicon-app.ico"
      type="image/x-icon"
    />
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style>
      body {
        margin-left: 5%;
        font-family: 'Open Sans', sans-serif;
      }
      ol {
        padding-left: 20px;
      }
      li {
        margin-bottom: 5px;
      }
      button {
        margin: 20px 0;
        font-weight: bold;
      }
    </style>
  </head>
  <body>
    <header>
      <div>
        <h1>workbox-workbox-streams Demo</h1>
      </div>
    </header>

    <ol>
      <li>Open DevTools</li>
      <li>Go to the Console</li>
      <li>
        Click this button to add an <code>iframe</code> to this page, whose body
        is created from multiple streamed sources:<br />
        <button class="make-streams-request">Add iframe</button>
      </li>
      <li>
        Checkout the logs for info on how the streamed response was generated.
      </li>
    </ol>

    <div id="iframes"></div>

    <script>
      const makeRequestBtn = document.querySelector('.make-streams-request');

      navigator.serviceWorker.register('./sw.js').then(() => {
        makeRequestBtn.addEventListener('click', () => {
          const iframe = document.createElement('iframe');
          // This URL will be handled by the service worker.
          iframe.src = 'iframe';
          document.querySelector('#iframes').appendChild(iframe);
        });
      });
    </script>

    <a href="https://developers.google.com/web/tools/workbox/modules"
      >Back to Demos</a
    >

    <p>
      <a href="https://developers.google.com/web/tools/workbox">Docs</a> |
      <a href="https://github.com/googlechrome/workbox">GitHub</a> |
      <a href="https://twitter.com/workboxjs">@workboxjs</a>
    </p>
  </body>
</html>


================================================
FILE: demos/src/workbox-streams/package.json
================================================
{
  "name": "workbox-streams",
  "version": "1.0.0",
  "description": "Workbox Streams Demo Git Listener",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "express": "^4.17.1"
  },
  "engines": {
    "node": "8.x"
  },
  "license": "MIT"
}


================================================
FILE: demos/src/workbox-streams/server.js
================================================
// server.js
// where your node app starts

// init project
const express = require('express');
const app = express();

// we've started you off with Express,
// but feel free to use whatever libs or frameworks you'd like through `package.json`.

// http://expressjs.com/en/starter/basic-routing.html
app.get('/', function (request, response) {
  response.sendFile(__dirname + '/index.html');
});

app.get('/sw.js', function (request, response) {
  response.sendFile(__dirname + '/sw.js');
});

// listen for requests :)
const listener = app.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + listener.address().port);
});

app.get('/api/date', function (req, res) {
  res.header('Content-Type', 'text/plain');
  res.header('Cache-Control', 'no-cache');
  res.send(`Received from the server at ${new Date().toLocaleString()}`);
});

/* /////////////////////////////////////////////////////////////////////////////
 The code below this comment is unrelated to the demo and used for maintenance
 vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
/////////////////////////////////////////////////////////////////////////////*/

const {execSync} = require('child_process');
const bodyParser = require('body-parser');

app.use(bodyParser.json());

app.post('/deploy', (request, response) => {
  if (request.query.secret !== process.env.SECRET) {
    response.status(401).send();
    return;
  }

  const repoUrl = request.query.repo;
  execSync(
    `git checkout -- ./ && git pull -X theirs ${repoUrl} ` +
      `glitch && refresh && git branch -D glitch`,
  );
  response.status(200).send();
});


================================================
FILE: demos/src/workbox-streams/sw.js
================================================
importScripts(
  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',
);

workbox.setConfig({
  debug: true,
});

const CACHE_NAME = 'my-cache';
const START_CACHE_KEY = 'start';
const END_CACHE_KEY = 'end';

self.addEventListener('install', (event) => {
  event.waitUntil(
    (async () => {
      const cache = await caches.open(CACHE_NAME);
      await Promise.all([
        cache.put(START_CACHE_KEY, new Response('<html><head></head><body>')),
        cache.put(END_CACHE_KEY, new Response('</body></html>')),
      ]);
    })(),
  );
});

// Use a stale-while-revalidate strategy as a source for part of the response.
const apiStrategy = new workbox.strategies.StaleWhileRevalidate({
  cacheName: 'apiStrategy',
});

// String together an artificially complex series of stream sources.
const streamsStrategy = workbox.streams.strategy([
  () => caches.match(START_CACHE_KEY, {cacheName: CACHE_NAME}),
  () => `<p>🎉 This <code>iframe</code> is composed of multiple streams.</p>`,
  () => `<p>Here's an API call, using a stale-while-revalidate strategy:</p>`,
  ({event}) =>
    apiStrategy.handle({
      event: event,
      request: new Request('/api/date'),
    }),
  () => caches.match(END_CACHE_KEY, {cacheName: CACHE_NAME}),
]);

// Once the strategy is configured, the actual routing looks clean.
workbox.routing.registerRoute(new RegExp('iframe$'), streamsStrategy);

workbox.core.skipWaiting();
workbox.core.clientsClaim();


================================================
FILE: demos/src/workbox-sw/README.md
================================================
# workbox-sw-demo


================================================
FILE: demos/src/workbox-sw/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>workbox-sw demo</title>
    <meta
      name="workbox-sw demo"
      content="An example to demonstrate the workbox-sw module"
    />
    <link
      id="favicon"
      rel="icon"
      href="https://glitch.com/edit/favicon-app.ico"
      type="image/x-icon"
    />
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style>
      body {
        margin-left: 5%;
        font-family: 'Open Sans', sans-serif;
      }
      ol {
        padding-left: 20px;
      }
      li {
        margin-bottom: 5px;
      }
      button {
        margin: 20px 0;
        font-weight: bold;
      }
    </style>
  </head>
  <body>
    <header>
      <div>
        <h1>workbox-sw demo</h1>
      </div>
    </header>

    <ol>
      <li>Open DevTools and go to the console</li>
      <li>
        Click this button:<br /><button class="install-sw">
          Install Service Worker
        </button>
      </li>
      <li>You should see a workbox message appear</li>
      <li>
        Refresh the page, go to the network tab, and check the "Size" of
        demo-img.png. It should read (ServiceWorker)
      </li>
    </ol>

    <!-- Image will be stored in a custom cache -->
    <img src="demo-img.png" style="width: 300px; height: 300px" />

    <script>
      const installSWBtn = document.querySelector('.install-sw');
      installSWBtn.addEventListener('click', () => {
        navigator.serviceWorker.register('./sw.js');
      });
    </script>

    <p>
      <a href="https://developers.google.com/web/tools/workbox/modules"
        >Back to Demos</a
      >
    </p>

    <p>
      <a href="https://developers.google.com/web/tools/workbox">Docs</a> |
      <a href="https://github.com/googlechrome/workbox">GitHub</a> |
      <a href="https://twitter.com/workboxjs">@workboxjs</a>
    </p>
  </body>
</html>


================================================
FILE: demos/src/workbox-sw/package.json
================================================
{
  "name": "workbox-sw",
  "version": "1.0.0",
  "description": "Workbox SW Demo Git Listener",
  "scripts": {
    "start": "node updateServer.js"
  },
  "dependencies": {
    "express": "^4.17.1"
  },
  "engines": {
    "node": "8.x"
  },
  "license": "MIT"
}


================================================
FILE: demos/src/workbox-sw/sw.js
================================================
importScripts(
  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',
);

// Note: Ignore the error that Glitch raises about workbox being undefined.
workbox.setConfig({
  debug: true,
});

workbox.precaching.precacheAndRoute([
  'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css',
]);

// Demonstrates using default cache
workbox.routing.registerRoute(
  new RegExp('.*\\.(?:js)'),
  new workbox.strategies.NetworkFirst(),
);

// Demonstrates a custom cache name for a route.
workbox.routing.registerRoute(
  new RegExp('.*\\.(?:png|jpg|jpeg|svg|gif)'),
  new workbox.strategies.CacheFirst({
    cacheName: 'image-cache',
    plugins: [
      new workbox.expiration.ExpirationPlugin({
        maxEntries: 3,
      }),
    ],
  }),
);


================================================
FILE: demos/src/workbox-sw/updateServer.js
================================================
const express = require('express');
const app = express();
const path = require('path');

app.get('/', (request, response) => {
  response.sendFile(path.resolve('index.html'));
});

app.get('/sw.js', (request, response) => {
  response.sendFile(path.resolve('sw.js'));
});

app.use(express.static('public'));

/* /////////////////////////////////////////////////////////////////////////////
 The code below this comment is unrelated to the demo and used for maintenance
 vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
/////////////////////////////////////////////////////////////////////////////*/

const {execSync} = require('child_process');
const bodyParser = require('body-parser');

app.use(bodyParser.json());

app.post('/deploy', (request, response) => {
  if (request.query.secret !== process.env.SECRET) {
    response.status(401).send();
    return;
  }

  const repoUrl = request.query.repo;
  execSync(
    `git checkout -- ./ && git pull -X theirs ${repoUrl} ` +
      `glitch && refresh && git branch -D glitch`,
  );
  response.status(200).send();
});

const listener = app.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + listener.address().port);
});


================================================
FILE: demos/src/workbox-window/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>workbox-window demo</title>
    <meta
      name="workbox-window demo"
      content="An example to demonstrate the workbox-window module"
    />
    <link
      id="favicon"
      rel="icon"
      href="https://glitch.com/edit/favicon-app.ico"
      type="image/x-icon"
    />
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style>
      body {
        margin-left: 5%;
        font-family: 'Open Sans', sans-serif;
      }
      ol {
        padding-left: 20px;
      }
      li {
        margin-bottom: 5px;
      }
      button {
        margin: 20px 0;
        font-weight: bold;
      }
    </style>
  </head>
  <body>
    <header>
      <div>
        <h1>workbox-window Demo</h1>
      </div>
    </header>

    <ol>
      <li>workbox-window runs in the window context, not the service worker</li>
      <li>Open up DevTools and go to the console</li>
    </ol>

    <script type="module">
      import {Workbox} from 'https://storage.googleapis.com/workbox-cdn/releases/5.0.0-beta.1/workbox-window.prod.mjs';

      if ('serviceWorker' in navigator) {
        const wb = new Workbox('/sw.js');

        wb.addEventListener('activated', (event) => {
          // `event.isUpdate` will be true if another version of the service
          // worker was controlling the page when this version was registered.
          if (!event.isUpdate) {
            console.log('Service worker activated for the first time!');

            // If your service worker is configured to precache assets, those
            // assets should all be available now.
          }
        });

        wb.addEventListener('waiting', (event) => {
          console.log(
            `A new service worker has installed, but it can't activate` +
              `until all tabs running the current version have fully unloaded.`,
          );
        });

        // Register the service worker after event listeners have been added.
        wb.register();

        const message = async () => {
          const swVersion = await wb.messageSW({type: 'GET_VERSION'});
          console.log('Service Worker version:', swVersion);
        };

        message();
      }
    </script>

    <a href="https://developers.google.com/web/tools/workbox/modules"
      >Back to Demos</a
    >

    <p>
      <a href="https://developers.google.com/web/tools/workbox">Docs</a> |
      <a href="https://github.com/googlechrome/workbox">GitHub</a> |
      <a href="https://twitter.com/workboxjs">@workboxjs</a>
    </p>
  </body>
</html>


================================================
FILE: demos/src/workbox-window/package.json
================================================
{
  "name": "workbox-window",
  "version": "1.0.0",
  "description": "Workbox Window Demo Git Listener",
  "scripts": {
    "start": "node updateServer.js"
  },
  "dependencies": {
    "express": "^4.17.1"
  },
  "engines": {
    "node": "8.x"
  },
  "license": "MIT"
}


================================================
FILE: demos/src/workbox-window/sw.js
================================================
importScripts(
  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',
);

workbox.setConfig({
  debug: true,
});

const SW_VERSION = '5.0.0';

addEventListener('message', (event) => {
  if (event.data.type === 'GET_VERSION') {
    event.ports[0].postMessage(SW_VERSION);
  }
});


================================================
FILE: demos/src/workbox-window/updateServer.js
================================================
const express = require('express');
const app = express();
const path = require('path');

app.get('/', (request, response) => {
  response.sendFile(path.resolve('index.html'));
});

app.get('/sw.js', (request, response) => {
  response.sendFile(path.resolve('sw.js'));
});

app.use(express.static('public'));

/* /////////////////////////////////////////////////////////////////////////////
 The code below this comment is unrelated to the demo and used for maintenance
 vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
/////////////////////////////////////////////////////////////////////////////*/

const {execSync} = require('child_process');
const bodyParser = require('body-parser');

app.use(bodyParser.json());

app.post('/deploy', (request, response) => {
  if (request.query.secret !== process.env.SECRET) {
    response.status(401).send();
    return;
  }

  const repoUrl = request.query.repo;
  execSync(
    `git checkout -- ./ && git pull -X theirs ${repoUrl} ` +
      `glitch && refresh && git branch -D glitch`,
  );
  response.status(200).send();
});

const listener = app.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + listener.address().port);
});


================================================
FILE: gulp-tasks/analyze-properties.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const AnalyseBuildForProperties = require('./utils/analyse-properties');

async function analyze_properties() {
  const analysisTool = new AnalyseBuildForProperties();
  const results = await analysisTool.run();
  for (const result of results) {
    analysisTool.printDetails(result);
  }
}

module.exports = {
  analyze_properties,
};


================================================
FILE: gulp-tasks/build-node-packages.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const {parallel} = require('gulp');
const execa = require('execa');
const fse = require('fs-extra');
const TJS = require('typescript-json-schema');
const upath = require('upath');

const constants = require('./utils/constants');
const packageRunner = require('./utils/package-runner');

async function buildNodePackage(packagePath) {
  const outputDirectory = upath.join(
    packagePath,
    constants.PACKAGE_BUILD_DIRNAME,
  );

  const configFile = upath.join(
    __dirname,
    'utils',
    'node-projects-babel.config.json',
  );

  await execa(
    'babel',
    [
      '--config-file',
      configFile,
      `${packagePath}/src`,
      '--out-dir',
      outputDirectory,
      '--copy-files',
    ],
    {preferLocal: true},
  );
}

async function generateWorkboxBuildJSONSchema(packagePath) {
  // We only want to do this for workbox-build, but this function might be
  // run for any package, so exit early.
  if (!packagePath.endsWith('workbox-build')) {
    return;
  }

  const program = TJS.programFromConfig(
    upath.join(packagePath, 'tsconfig.json'),
  );
  const generator = TJS.buildGenerator(program, {
    noExtraProps: true,
    required: true,
  });
  const optionTypes = [
    'GenerateSWOptions',
    'GetManifestOptions',
    'InjectManifestOptions',
    'WebpackGenerateSWOptions',
    'WebpackInjectManifestOptions',
  ];
  for (const optionType of optionTypes) {
    const schema = generator.getSchemaForSymbol(optionType);

    if (schema.properties.manifestTransforms) {
      schema.properties.manifestTransforms.items = {};
    }

    if (schema.properties.exclude) {
      schema.properties.exclude.items = {};
    }

    if (schema.properties.include) {
      schema.properties.include.items = {};
    }

    // See https://github.com/GoogleChrome/workbox/issues/2910
    if (schema.definitions.OnSyncCallback) {
      schema.definitions.OnSyncCallback = {};
    }

    if (schema.definitions.AbortSignal) {
      schema.definitions.AbortSignal = {};
    }

    if (schema.definitions.RouteMatchCallback) {
      schema.definitions.RouteMatchCallback = {};
    }

    if (schema.definitions.RouteHandlerCallback) {
      schema.definitions.RouteHandlerCallback = {};
    }

    // See https://github.com/GoogleChrome/workbox/issues/2901
    if (schema.definitions.WorkboxPlugin) {
      for (const plugin of Object.keys(
        schema.definitions.WorkboxPlugin.properties,
      )) {
        schema.definitions.WorkboxPlugin.properties[plugin] = {};
      }
    }

    await fse.writeJSON(
      upath.join(packagePath, 'src', 'schema', `${optionType}.json`),
      schema,
      {spaces: 2},
    );
  }
}

module.exports = {
  build_node_packages: parallel(
    packageRunner('build_node_packages', 'node', buildNodePackage),
  ),
  build_node_ts_packages: parallel(
    packageRunner(
      'build_node_ts_packages',
      'node_ts',
      generateWorkboxBuildJSONSchema,
    ),
  ),
};


================================================
FILE: gulp-tasks/build-packages.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const {parallel, series} = require('gulp');
const del = require('del');
const fse = require('fs-extra');
const upath = require('upath');

const {
  build_node_packages,
  build_node_ts_packages,
} = require('./build-node-packages');
const {build_sw_packages} = require('./build-sw-packages');
const {build_window_packages} = require('./build-window-packages');
const {transpile_typescript} = require('./transpile-typescript');
const constants = require('./utils/constants');
const packageRunner = require('./utils/package-runner');

async function cleanPackage(packagePath) {
  // Delete generated files from the the TypeScript transpile.
  if (await fse.pathExists(upath.join(packagePath, 'src', 'index.ts'))) {
    // Store the list of deleted files, so we can delete directories after.
    const deletedPaths = await del([
      `${packagePath}/**/*.+(js|mjs|d.ts)`,
      // Don't delete files in node_modules.
      '!**/node_modules/**/*',
      // Don't delete anything under src.
      `!${packagePath}/src/**/*`,
    ]);

    // Any directories in `deletedPaths` that are top-level directories to the
    // package should also be deleted since those directories should only
    // contain generated `.mjs` and `.d.ts` files.
    const directoriesToDelete = new Set();
    for (const deletedPath of deletedPaths) {
      const relativePath = upath.relative(packagePath, deletedPath);
      const directory = relativePath.split(upath.sep)[0];
      directoriesToDelete.add(upath.join(packagePath, directory));
    }
    await del([...directoriesToDelete]);
  }

  // Delete build files.
  await del(upath.join(packagePath, constants.PACKAGE_BUILD_DIRNAME));

  // Delete tsc artifacts (if present).
  await del(upath.join(packagePath, 'tsconfig.tsbuildinfo'));
}

// Wrap this in a function since it's used multiple times.
function cleanSequence() {
  return parallel(packageRunner('build_packages_clean', 'all', cleanPackage));
}

module.exports = {
  build_packages_clean: cleanSequence(),
  build_packages: series(
    // This needs to be a series, not in parallel, so that there isn't a
    // race condition with the terser nameCache.
    transpile_typescript,
    series(build_sw_packages, build_window_packages),
    parallel(build_node_packages, build_node_ts_packages),
  ),
};


================================================
FILE: gulp-tasks/build-sw-packages.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const {parallel, series} = require('gulp');
const {rollup} = require('rollup');
const fse = require('fs-extra');
const ol = require('common-tags').oneLine;
const upath = require('upath');

const constants = require('./utils/constants');
const logHelper = require('../infra/utils/log-helper');
const packageRunner = require('./utils/package-runner');
const pkgPathToName = require('./utils/pkg-path-to-name');
const rollupHelper = require('./utils/rollup-helper');
const versionModule = require('./utils/version-module');

// This makes Rollup assume workbox-* will be added to the global
// scope and replace references with the core namespace.
function globals(moduleId) {
  if (moduleId === 'workbox') {
    return moduleId;
  }

  const splitImportPath = moduleId.split('/');
  if (splitImportPath[0].indexOf('workbox-') !== 0) {
    throw new Error(`Unknown global module ID: ${moduleId}`);
  }

  const packageName = splitImportPath.shift();
  const packagePath = upath.join(__dirname, '..', 'packages', packageName);
  const namespacePathParts = splitImportPath.map((importPathPiece) => {
    // The browser namespace will need the file extension removed
    return upath.basename(importPathPiece, upath.extname(importPathPiece));
  });

  if (namespacePathParts.length === 0) {
    // Tried to pull in default export of module - this isn't allowed.
    // A specific file must be referenced
    throw new Error(ol`You cannot use a module directly. Instead, you must
        specify a named import, to facilitate tree-shaking. Please fix the
        import: '${moduleId}'`);
  }

  let additionalNamespace;
  if (namespacePathParts.length > 1) {
    if (namespacePathParts[0] !== '_private' || namespacePathParts.length > 2) {
      // Tried to pull in default export of module - this isn't allowed.
      // A specific file must be referenced
      throw new Error(ol`You cannot use nested files. It must be a top level
          (and public) file or a file under '_private' in a module. Please fix
          the import: '${moduleId}'`);
    }
    additionalNamespace = namespacePathParts[0];
  }

  // Get a package's browserNamespace so we know where it will be
  // on the global scope (i.e. workbox.<browserNamespace>)
  try {
    const pkg = require(upath.join(packagePath, 'package.json'));
    return [pkg.workbox.browserNamespace, additionalNamespace]
      .filter((value) => value && value.length > 0)
      .join('.');
  } catch (err) {
    logHelper.error(`Unable to get browserNamespace for '${packageName}'`);
    throw err;
  }
}

// This ensures all workbox-* modules are treated as external and are
// referenced as globals.
function externalAndPure(importPath) {
  return importPath.indexOf('workbox-') === 0;
}

async function buildSWBundle(packagePath, buildType) {
  const packageName = pkgPathToName(packagePath);
  const packageIndex = upath.join(packagePath, 'index.mjs');

  // First check if the bundle file exists, if it doesn't
  // there is nothing to build
  if (!(await fse.exists(packageIndex))) {
    throw new Error(`Could not find ${packageIndex}`);
  }

  const pkgJson = require(upath.join(packagePath, 'package.json'));
  if (!pkgJson.workbox || !pkgJson.workbox.browserNamespace) {
    throw new Error(ol`You must define a 'workbox.browserNamespace' property in
        ${packageName}/package.json`);
  }

  let outputFilename = pkgJson.workbox.outputFilename || packageName;
  if (pkgJson.workbox.prodOnly) {
    // Bail out early if this is a non-prod build.
    if (buildType !== constants.BUILD_TYPES.prod) {
      return Promise.resolve();
    }
  } else {
    // Prod-only builds (above) don't need the build type, but when there's a
    // dev and prod build we have to include it.
    outputFilename += `.${buildType.slice(0, 4)}`;
  }
  outputFilename += '.js';

  const namespace = pkgJson.workbox.browserNamespace;
  const outputDirectory = upath.join(
    packagePath,
    constants.PACKAGE_BUILD_DIRNAME,
  );

  const plugins = rollupHelper.getDefaultPlugins(buildType);

  const bundle = await rollup({
    input: packageIndex,
    external: externalAndPure,
    treeshake: {
      moduleSideEffects: externalAndPure ? 'no-external' : false,
    },
    plugins,
    onwarn: (warning) => {
      if (
        buildType === constants.BUILD_TYPES.prod &&
        warning.code === 'UNUSED_EXTERNAL_IMPORT'
      ) {
        // This can occur when using rollup-plugin-replace.
        logHelper.warn(`[${warning.code}] ${warning.message}`);
        return;
      }

      // The final builds should have no warnings.
      if (warning.code && warning.message) {
        throw new Error(
          `Unhandled Rollup Warning: [${warning.code}] ` + `${warning.message}`,
        );
      } else {
        throw new Error(`Unhandled Rollup Warning: ${warning}`);
      }
    },
  });

  await bundle.write({
    file: upath.join(outputDirectory, outputFilename),
    name: namespace,
    sourcemap: true,
    format: 'iife',
    globals,
    esModule: false,
  });
}

// This reads a little cleaner with a function to generate the sub-sequences.
function swBundleSequence() {
  const builds = Object.keys(constants.BUILD_TYPES).map((type) =>
    packageRunner(
      'build_sw_packages_bundle',
      'sw',
      buildSWBundle,
      constants.BUILD_TYPES[type],
    ),
  );

  return series(builds);
}

module.exports = {
  build_sw_packages: series(
    parallel(
      packageRunner('build_sw_packages_version_module', 'sw', versionModule),
    ),
    swBundleSequence(),
  ),
};


================================================
FILE: gulp-tasks/build-window-packages.js
================================================
/*
  Copyright 2019 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const {parallel, series} = require('gulp');
const {rollup} = require('rollup');
const fse = require('fs-extra');
const ol = require('common-tags').oneLine;
const upath = require('upath');

const constants = require('./utils/constants');
const logHelper = require('../infra/utils/log-helper');
const packageRunner = require('./utils/package-runner');
const pkgPathToName = require('./utils/pkg-path-to-name');
const rollupHelper = require('./utils/rollup-helper');
const versionModule = require('./utils/version-module');

async function buildWindowBundle(packagePath, buildType) {
  const packageName = pkgPathToName(packagePath);
  const packageIndex = upath.join(packagePath, 'index.mjs');

  if (!(await fse.exists(packageIndex))) {
    throw new Error(`Could not find ${packageIndex}`);
  }

  const outputDirectory = upath.join(
    packagePath,
    constants.PACKAGE_BUILD_DIRNAME,
  );

  const esmFilename = `${packageName}.${buildType.slice(0, 4)}.mjs`;
  const esmLegacyFilename = `${packageName}.${buildType.slice(0, 4)}.es5.mjs`;
  const umdFilename = `${packageName}.${buildType.slice(0, 4)}.umd.js`;

  const onwarn = (warning) => {
    // This can occur when using rollup-plugin-replace.
    if (
      buildType === constants.BUILD_TYPES.prod &&
      warning.code === 'UNUSED_EXTERNAL_IMPORT'
    ) {
      logHelper.warn(`[${warning.code}] ${warning.message}`);
      return;
    }

    // The final builds should have no warnings.
    if (warning.code && warning.message) {
      throw new Error(ol`Unhandled Rollup Warning:
          [${warning.code}] ${warning.message}`);
    } else {
      throw new Error(`Unhandled Rollup Warning: ${warning}`);
    }
  };

  const mjsBundle = await rollup({
    input: packageIndex,
    plugins: rollupHelper.getDefaultPlugins(buildType, 'esm', false),
    onwarn,
  });

  const es5Bundle = await rollup({
    input: packageIndex,
    plugins: rollupHelper.getDefaultPlugins(buildType, 'esm', true),
    onwarn,
  });

  const umdBundle = await rollup({
    input: packageIndex,
    plugins: rollupHelper.getDefaultPlugins(buildType, 'umd', true),
    onwarn,
  });

  // Generate both a native module and a UMD module (for compat).
  await Promise.all([
    mjsBundle.write({
      file: upath.join(outputDirectory, esmFilename),
      sourcemap: true,
      format: 'esm',
    }),
    es5Bundle.write({
      file: upath.join(outputDirectory, esmLegacyFilename),
      sourcemap: true,
      format: 'esm',
    }),
    umdBundle.write({
      file: upath.join(outputDirectory, umdFilename),
      sourcemap: true,
      format: 'umd',
      name: 'workbox',
    }),
  ]);
}

// This reads a little cleaner with a function to generate the sub-sequences.
function windowBundleSequence() {
  const builds = Object.keys(constants.BUILD_TYPES).map((type) =>
    packageRunner(
      'build_window_packages_bundle',
      'window',
      buildWindowBundle,
      constants.BUILD_TYPES[type],
    ),
  );

  return series(builds);
}

module.exports = {
  build_window_packages: series(
    parallel(
      packageRunner(
        'build_window_packages_version_module',
        'window',
        versionModule,
      ),
    ),
    windowBundleSequence(),
  ),
};


================================================
FILE: gulp-tasks/build.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const {series} = require('gulp');
const execa = require('execa');
const fse = require('fs-extra');
const upath = require('upath');

const {build_packages} = require('./build-packages');

// This is needed for workbox-build but is also used by the rollup-helper
// to add CDN details to workbox-sw.
// Make sure this runs **before** build_lerna_bootstrap.
async function build_update_cdn_details() {
  const cdnDetails = await fse.readJSON(
    upath.join(__dirname, '..', 'cdn-details.json'),
  );

  const workboxBuildPath = upath.join(
    __dirname,
    '..',
    'packages',
    'workbox-build',
  );

  const workboxBuildCdnDetailsPath = upath.join(
    workboxBuildPath,
    'src',
    'cdn-details.json',
  );

  const workboxBuildPkg = await fse.readJSON(
    upath.join(workboxBuildPath, 'package.json'),
  );

  cdnDetails.latestVersion = workboxBuildPkg.version;

  await fse.writeJson(workboxBuildCdnDetailsPath, cdnDetails, {
    spaces: 2,
  });
}

async function build_lerna_bootstrap() {
  await execa('lerna', ['bootstrap'], {preferLocal: true});
}

module.exports = {
  build: series(
    build_update_cdn_details,
    build_lerna_bootstrap,
    build_packages,
  ),
};


================================================
FILE: gulp-tasks/docs.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const {series, watch} = require('gulp');
const execa = require('execa');
const fse = require('fs-extra');
const upath = require('upath');

const logHelper = require('../infra/utils/log-helper');

const DOCS_DIRECTORY = upath.join(__dirname, '..', 'docs');

async function docs_build() {
  await fse.remove(DOCS_DIRECTORY);

  const queryString = [
    `projectRoot=/`,
    `basepath=/`,
    `productName=Workbox`,
  ].join('&');

  const params = [
    '-c',
    upath.join(__dirname, '..', 'jsdoc.conf'),
    '-d',
    DOCS_DIRECTORY,
  ];

  if (!(global.cliOptions && global.cliOptions.pretty)) {
    logHelper.warn(`

These docs will look ugly, but they will more accurately match what
is shown on developers.google.com.

You can view a friendlier UI by running

'gulp docs --pretty'
`);
    params.push(
      '--template',
      upath.join(
        __dirname,
        '..',
        'infra',
        'templates',
        'reference-docs',
        'jsdoc',
      ),
      '--query',
      queryString,
    );
  }

  if (global.cliOptions && global.cliOptions.debugDocs) {
    params.push('--debug');
  }

  await execa('jsdoc', params, {preferLocal: true});
}

function docs_watch() {
  const watcher = watch('packages/**/*', docs_build);
  watcher.on('error', (err) => logHelper.error(`Docs failed to build: `, err));
}

module.exports = {
  docs_build,
  docs: series(docs_build, docs_watch),
};


================================================
FILE: gulp-tasks/lint.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const {parallel} = require('gulp');
const execa = require('execa');

async function lint_js() {
  await execa(
    'eslint',
    [
      '**/*.{js,mjs}',
      '--config',
      'javascript.eslintrc.js',
      '--ignore-path',
      '.gitignore',
    ],
    {preferLocal: true},
  );
}

async function lint_ts() {
  await execa(
    'eslint',
    [
      '**/*.ts',
      '--config',
      'typescript.eslintrc.js',
      '--ignore-path',
      '.gitignore',
    ],
    {preferLocal: true},
  );
}

module.exports = {
  lint_js,
  lint_ts,
  // Temporarily disable lint_ts until we upgrade our ESLint dependencies.
  lint: parallel(lint_js, lint_ts),
};


================================================
FILE: gulp-tasks/publish-cdn.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const upath = require('upath');

const cdnUploadHelper = require('./utils/cdn-helper');
const githubHelper = require('./utils/github-helper');
const logHelper = require('../infra/utils/log-helper');
const publishHelpers = require('./utils/publish-helpers');

// Git adds 'v' to tag name, lerna does not in package.json version.
// We are going to publish to CDN *without* the 'v'
function cleanTagName(name) {
  let friendlyTagName = name;

  if (friendlyTagName.startsWith('v')) {
    friendlyTagName = friendlyTagName.substring(1);
  }

  return friendlyTagName;
}

async function findMissingCDNTags(tagsData) {
  const missingTags = [];

  for (const tagData of tagsData) {
    const exists = await cdnUploadHelper.tagExists(cleanTagName(tagData.name));

    if (!exists) {
      missingTags.push(tagData);
    }
  }

  return missingTags;
}

async function handleCDNUpload(tagName, gitBranch) {
  const buildDir = await publishHelpers.groupBuildFiles(tagName, gitBranch);

  const friendlyTagName = cleanTagName(tagName);

  logHelper.log(`Uploading '${tagName}' to the CDN as ${friendlyTagName}.`);
  const urls = await cdnUploadHelper.upload(friendlyTagName, buildDir);

  logHelper.log('The following URLs are now available:');
  for (const url of urls) {
    // Skip the .map for cleaner logs.
    if (upath.extname(url) !== '.map') {
      logHelper.log(`• ${url}`);
    }
  }
}

async function publish_cdn() {
  let missingTags = [];

  // Usage: npx gulp publish_cdn --cdnTag=vX.Y.Z
  // See https://github.com/GoogleChrome/workbox/issues/2479
  if (global.cliOptions.cdnTag) {
    const tags = [{name: global.cliOptions.cdnTag}];
    missingTags = await findMissingCDNTags(tags);
  } else {
    // Get all of the tags in the repo.
    const tags = await githubHelper.getTags();
    missingTags = await findMissingCDNTags(tags);

    if (missingTags.length === 0) {
      logHelper.log('No tags missing from CDN.');
    }
  }

  for (const missingTag of missingTags) {
    // Override the git branch here since we aren't actually
    // using a tagged release.
    await handleCDNUpload(missingTag.name, missingTag.name);
  }
}

module.exports = {
  publish_cdn,
};


================================================
FILE: gulp-tasks/publish-github.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const semver = require('semver');

const githubHelper = require('./utils/github-helper');
const logHelper = require('../infra/utils/log-helper');

async function publishReleaseOnGithub(tagName, releaseInfo) {
  if (!releaseInfo) {
    const releaseData = await githubHelper.createRelease({
      tag_name: tagName,
      draft: true,
      name: `Workbox ${tagName}`,
      prerelease: semver.prerelease(tagName) !== null,
    });
    releaseInfo = releaseData.data;
  }
}

async function handleGithubRelease(tagName, gitBranch, releaseInfo) {
  logHelper.log(`Creating GitHub release ${logHelper.highlight(tagName)}.`);

  await publishReleaseOnGithub(tagName, releaseInfo);
}

function filterTagsWithReleaseBundles(allTags, taggedReleases) {
  return allTags.filter((tagInfo) => {
    const release = taggedReleases[tagInfo.name];
    if (release && release.assets.length > 0) {
      // If a tag has a release and there is an asset let's assume the
      // the release is fine. Note: GitHub's source doesn't count as an
      // asset
      return false;
    }

    return true;
  });
}

async function publish_github() {
  // Get all of the tags in the repo.
  const allTags = await githubHelper.getTags();
  const taggedReleases = await githubHelper.getTaggedReleases();
  const tagsToBuild = filterTagsWithReleaseBundles(allTags, taggedReleases);

  if (tagsToBuild.length === 0) {
    logHelper.log(`No tags missing from GitHub.`);
    return;
  }

  for (const tagToBuild of tagsToBuild) {
    await handleGithubRelease(
      tagToBuild.name,
      tagToBuild.name,
      taggedReleases[tagToBuild.name],
    );
  }
}

module.exports = {
  publish_github,
};


================================================
FILE: gulp-tasks/publish-glitch.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const del = require('del');
const execa = require('execa');
const fse = require('fs-extra');
const globby = require('globby');
const ol = require('common-tags').oneLine;
const olt = require('common-tags').oneLineTrim;
const tempy = require('tempy');
const upath = require('upath');

const logHelper = require('../infra/utils/log-helper');

const DEMOS_DIR = 'demos/src';

async function publish_glitch() {
  const glitchProjects = await globby('*', {cwd: DEMOS_DIR, onlyFiles: false});

  if (!process.env.GLITCH_PERSONAL_TOKEN) {
    throw new Error(ol`You must set a GLITCH_TOKEN in your environment to
        publish to Glitch (you must have owner or editor access for the
        demo associated with the token).`);
  }

  if (!process.env.GLITCH_WORKBOX_SECRET) {
    throw new Error(ol`You must set the correct GLITCH_SECRET in your
        environment to publish to Workbox Demos on Glitch.`);
  }

  for (const project of glitchProjects) {
    const projectURL = olt`https://${process.env.GLITCH_PERSONAL_TOKEN}
        @api.glitch.com/git/${project}`;
    const projectPath = tempy.directory();

    try {
      await execa('git', ['clone', projectURL, projectPath]);
      await fse.copy(upath.join(DEMOS_DIR, project), projectPath, {
        overwrite: true,
      });
      await execa('git', ['checkout', '-b', 'glitch'], {cwd: projectPath});
      await execa('git', ['add', '-A'], {cwd: projectPath});
      await execa('git', ['commit', `-m'Autocommit on ${new Date()}'`], {
        cwd: projectPath,
      });
      await execa(
        'git',
        ['push', 'origin', 'glitch', '-f', '--set-upstream', '--no-verify'],
        {cwd: projectPath},
      );

      const deployURL = new URL(`https://${project}.glitch.me/deploy`);
      deployURL.searchParams.set('secret', process.env.GLITCH_WORKBOX_SECRET);
      deployURL.searchParams.set(
        'repo',
        `https://api.glitch.com/git/${project}`,
      );
      await execa('curl', ['-X', 'POST', deployURL.href]);
    } catch (error) {
      logHelper.error(`'${error}' occurred while processing ${project}.`);
    }

    await del(projectPath, {force: true});
  }
}

module.exports = {
  publish_glitch,
};


================================================
FILE: gulp-tasks/publish-lerna.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const execa = require('execa');
const ol = require('common-tags').oneLine;

const logHelper = require('../infra/utils/log-helper');

async function publish_lerna() {
  // See https://github.com/GoogleChrome/workbox/issues/2904#issuecomment-894452253
  const options = ['publish', '--force-publish', '--exact'];

  // gulp publish --distTag=latest would be the most common.
  if (global.cliOptions.distTag) {
    logHelper.log(
      ol`Using ${logHelper.highlight(
        '--dist-tag=' + global.cliOptions.distTag,
      )}`,
    );
    options.push('--dist-tag', global.cliOptions.distTag);
  } else {
    throw new Error(ol`Please set the --distTag command line option, normally
        to 'latest' (for a stable release) or 'next' (for a pre-release).`);
  }

  await execa('lerna', options, {
    preferLocal: true,
    stdio: 'inherit',
  });
}

module.exports = {
  publish_lerna,
};


================================================
FILE: gulp-tasks/publish.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const {series} = require('gulp');
const execa = require('execa');
const fse = require('fs-extra');
const ol = require('common-tags').oneLine;

const {build} = require('./build');
const {build_packages_clean} = require('./build-packages');
const {publish_cdn} = require('./publish-cdn');
const {publish_github} = require('./publish-github');
const {publish_lerna} = require('./publish-lerna');
const {test} = require('./test');
const constants = require('./utils/constants');

async function publish_clean() {
  await fse.remove(constants.GENERATED_RELEASE_FILES_DIRNAME);
}

async function publish_sign_in_check() {
  await execa('npm', ['whoami']);
}

async function dist_tag_check() {
  if (!global.cliOptions.distTag) {
    throw new Error(ol`Please set the --distTag command line option, normally
        to 'latest' (for a stable release) or 'next' (for a pre-release).`);
  }
}

module.exports = {
  publish: series(
    dist_tag_check,
    publish_sign_in_check,
    build_packages_clean,
    publish_clean,
    build,
    test,
    publish_lerna,
    publish_github,
    publish_cdn,
  ),
};


================================================
FILE: gulp-tasks/test-integration.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const clearModule = require('clear-module');
const execa = require('execa');
const {globSync} = require('glob');
const ol = require('common-tags').oneLine;
const upath = require('upath');
const seleniumAssistant = require('selenium-assistant');

const constants = require('./utils/constants');
const logHelper = require('../infra/utils/log-helper');
const server = require('../infra/testing/server/index');

function runFiles(filePaths) {
  // Mocha can't be run multiple times, which we need for NODE_ENV.
  // More info: https://github.com/mochajs/mocha/issues/995
  clearModule.all();
  const Mocha = require('mocha');

  return new Promise((resolve, reject) => {
    const mocha = new Mocha({
      retries: process.env.TRAVIS || process.env.GITHUB_ACTIONS ? 4 : 1,
      timeout: 3 * 60 * 1000,
    });

    for (const filePath of filePaths) {
      mocha.addFile(filePath);
    }

    // Run the tests.
    mocha.run(function (failureCount) {
      if (failureCount > 0) {
        return reject(new Error(`${failureCount} tests failed.`));
      }
      resolve();
    });
  });
}

async function runTestSuite(testPath, nodeEnv, seleniumBrowser, webdriver) {
  logHelper.log(ol`Running integration test on ${logHelper.highlight(testPath)}
      with NODE_ENV '${nodeEnv}' and browser
      '${logHelper.highlight(seleniumBrowser.getPrettyName())}'`);

  const options = [];
  if (global.cliOptions.grep) {
    options.push('--grep', global.cliOptions.grep);
  }
  const originalNodeEnv = process.env.NODE_ENV;

  process.env.NODE_ENV = nodeEnv;

  try {
    global.__workbox = {
      seleniumBrowser,
      server,
      webdriver,
    };

    const testFiles = globSync(
      upath.join(__dirname, '..', testPath, 'test-*.js'),
    );

    await runFiles(testFiles);
  } finally {
    process.env.NODE_ENV = originalNodeEnv;
  }
}

async function runIntegrationForBrowser(browser) {
  const packagesToTest = globSync(`test/${global.packageOrStar}/integration`);

  for (const buildKey of Object.keys(constants.BUILD_TYPES)) {
    const webdriver = await browser.getSeleniumDriver();
    const timeout = 2 * 60 * 1000;
    webdriver.manage().setTimeouts({
      implicit: timeout,
      pageLoad: timeout,
      script: timeout,
    });

    for (const packageToTest of packagesToTest) {
      // Since workbox-google-analytics is deprecated, removing the tests from integration tests.
      if (packageToTest.includes('workbox-google-analytics')) {
        continue;
      }
      const nodeEnv = constants.BUILD_TYPES[buildKey];
      try {
        await runTestSuite(packageToTest, nodeEnv, browser, webdriver);
      } catch (error) {
        await seleniumAssistant.killWebDriver(webdriver);
        throw error;
      }
    }

    await seleniumAssistant.killWebDriver(webdriver);
  }
}

async function test_integration() {
  if (process.platform === 'win32') {
    logHelper.warn(`Skipping integration tests on Windows.`);
    return;
  }

  // Install the latest Chrome and Firefox webdrivers without referencing
  // package-lock.json, to ensure that they're up to date.
  await execa('npm', ['install', '--no-save', 'chromedriver', 'geckodriver'], {
    preferLocal: true,
  });

  logHelper.log(`Downloading browsers...`);
  const expiration = 24;
  // We are only running tests in stable, see bellow for reasons.
  await seleniumAssistant.downloadLocalBrowser('chrome', 'stable', expiration);
  await seleniumAssistant.downloadLocalBrowser('firefox', 'stable', expiration);

  const packagesToTest = globSync(`test/${global.packageOrStar}/integration`);
  if (packagesToTest.length === 0) {
    return;
  }

  await server.start();

  try {
    const localBrowsers = seleniumAssistant.getLocalBrowsers();
    for (const localBrowser of localBrowsers) {
      switch (localBrowser.getId()) {
        case 'firefox':
          if (localBrowser.getReleaseName() !== 'unstable') {
            await runIntegrationForBrowser(localBrowser);
          }
          break;
        // Temporarily only test the stable release of Chrome, until the next
        // https://www.npmjs.com/package/chromedriver release.
        case 'chrome':
        case 'safari':
          if (localBrowser.getReleaseName() === 'stable') {
            await runIntegrationForBrowser(localBrowser);
          }
          break;
        default:
          logHelper.warn(ol`Skipping integration tests for
              ${localBrowser.getPrettyName()}.`);
      }
    }
  } finally {
    await server.stop();
  }
}

module.exports = {
  test_integration,
};


================================================
FILE: gulp-tasks/test-node.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const {series} = require('gulp');
const execa = require('execa');
const fse = require('fs-extra');
const {globSync} = require('glob');
const ol = require('common-tags').oneLine;
const upath = require('upath');

const constants = require('./utils/constants');
const logHelper = require('../infra/utils/log-helper');

async function runNodeTestSuite(testPath, nodeEnv) {
  logHelper.log(ol`Running node test on ${logHelper.highlight(testPath)}
      with NODE_ENV '${nodeEnv}'`);

  const options = [];
  if (global.cliOptions.grep) {
    options.push('--grep', global.cliOptions.grep);
  }
  const originalNodeEnv = process.env.NODE_ENV;

  process.env.NODE_ENV = nodeEnv;
  try {
    const {stdout} = await execa(
      'nyc',
      [
        '--clean',
        'false',
        '--silent',
        'mocha',
        '--timeout',
        '60000',
        `${testPath}/**/*.{js,mjs}`,
        ...options,
      ],
      {preferLocal: true},
    );

    console.log(stdout);
  } finally {
    process.env.NODE_ENV = originalNodeEnv;
  }
}

async function runNodeTestsWithEnv(testGroup, nodeEnv) {
  const globConfig = {
    ignore: ['**/all/**'],
  };

  if (testGroup === 'all') {
    globConfig.ignore = [];
  }

  const packagesToTest = globSync(`test/${testGroup}/node`, globConfig);
  for (const packageToTest of packagesToTest) {
    // Hardcode special logic for webpack v4 and v5 tests, which need to
    // be run in separate processes.
    if (packageToTest.includes('workbox-webpack-plugin')) {
      await runNodeTestSuite(`${packageToTest}/v4`, nodeEnv);
      await runNodeTestSuite(`${packageToTest}/v5`, nodeEnv);
    } else {
      await runNodeTestSuite(packageToTest, nodeEnv);
    }
  }
}

async function test_node_prod() {
  await runNodeTestsWithEnv(global.packageOrStar, constants.BUILD_TYPES.prod);
}

async function test_node_dev() {
  await runNodeTestsWithEnv(global.packageOrStar, constants.BUILD_TYPES.dev);
}

async function test_node_all() {
  await runNodeTestsWithEnv('all', constants.BUILD_TYPES.prod);
}

async function test_node_clean() {
  await fse.remove(upath.join(__dirname, '..', '.nyc_output'));
}

async function test_node_coverage() {
  const runOptions = [];
  if (global.packageOrStar !== '*') {
    runOptions.push('--include');
    runOptions.push(upath.join('packages', global.packageOrStar, '**', '*'));
  }

  const {stdout} = await execa(
    'nyc',
    ['report', '--reporter', 'lcov', '--reporter', 'text', ...runOptions],
    {preferLocal: true},
  );

  console.log(stdout);
}

module.exports = {
  test_node_all,
  test_node_coverage,
  test_node_dev,
  test_node_prod,
  test_node: series(
    test_node_clean,
    test_node_dev,
    test_node_prod,
    test_node_all,
    test_node_coverage,
  ),
};


================================================
FILE: gulp-tasks/test-server.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const {series} = require('gulp');

const {
  transpile_typescript,
  transpile_typescript_watch,
} = require('./transpile-typescript');
const constants = require('./utils/constants');
const testServer = require('../infra/testing/server/index');

function handleExit() {
  testServer.stop();
  process.exit(0);
}

function startServer() {
  process.env.NODE_ENV = process.env.NODE_ENV || constants.BUILD_TYPES.dev;

  const eventNames = [
    'exit',
    'SIGINT',
    'SIGUSR1',
    'SIGUSR2',
    'uncaughtException',
  ];
  for (const eventName of eventNames) {
    process.on(eventName, handleExit);
  }

  return testServer.start();
}

module.exports = {
  test_server: series(
    transpile_typescript,
    startServer,
    transpile_typescript_watch,
  ),
};


================================================
FILE: gulp-tasks/test.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const {parallel, series} = require('gulp');

const {lint} = require('./lint');
const {test_integration} = require('./test-integration');
const {test_node} = require('./test-node');
const logHelper = require('../infra/utils/log-helper');

async function logSkip() {
  logHelper.log('Skipping test suite due to --skipTests');
}

function runTestsUnlessSkipped() {
  if (global.cliOptions.skipTests) {
    return logSkip;
  } else {
    // The node and integration tests both muck with process.env.NODE_ENV,
    // and therefore can't be run in parallel.
    return parallel(lint, series(test_node, test_integration));
  }
}

module.exports = {
  test: runTestsUnlessSkipped(),
};


================================================
FILE: gulp-tasks/transpile-typescript.js
================================================
/*
  Copyright 2019 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const execa = require('execa');
const fse = require('fs-extra');
const globby = require('globby');
const upath = require('upath');

const {AsyncDebounce} = require('../infra/utils/AsyncDebounce');

/**
 * A mapping between each package name and its corresponding `AsyncDebounce`
 * instance of the `transpilePackage()` function.
 *
 * @type {{[key: string]: AsyncDebounce}}
 */
const debouncedTranspilerMap = {};

/**
 * Takes a package name and schedules that package's source TypeScript code
 * to be converted to JavaScript. If a transpilation is already scheduled, it
 * won't be queued twice, so this function is safe to call as frequently as
 * needed.
 *
 * @param {string} packageName
 * @param {Object} [options]
 */
async function queueTranspile(packageName, options) {
  if (!debouncedTranspilerMap[packageName]) {
    debouncedTranspilerMap[packageName] = new AsyncDebounce(async () => {
      await transpile_typescript();
    });
  }
  await debouncedTranspilerMap[packageName].call();
  debouncedTranspilerMap[packageName] = null;
}

/**
 * A mapping between package names and whether or not they have pending
 * file changes
 *
 * @type {{[key: string]: boolean}}
 */
const pendingChangesMap = {};

/**
 * Returns true if a TypeScript file has been modified in the package since
 * the last time it was transpiled.
 *
 * @param {string} packageName
 */
function needsTranspile(packageName) {
  return pendingChangesMap[packageName] === true;
}

/**
 * Transpiles all packages listed in the root tsconfig.json's references section
 * into .js and .d.ts files. Creates stub .mjs files that re-export the contents
 * of the .js files.
 *
 * Unlike other scripts, this does not take the --package= command line param
 * into account. Each project in packages/ theoretically could depend on any
 * other project, so kicking off a single, top-level compilation makes the
 * most sense (and is faster when all the packages need to be compiled).
 */
async function transpile_typescript() {
  await execa('tsc', ['--build', 'tsconfig.json'], {preferLocal: true});

  const jsFiles = await globby(`packages/*/**/*.js`, {
    ignore: ['**/build/**', '**/src/**'],
  });

  for (const jsFile of jsFiles) {
    const {dir, name} = upath.parse(jsFile);
    const mjsFile = upath.join(dir, `${name}.mjs`);
    const mjsSource = `export * from './${name}.js';`;
    await fse.outputFile(mjsFile, mjsSource);
  }
}

async function transpile_typescript_watch() {
  await execa('tsc', ['--build', '--watch', 'tsconfig.json'], {
    preferLocal: true,
  });
}

module.exports = {
  // These are used as functions from other modules, not as gulp tasks.
  functions: {
    needsTranspile,
    queueTranspile,
  },
  transpile_typescript_watch,
  transpile_typescript,
};


================================================
FILE: gulp-tasks/utils/analyse-properties.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

/*
 * This file should be run as a node script to analyse the content of the
 * browser bundles.
 *
 * It's an extremely naive approach to picking property names out and seeing
 * how often they are used in the final browser bundles. This can be
 * used to detect variable names that are long and used repeatedly meaning
 * that a small refactor allowing `uglify-es` to mangle these properties,
 * could lead to reasonable improvement in final bundle size.
 *
 * This is very rough and vague. It needs to be run manually and if it's not
 * used can and should be removed from Workbox repo.
 */
const {globSync} = require('glob');
const path = require('path');
const fs = require('fs-extra');
const babylon = require('babylon');

const constants = require('./constants');
const logHelper = require('../../infra/utils/log-helper');

class AnalyseBuildForProperties {
  run() {
    const filePaths = this.getBuildFiles();
    return Promise.all(
      filePaths.map((filePath) => {
        const rawAnalysis = this.analyzeFile(filePath);
        const analysis = this.tidyData(rawAnalysis);

        return {
          filePath,
          analysis,
        };
      }),
    );
  }

  getBuildFiles() {
    // workbox-sw doesn't include .prod. in the build name.
    const buildGlob = path.join(
      __dirname,
      '..',
      '..',
      'packages',
      '*',
      constants.PACKAGE_BUILD_DIRNAME,
      '{*.prod.js,workbox-sw.js}',
    );
    return globSync(buildGlob);
  }

  analyzeFile(filePath) {
    const fileContents = fs.readFileSync(filePath).toString();

    const parsedCode = babylon.parse(fileContents);
    const tokens = parsedCode.tokens;
    const nameTokens = tokens.filter((token) => {
      return token.type.label === 'name';
    });

    const matches = {};

    nameTokens.forEach((token) => {
      const variableName = token.value;
      if (!matches[variableName]) {
        matches[variableName] = 0;
      }
      matches[variableName]++;
    });

    return Object.keys(matches).map((matchKey) => {
      return {
        propertyName: matchKey,
        propertyCount: matches[matchKey],
      };
    });
  }

  tidyData(analysisEntries) {
    return analysisEntries
      .filter((entry) => {
        // If there is only one entry or it's a single character it's
        // either not important or it's already been minified.
        return entry.propertyCount > 1 && entry.propertyName.length > 1;
      })
      .filter((entry) => {
        switch (entry.propertyName) {
          case 'await':
          case 'async':
            return false;
          default:
            return true;
        }
      })
      .sort((a, b) => {
        return b.propertyCount - a.propertyCount;
      });
  }

  printDetails({filePath, analysis}) {
    let longestPropertyName = 0;
    analysis.forEach((entry) => {
      if (entry.propertyName.length > longestPropertyName) {
        longestPropertyName = entry.propertyName.length;
      }
    });

    logHelper.log();
    logHelper.log(`Results for '${path.relative(process.cwd(), filePath)}'`);
    logHelper.log();

    analysis.forEach((entry) => {
      const numberOfSpaces = longestPropertyName - entry.propertyName.length;
      const extraSpace = ' '.repeat(numberOfSpaces);
      logHelper.log(
        `    ${entry.propertyName} ` + `${extraSpace} ${entry.propertyCount}`,
      );
    });
    logHelper.log();
  }
}

module.exports = AnalyseBuildForProperties;


================================================
FILE: gulp-tasks/utils/cdn-helper.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const {globSync} = require('glob');
const path = require('path');
const {Storage} = require('@google-cloud/storage');

const cdnDetails = require('../../cdn-details.json');
const logHelper = require('../../infra/utils/log-helper');

const PROJECT_ID = 'workbox-bab1f';

class CDNHelper {
  constructor() {
    this._gcs = null;
  }

  _getReleaseTagPath(tagName) {
    return `${cdnDetails.releasesDir}/${tagName}`;
  }

  async getGCS() {
    if (!this._gcs) {
      // Run `gcloud auth application-default login` if needed.
      // See https://stackoverflow.com/a/42059661/385997
      this._gcs = new Storage({
        projectId: PROJECT_ID,
      });
    }

    return this._gcs;
  }

  async tagExists(tagName) {
    const gcs = await this.getGCS();
    try {
      const bucket = gcs.bucket(cdnDetails.bucketName);
      // bucket.file('some/path/').exists() doesn't seem to work
      // for nested directories. Instead we are checking if there are
      // files in the expected release directory.
      const [files] = await bucket.getFiles({
        prefix: `${this._getReleaseTagPath(tagName)}/`,
      });
      return files.length > 0;
    } catch (err) {
      logHelper.error(err);
      throw err;
    }
  }

  async upload(tagName, directoryToUpload) {
    const gcs = await this.getGCS();

    const filePaths = globSync(`${directoryToUpload}/*`, {
      absolute: true,
    });

    const publicUrls = [];
    const bucket = gcs.bucket(cdnDetails.bucketName);

    for (const filePath of filePaths) {
      const destination = `${this._getReleaseTagPath(tagName)}/${path.basename(
        filePath,
      )}`;

      try {
        await bucket.upload(filePath, {
          destination,
          gzip: true,
          public: true,
          resumable: false,
          metadata: {
            cacheControl: 'public, max-age=31536000',
          },
        });
      } catch (err) {
        logHelper.error(`Failed to upload file to GCS bucket: '${filePath}'`);
        throw err;
      }
      publicUrls.push(
        `${cdnDetails.origin}/${cdnDetails.bucketName}/${destination}`,
      );
    }

    return publicUrls;
  }
}

module.exports = new CDNHelper();


================================================
FILE: gulp-tasks/utils/constants.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

module.exports = {
  // This is a directory that should not be commited
  // to git and will be removed and rebuilt between
  // test runs.
  PACKAGE_BUILD_DIRNAME: 'build',
  GENERATED_RELEASE_FILES_DIRNAME: 'generated-release-files',

  // This is used in the publish-bundle step to avoid doing anything
  // with tags that have known issues.
  MIN_RELEASE_TAG_TO_PUBLISH: 'v6.1.5',
  GITHUB_OWNER: 'GoogleChrome',
  GITHUB_REPO: 'workbox',

  // This is the environments that we should use for NODE_ENV.
  BUILD_TYPES: {
    dev: 'dev',
    prod: 'production',
  },
};


================================================
FILE: gulp-tasks/utils/get-packages.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const {globSync} = require('glob');
const path = require('path');

const DEFAULT_ROOT = path.join(__dirname, '..', '..');

const getPackages = ({type, root = DEFAULT_ROOT} = {}) => {
  const pathToPkgJsons = globSync('packages/*/package.json', {cwd: root});

  return pathToPkgJsons
    .map((pathToPkgJson) => {
      const pkg = require(`${path.resolve(root)}/${pathToPkgJson}`);
      return pkg;
    })
    .filter((pkg) => {
      return pkg.workbox && pkg.workbox.packageType === type;
    });
};

module.exports = {
  getPackages,
};


================================================
FILE: gulp-tasks/utils/github-helper.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const {Octokit} = require('@octokit/rest');
const semver = require('semver');

const constants = require('./constants');

// github.authenticate() is synchronous, and it only stores the credentials for
// the next request, so it should be called once per method that requires auth.
// See https://github.com/mikedeboer/node-github#authentication
const authenticate = () => {
  if (!process.env.GITHUB_TOKEN) {
    throw new Error(
      'You must set a GITHUB_TOKEN in your environment to ' +
        'publish a GitHub release.',
    );
  }

  return new Octokit({auth: process.env.GITHUB_TOKEN});
};

module.exports = {
  createRelease: (args) => {
    const github = authenticate();

    args.owner = constants.GITHUB_OWNER;
    args.repo = constants.GITHUB_REPO;
    return github.rest.repos.createRelease(args);
  },

  uploadAsset: (args) => {
    const github = authenticate();
    args.owner = constants.GITHUB_OWNER;
    args.repo = constants.GITHUB_REPO;
    return github.rest.repos.uploadReleaseAsset(args);
  },

  getTaggedReleases: async () => {
    const github = authenticate();
    const releasesData = await github.rest.repos.listReleases({
      owner: constants.GITHUB_OWNER,
      repo: constants.GITHUB_REPO,
    });

    const releases = releasesData.data;
    const releasesByTags = {};
    releases.forEach((release) => {
      const tagName = release.tag_name;
      if (semver.gte(tagName, constants.MIN_RELEASE_TAG_TO_PUBLISH)) {
        releasesByTags[tagName] = release;
      }
    });

    return releasesByTags;
  },

  getTags: async () => {
    const github = authenticate();
    const tagsResponse = await github.repos.listTags({
      owner: constants.GITHUB_OWNER,
      repo: constants.GITHUB_REPO,
    });

    const tagsData = tagsResponse.data;
    return tagsData.filter((tagData) => {
      return semver.gte(tagData.name, constants.MIN_RELEASE_TAG_TO_PUBLISH);
    });
  },
};


================================================
FILE: gulp-tasks/utils/node-projects-babel.config.json
================================================
{
  "presets": [["@babel/preset-env", {"targets": {"node": "10.0"}}]]
}


================================================
FILE: gulp-tasks/utils/output-filename-to-package-map.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const {getPackages} = require('./get-packages');

const outputFilenameToPkgMap = {};

const windowAndSWPackages = [
  ...getPackages({type: 'sw'}),
  ...getPackages({type: 'window'}),
];

windowAndSWPackages.forEach((pkg) => {
  // When no `outputFilename` property exists, the package name is used.
  const outputFilename = pkg.workbox.outputFilename || pkg.name;

  outputFilenameToPkgMap[outputFilename] = pkg;
});

module.exports = {
  outputFilenameToPkgMap,
};


================================================
FILE: gulp-tasks/utils/package-runner.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const path = require('path');
const {globSync} = require('glob');

const oneLine = require('common-tags').oneLine;

const pkgPathToName = require('./pkg-path-to-name');

/**
 * @param {string} typeFilter The type of packages to return: 'node', 'sw',
 * or 'all'.
 * @return Array<string> Paths to package.json files for the matching packages.
 */
function getPackages(typeFilter) {
  return globSync(`packages/${global.packageOrStar}/package.json`, {
    absolute: true,
  }).filter((pathToPackageJson) => {
    const pkgInfo = require(pathToPackageJson);
    const packageType = pkgInfo.workbox.packageType;
    if (!packageType) {
      throw Error(oneLine`Unable to determine package type. Please add
      workbox.packageType metadata to ${pathToPackageJson}`);
    }

    return typeFilter === 'all' || typeFilter === packageType;
  });
}

/*
 * This methods only purpose is to call a function with
 * the package path that needs to be acted upon.
 *
 * The specific function might vary depending on whether a give project targets
 * Node or the browser, so you can specify 'sw', 'node', or 'all'.
 *
 * If we ran gulp as `gulp build` we would want the
 * 'build' task to run against all packages.
 *
 * If we ran gulp as `gulp build --project workbox-core`
 * we would want the 'build' task to run against `workbox-core`
 * **only**.
 *
 * This method simplifies how we would write the 'build'
 * task and should be the only way we write functions.
 *
 * ```javascript
 * gulp.task('build',
 *   gulp.series(
 *     packageRunner(displayName, 'all', func, arg1, arg2)
 *   )
 * );
 * ```
 *
 * Package runner will return an array of functions that
 * will call `func` where the first argument
 * is the absolute path to a package,
 * like `/user/matt/workbox/packages/workbox-core` and
 * the remaining arguments will be whatever is passed to
 * packageRunner, in the above sample this would be
 * `arg1` and `arg2`.
 *
 * In the example above, `func` would be written as:
 *
 * ```javascript
 * function functionForEachProjectType(packagePath, arg1, arg2) {
 *   // Return a Promise
 *   return Promise.resolve().then(() => ...)
 *
 *   // OR
 *
 *   // Return a gulp stream
 *   return gulp.src(path.posix.join(packagePath, 'example-dir', '*.js'))
 *   .pipe(...)
 *   .pipe(gulp.dest(...));
 * }
 * ```
 *
 * You can use this with both `gulp.series` and
 * `gulp.parallel`.
 *
 * ```javascript
 * gulp.series(packageRunner(displayName, 'all', func))
 * gulp.parallel(packageRunner(displayName, 'all', func))
 * ```
 *
 * If you need to call the runner with multiple functions
 * you can do this and gulp will merge the arrays returned
 * by the runner.
 *
 * For example:
 *
 * ```javascript
 * gulp.parallel(
 *   packageRunner(displayName, 'sw', func, true),
 *   packageRunner(displayName, 'sw', func, false),
 * )
 * ```
 *
 * If we run the above, it would call the appropriate
 * `func` for all packages in workbox twice, once with
 * argument `true` and once with `false`. `gulp.parallel` will run all of these
 * calls to `func` in parallel.
 *
 * @param {string} displayName A friendly name to log.
 * @param Array<string> The type of package we want to run func against:
 * 'node', 'sw', or 'all'.
 * @param {function} func The function that we want to run for each package.
 * @param {*} args Any arguments that should be passed in to the func.
 * @return Array<function> All of the function wrappers.
 */
module.exports = (displayName, packageType, func, ...args) => {
  const packagePaths = getPackages(packageType);
  // We need to return a single no-op rather than an empty array, or else gulp
  // will throw 'One or more tasks should be combined using series or parallel'.
  if (packagePaths.length === 0) {
    const noOp = (done) => done();
    noOp.displayName = displayName;
    return [noOp];
  }
  return packagePaths.map((packagePath) => {
    const packageRootPath = path.dirname(packagePath);

    const wrappedFunc = () => func(packageRootPath, ...args);
    wrappedFunc.displayName = oneLine`
      ${displayName}
      (${pkgPathToName(packageRootPath)})
      ${args.length === 0 ? '' : JSON.stringify(args)}`;
    return wrappedFunc;
  });
};


================================================
FILE: gulp-tasks/utils/pkg-path-to-name.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const path = require('path');

const packagesPath = path.join(__dirname, '..', '..', 'packages');

// A helper method that should be used when you want to log
// the package name ONLY.
module.exports = (pkgPath) => {
  return path.relative(packagesPath, pkgPath);
};


================================================
FILE: gulp-tasks/utils/publish-helpers.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const execa = require('execa');
const fse = require('fs-extra');
const {globSync} = require('glob');
const ol = require('common-tags').oneLine;
const upath = require('upath');

const {outputFilenameToPkgMap} = require('./output-filename-to-package-map');
const constants = require('./constants');
const logHelper = require('../../infra/utils/log-helper');

const SOURCE_CODE_DIR = 'source-code';
const GROUPED_BUILD_FILES = 'grouped-build-files';

const doesDirectoryExist = async (directoryPath) => {
  let stats = null;
  try {
    stats = await fse.stat(directoryPath);
  } catch (err) {
    return false;
  }
  return stats.isDirectory();
};

const getBuildPath = (tagName) => {
  const tempReleasePath = upath.join(
    __dirname,
    '..',
    '..',
    constants.GENERATED_RELEASE_FILES_DIRNAME,
  );
  return upath.join(tempReleasePath, tagName);
};

const downloadGitCommit = async (tagName, gitBranch) => {
  if (!tagName) {
    throw new Error(`You must provide a tagName to 'downloadGitCommit()`);
  }

  if (!gitBranch) {
    throw new Error(`You must provide a gitBranch to 'downloadGitCommit()`);
  }

  const sourceCodePath = upath.join(getBuildPath(tagName), SOURCE_CODE_DIR);

  logHelper.log(`Download Git Commit ${logHelper.highlight(gitBranch)}.`);

  const dirExists = await doesDirectoryExist(sourceCodePath);
  if (!dirExists) {
    logHelper.log(`    Clone Git repo for branch: '${gitBranch}'.`);

    await execa('git', [
      'clone',
      '--branch',
      gitBranch,
      '--depth',
      '1',
      `http://github.com/${constants.GITHUB_OWNER}/${constants.GITHUB_REPO}.git`,
      sourceCodePath,
    ]);
  } else {
    logHelper.log(`   Git repo for branch '${gitBranch}' is cloned already.`);
  }

  return sourceCodePath;
};

const buildGitCommit = async (tagName) => {
  const sourceCodePath = upath.join(getBuildPath(tagName), SOURCE_CODE_DIR);

  logHelper.log(ol`
    Building Commit
    ${logHelper.highlight(upath.relative(process.cwd(), sourceCodePath))}.
  `);

  await execa('npm', ['install'], {cwd: sourceCodePath});

  await execa('gulp', ['build'], {cwd: sourceCodePath});

  // This is to try and fix GitHub and CDN steps from having file read / close
  // issues by removing any risk of spawn tasks being out of sync
  await new Promise((resolve) => setTimeout(resolve, 1000));
};

/*
 * This function will create a directory with the same name as the
 * .tar.gz file it generates. This way when the file is extracted
 * the folder structure will be the same.
 */
const groupBuildFiles = async (tagName, gitBranch) => {
  const groupedBuildFiles = upath.join(
    getBuildPath(tagName),
    GROUPED_BUILD_FILES,
  );
  const dirExists = await doesDirectoryExist(groupedBuildFiles);

  if (!dirExists) {
    await downloadGitCommit(tagName, gitBranch);
    await buildGitCommit(tagName);

    const sourceCodePath = upath.join(getBuildPath(tagName), SOURCE_CODE_DIR);

    const browserPackages = Object.values(outputFilenameToPkgMap).map(
      (item) => item.name,
    );

    const pattern = upath.join(
      sourceCodePath,
      'packages',
      `{${browserPackages.join(',')}}`,
      constants.PACKAGE_BUILD_DIRNAME,
      '*.{js,mjs,map}',
    );

    logHelper.log(ol`
      Grouping Build Files into
      ${logHelper.highlight(upath.relative(process.cwd(), groupedBuildFiles))}.
    `);

    // Copy files from the source code and move into the grouped build
    // directory. In others, have a flat file structure of just the built files.
    const filesToInclude = globSync(pattern);
    for (const fileToInclude of filesToInclude) {
      await fse.copy(
        fileToInclude,
        upath.join(groupedBuildFiles, upath.basename(fileToInclude)),
      );
    }
  } else {
    logHelper.log(`   Build files already grouped.`);
  }

  return groupedBuildFiles;
};

module.exports = {
  groupBuildFiles,
};


================================================
FILE: gulp-tasks/utils/rollup-helper.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const {babel} = require('@rollup/plugin-babel');
const {nodeResolve} = require('@rollup/plugin-node-resolve');
const asyncToPromises = require('babel-plugin-transform-async-to-promises');
const replace = require('@rollup/plugin-replace');
const terserPlugin = require('@rollup/plugin-terser');

const constants = require('./constants');
const getVersionsCDNUrl = require('./versioned-cdn-url');

// See https://github.com/GoogleChrome/workbox/issues/1674
const nameCache = {};

module.exports = {
  // Every use of rollup should have minification and the replace
  // plugin set up and used to ensure as consist set of tests
  // as possible.
  getDefaultPlugins: (buildType, buildFormat = 'iife', es5 = false) => {
    const plugins = [nodeResolve()];

    const babelConfig = {
      babelHelpers: 'bundled',
      presets: [
        [
          '@babel/preset-env',
          {
            loose: true,
            targets: {
              browsers: es5
                ? // If es5 is true, target IE11
                  // https://github.com/browserslist/browserslist#queries
                  ['ie 11']
                : // This corresponds to the version of Chromium used by
                  // Samsung Internet 6.x, which is the minimum non-evergreen
                  // browser we currently support.
                  ['chrome >= 56'],
            },
          },
        ],
      ],
    };
    if (es5) {
      babelConfig.plugins = [asyncToPromises];
    }
    plugins.push(babel(babelConfig));

    const minifyBuild = buildType === constants.BUILD_TYPES.prod;
    if (minifyBuild) {
      const terserOptions = {
        nameCache,
        module: buildFormat === 'esm' ? true : false,
        mangle: {
          properties: {
            reserved: [
              // Chai will break unless we reserve this private variable.
              '_obj',
              // We need this to be exported correctly.
              '_private',
              // See https://github.com/GoogleChrome/workbox/issues/2686
              '_handle',
            ],
            // mangle > properties > regex will allow terser to minify
            // private variable and names that start with a single underscore
            // followed by a letter. This restriction to avoid mangling
            // unintentional fields in our or other libraries code.
            regex: /^_[A-Za-z]/,
            // If you are getting an error due to a property mangle
            // set this flag to true and the property will be changed
            // from '_foo' to '$_foo$' to help diagnose the problem.
            debug: false,
          },
        },
      };
      plugins.push(terserPlugin(terserOptions));
    }

    // This is what the build should be
    const replaceOptions = {
      preventAssignment: true,
      WORKBOX_CDN_ROOT_URL: getVersionsCDNUrl(),
    };

    if (buildType) {
      replaceOptions['process.env.NODE_ENV'] = JSON.stringify(buildType);
    }

    // Replace allows us to input NODE_ENV and strip code accordingly
    plugins.push(replace(replaceOptions));

    return plugins;
  },
};


================================================
FILE: gulp-tasks/utils/version-module.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const fs = require('fs-extra');
const path = require('path');

const pkgPathToName = require('./pkg-path-to-name');

const getDetails = (packagePath) => {
  // Read file from filesystem to avoid require caching
  const packageJsonPath = path.join(packagePath, 'package.json');
  const pkgJson = fs.readJSONSync(packageJsonPath);
  const name = pkgPathToName(packagePath).replace('workbox-', '');
  return ['workbox', name, pkgJson.version].join(':');
};

module.exports = async (packagePath) => {
  const versionString = `try{self['${getDetails(
    packagePath,
  )}']&&_()}catch(e){}`;

  if (await fs.pathExists(path.join(packagePath, 'src', 'index.ts'))) {
    const tsVersionString = `// @ts-ignore\n${versionString}`;
    await fs.writeFile(
      path.join(packagePath, 'src', '_version.ts'),
      tsVersionString,
    );
  }

  const mjsVersionString = `${versionString}// eslint-disable-line`;
  return fs.writeFile(path.join(packagePath, '_version.mjs'), mjsVersionString);
};


================================================
FILE: gulp-tasks/utils/versioned-cdn-url.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const cdn = require('../../packages/workbox-build/src/cdn-details.json');
const lernaPkg = require('../../lerna.json');

module.exports = () =>
  `${cdn.origin}/${cdn.bucketName}/${cdn.releasesDir}` + `/${lernaPkg.version}`;


================================================
FILE: gulpfile.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const fse = require('fs-extra');
const globby = require('globby');
const minimist = require('minimist');
const upath = require('upath');

const options = minimist(process.argv.slice(2));

if (options.package) {
  // Ensure the package is valid before running tasks
  try {
    fse.statSync(upath.join(__dirname, 'packages', options.package));
  } catch (err) {
    throw new Error(`The supplied package '${options.package}' is invalid.`);
  }
}

global.port = options.port || 3000;
global.packageOrStar = options.package || '*';
global.cliOptions = options;

const taskFiles = globby.sync('./gulp-tasks/*.js');

for (const taskFile of taskFiles) {
  const taskDefinitions = require(taskFile);
  for (const [name, task] of Object.entries(taskDefinitions)) {
    if (name === 'functions') {
      continue;
    }
    if (name in module.exports) {
      throw new Error(
        `Duplicate task definition: ${name} defined in` +
          ` ${taskFile} conflicts with another task.`,
      );
    }
    module.exports[name] = task;
  }
}


================================================
FILE: infra/pr-bot/aggregate-size-plugin.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const {oneLine} = require('common-tags');
const {PluginInterface} = require('pr-bot');
const bytes = require('bytes');
const fs = require('fs-extra');
const gzipSize = require('gzip-size');
const path = require('path');

// 15kb max size, gzip'ed.
const MAX_SIZE_GZIP = 15 * 1024;

class AggregateSizePlugin extends PluginInterface {
  constructor() {
    super(`Workbox Aggregate Size Plugin`);
  }

  async run({afterPath} = {}) {
    const packagesToAggregate = [
      `workbox-cacheable-response`,
      `workbox-core`,
      `workbox-expiration`,
      `workbox-precaching`,
      `workbox-routing`,
      `workbox-strategies`,
      `workbox-sw`,
    ];

    const absoluteAfterPath = path.resolve(afterPath);
    const files = packagesToAggregate.map((pkgName) => {
      const prefix = `${absoluteAfterPath}/packages/${pkgName}/`;
      const pkgJson = require(`${prefix}package.json`);
      const posixPath = prefix + pkgJson.main;
      return posixPath.split('/').join(path.sep);
    });

    let totalSize = 0;
    let totalGzipSize = 0;

    for (const filePath of files) {
      const fileContents = await fs.readFile(filePath);
      const stat = await fs.stat(filePath);
      totalSize += stat.size;
      totalGzipSize += await gzipSize(fileContents);
    }

    const percentValue = (totalGzipSize / MAX_SIZE_GZIP) * 100;
    const percentString = parseFloat(percentValue).toFixed(0);

    const totalSizeString = bytes(totalSize);
    const totalGzipString = bytes(totalGzipSize);

    let markdownWarning = ``;
    if (percentValue >= 90) {
      const markdownMoji = percentValue >= 95 ? '☠️' : '⚠️';
      markdownWarning = oneLine`
      <h3 align="center">${markdownMoji} WARNING ${markdownMoji}</h3>
      <p align="center">
        We are using <strong>${percentString}%</strong>
        of our max budget for gzip'ed bundle size.
      </p>`;
    }

    const failPR = Boolean(percentValue > 100);

    const prettyLog =
      `**${totalGzipString}** gzip'ed ` +
      `(**${percentString}%** of limit)\n` +
      `**${totalSizeString}** uncompressed`;

    const markdownLog = `${markdownWarning}\n\n${prettyLog}`;

    return {
      failPR, // Fail the PR if we have exceeded the limit.
      markdownLog,
      prettyLog,
    };
  }
}

module.exports = AggregateSizePlugin;


================================================
FILE: infra/templates/reference-docs/jsdoc/lang/en.yaml
================================================
# @license
# Copyright 2018 Google LLC
#
# Use of this source code is governed by an MIT-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/MIT.

constructor:
  prefix: 'new '
returnTypesSeparator: '&nbsp;returns&nbsp;'
tables:
  body:
    defaultValue: 'Defaults to {valueString}.'
    defaultValueString: '<code>{value}</code>'
    eachValueHasProperties: 'Values in <code>{name}</code> have the following properties:'
    isOptional: 'Optional'
    isRequired: '&nbsp;'
    nonNullable:
      long: 'Value must not be null.'
      short: 'non-null'
    nullable:
      long: 'Value may be null.'
      short: 'nullable'
    repeatable:
      long: 'Value may be repeated.'
      short: 'repeatable'
    unknownType: '?'
  emptyCellPlaceholder: '&nbsp;'
  header:
    description: 'Description'
    name: 'Name'
    optional: 'Optional'
    type: 'Type'
  notApplicable: '&#8212;'
params:
  all: '({params})'
  joiner: |
    {items, plural,
        =0 {{param}}
        other {, {param}}}
  optional: '{param}'
  repeatable: '...{param}'
headings:
  enums: |
    {items, plural,
        =1 {Enumeration}
        other {Enumerations}}
  values: |
    {items, plural,
        =1 {Value}
        other {Values}}


================================================
FILE: infra/templates/reference-docs/jsdoc/lib/publishjob.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

/* eslint-env node */
/* eslint-disable valid-jsdoc, require-jsdoc */

const name = require('jsdoc/name');
const BaselinePublishJob = require('jsdoc-baseline/lib/publishjob');

class PublishJob extends BaselinePublishJob {
  constructor(...args) {
    super(...args);
    this._symbolNames = {};
    this._data;
  }

  generateTocYaml(symbols, basepath) {
    symbols.sort(function (a, b) {
      let aName = a.kind === 'namespace' ? a.longname : a.name;
      let bName = b.kind === 'namespace' ? b.longname : b.name;

      aName = aName.toLowerCase();
      bName = bName.toLowerCase();

      if (aName > bName) {
        return 1;
      }

      if (aName < bName) {
        return -1;
      }

      return 0;
    });

    // check for duplicated names
    symbols.forEach((symbol) => {
      const symbolName =
        symbol.kind === 'namespace' ? symbol.longname : symbol.name;
      if ({}.hasOwnProperty.call(this._symbolNames, symbolName)) {
        this._symbolNames[symbolName] = true;
      } else {
        this._symbolNames[symbolName] = false;
      }
    });

    // To disambiguate duplicated names, prepend the name and scope of the
    // parent. For example, if you have foo.bar.Qux and foo.baz.Qux, the
    // disambiguated names are bar.Quxand baz.Qux.
    symbols.forEach((symbol) => {
      let mappedName = null;
      const symbolName =
        symbol.kind === 'namespace' ? symbol.longname : symbol.name;

      if (this._symbolNames[symbolName] === true) {
        if (symbol.kind !== 'namespace') {
          // get info for the parent's name
          const atomized = name.shorten(symbol.longname);
          const atomizedParent = name.shorten(atomized.memberof);
          // prepend the parent's name and the symbol's scope to the name
          mappedName = atomizedParent.name + atomized.scope + symbol.name;
        } else {
          mappedName = symbol.longname;
        }
      }

      symbol.tocYamlName =
        mappedName ||
        (symbol.kind === 'namespace' ? symbol.longname : symbol.name);
    });

    const data = {
      symbols,
      basepath,
    };

    this.generate('toc-yaml', data, '_toc.yaml');
  }

  generateIndex(readme) {
    const data = {
      allLongnamesTree: this.allLongnamesTree,
      package: this.package,
      pageTitle: global.env.opts.query ? global.env.opts.query.productName : '',
      readme: readme || null,
    };

    this.generate('index', data, this.indexUrl);

    return this;
  }

  generateIndexAll(longnames) {
    longnames.sort();
    const data = {
      longnames: longnames,
      pageTitle: global.env.opts.query ? global.env.opts.query.productName : '',
    };

    this.generate('index-all', data, 'index-all.html');
  }
}

/** const PublishJob = module.exports = function(...args) {
  Parent.apply(this, [].slice.call(args, 0));
};
util.inherits(PublishJob, Parent);**/

module.exports = PublishJob;


================================================
FILE: infra/templates/reference-docs/jsdoc/publish.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

/* eslint-env node */

const baselineConfig = require('jsdoc-baseline/lib/config');
const fileFinder = require('jsdoc-baseline/lib/filefinder');
const helper = require('jsdoc/util/templateHelper');
const path = require('jsdoc/path');

exports.publish = function (data, opts, tutorials) {
  baselineConfig.loadSync();
  baselineConfig
    .set('l10n', path.join(__dirname, 'lang'))
    .set('static', path.join(__dirname, 'static'))
    .set('views.partials', path.join(__dirname, 'views'))
    .set('views.layouts', path.join(__dirname, 'views'))
    .set('modules', path.join(__dirname, 'lib'));

  const config = baselineConfig.get();

  // load the core modules using the file finder
  const modulesFinder = fileFinder.get('modules', config.modules);

  const DocletHelper = modulesFinder.require('./doclethelper');
  const PublishJob = modulesFinder.require('./publishjob');
  const Template = modulesFinder.require('./template');

  const docletHelper = new DocletHelper();
  const template = new Template(config);
  const job = new PublishJob(template, opts);

  // set up tutorials
  helper.setTutorials(tutorials);

  docletHelper.addDoclets(data);

  job
    .setPackage(docletHelper.getPackage())
    .setNavTree(docletHelper.navTree)
    .setAllLongnamesTree(docletHelper.allLongnamesTree);

  // create the output directory so we can start generating files
  job
    .createOutputDirectory()
    // then generate the source files so we can link to them
    .generateSourceFiles(docletHelper.shortPaths);

  // generate globals page if necessary
  job.generateGlobals(docletHelper.globals);

  // generate TOC data and index page
  job
    .generateTocData({hasGlobals: docletHelper.hasGlobals()})
    .generateIndex(opts.readme);

  // generate the rest of the output files (excluding tutorials)
  docletHelper.getOutputLongnames().forEach(function (longname) {
    job.generateByLongname(
      longname,
      docletHelper.getLongname(longname),
      docletHelper.getMemberof(longname),
    );
  });

  // finally, generate the tutorials, and copy static files to the output
  // directory
  job.generateTutorials(tutorials).copyStaticFiles();

  // custom Cast pages
  job.generateTocYaml(
    docletHelper
      .getCategory('classes')
      .concat(docletHelper.getCategory('namespaces'))
      .concat(docletHelper.getCategory('interfaces')),
    global.env.opts.query ? global.env.opts.query.basepath : '',
  );
  job.generateIndexAll(Object.keys(docletHelper.longname));
};


================================================
FILE: infra/templates/reference-docs/jsdoc/static/jsdoc.css
================================================
.label {
  font-style: italic;
  text-transform: uppercase;
}

.dl-compact dt {
  margin: 8px 0px 0px 0px;
}

h1.devsite-page-title {
  display: none;
}

h1 {
  margin-bottom: 8px;
}

h2 {
  margin: 48px 0px 0px 0px;
}

h3.symbol-name {
  margin: 32px 0px 8px 0px;
}

h3.class-list:first-child {
  display: block;
  margin: 16px 0px 0px 0px;
}

h3.class-list {
  display: block;
  margin: 12px 0px 0px 0px;
  font-size: 16px;
}

h3.class-list + p {
  margin: 0px 0px 0px 0px;
}

h4 {
  margin: 8px 0px 0px 0px;
}

td p {
  margin: 6px 0px 0px 0px;
}

p.type-signature {
  font-family: 'Roboto Mono', monospace;
  font-size: 80%;
  font-style: normal;
  font-variant: normal;
  font-weight: 500;
  font-stretch: normal;
  line-height: normal;
  margin-top: 0px;
}

p.symbol-index-name {
  margin: 8px 0px 0px 0px;
}

h2.symbol-header {
  margin: 36px 0px 0px 0px;
}

table.function.param tr {
  background: #80a7b9;
}


================================================
FILE: infra/templates/reference-docs/jsdoc/views/augments.hbs
================================================
{{#any augments}}
  <dt>{{translateHeading 'augments' augments}}</dt>
  {{#each augments}}
    <dd><small>{{link this}}</small></dd>
  {{/each}}
{{/any}}


================================================
FILE: infra/templates/reference-docs/jsdoc/views/classes-links.hbs
================================================
{{#any items}}
<h>{{translateHeading headingKey items}}</h>
  <section id='members-links'>
  {{#each items}}
    <h3 {{~cssClass '!class-list'}}>{{link longname name}}</h3>
    {{#if classdesc}}
      {{#markdown}}{{resolveLinks classdesc}}{{/markdown}}
    {{else}}
      {{#markdown}}{{resolveLinks description}}{{/markdown}}
    {{/if}}
  {{/each}}
  </section>
{{/any}}


================================================
FILE: infra/templates/reference-docs/jsdoc/views/details-table-row.hbs
================================================
<tr>
  {{#block 'details-table-name'}}
    <td {{~cssClass '!details-table-name'}}>
      <p>{{#if name}}{{name}}{{else}}{{translate 'tables.notApplicable'}}{{/if}}</p>
    </td>
  {{/block}}
  <td>
  {{#block 'details-table-optional'}}
    {{#if optional}}
      <p {{~cssClass '!details-table-optional'}}>{{translate 'tables.body.isOptional'}}</p>
    {{/if}}
  {{/block}}
  {{#block 'details-table-types'}}
    {{#if type}}
      {{#all type type.parsedType}}
        <p {{~cssClass '!details-table-types'}}>{{describeType type.parsedType 'extended'}}</p>
      {{/all}}
    {{/if}}
  {{/block}}
  {{#block 'details-table-description'}}
    {{#if description}}
      {{#markdown}}{{resolveLinks description}}{{/markdown}}
    {{/if}}
    {{#if (hasModifiers this)}}
      <p>{{modifierText this}}</p>
    {{/if}}
    {{#if ../children}}
      <p>{{translate 'tables.body.eachValueHasProperties' name=name}}</p>
        {{#withOnly values=../children}}
          {{#embed 'details-table'}}{{/embed}}
        {{/withOnly}}
    {{/if}}
  {{/block}}
  </td>
</tr>

{{!-- This produces extra <p>'s in the output
<p {{~cssClass '!details-table-description'}}>
  {{#markdown}}{{resolveLinks description}}{{/markdown}}</p>
--}}


================================================
FILE: infra/templates/reference-docs/jsdoc/views/details-table.hbs
================================================
<table class="function param responsive">
  {{#block 'details-table-header'}}
    <tr>
      <th colspan="2">
        {{#if isEnum}}
          <h>{{translateHeading 'values' params}}</h>
        {{else}}
          <h>{{translateHeading 'parameters' params}}</h>
        {{/if}}
      </th>
    </tr>
  {{/block}}
  {{#block 'details-table-body'}}
    <tbody>
      {{#each values}}
        {{#embed 'details-table-row'}}{{/embed}}
      {{/each}}
    </tbody>
  {{/block}}
</table>


================================================
FILE: infra/templates/reference-docs/jsdoc/views/implements.hbs
================================================
{{#any implements}}
  <dt>{{translateHeading 'implements' implements}}</dt>
  {{#each implements}}
    <dd><small>{{link this}}</small></dd>
  {{/each}}
{{/any}}


================================================
FILE: infra/templates/reference-docs/jsdoc/views/index-all.hbs
================================================
{{#extend 'layout'}}
  {{#content 'title'}}
    <title>Index All</title>
  {{/content}}
  {{#content 'body-main-content'}}
    <ul>
      {{#each longnames}}
        <li>{{link this}}</li>
      {{/each}}
    </ul>
  {{/content}}
{{/extend}}


================================================
FILE: infra/templates/reference-docs/jsdoc/views/index.hbs
================================================
{{#extend 'layout'}}
  {{#content 'title'}}
    <title>Overview</title>
  {{/content}}
  {{#content 'body-main-content'}}
    {{#if readme}}
      {{{ readme }}}
    {{else}}
      {{#block 'body-symbol-index'}}
        {{#embed 'symbol-index'}}{{/embed}}
      {{/block}}
    {{/if}}
  {{/content}}
{{/extend}}


================================================
FILE: infra/templates/reference-docs/jsdoc/views/layout.hbs
================================================
<!DOCTYPE html>
<html devsite>
    {{#block 'head'}}
        <head>
            {{#block 'meta'}}
                <meta name="project_path" value="{{query 'projectRoot'}}_project.yaml" />
                <meta name="book_path" value="{{query 'projectRoot'}}_book.yaml" />
                <meta name="gtm_var" data-key="docType" data-value="reference">
            {{/block}}
            {{#block 'title'}}
                <title>{{translatePageTitle pageTitlePrefix pageTitle pageCategory}}</title>
            {{/block}}
            {{#block 'css'}}
                <link href="jsdoc.css" rel="stylesheet">
            {{/block}}
        </head>
    {{/block}}
    {{#block 'body'}}
        <body>
            {{#block 'body-container'}}
                <div id="jsdoc-body-container">
                    {{#block 'body-content'}}
                        <div id="jsdoc-content">
                            {{#block 'body-content-container'}}
                                <div id="jsdoc-content-container">
                                    {{#block 'body-banner'}}
                                        <div id="jsdoc-banner" role="banner">
                                            {{#block 'body-banner-content'}}
                                                {{!--
                                                    Override the `body-banner-content` block
                                                    to add content.
                                                --}}
                                            {{/block}}
                                        </div>
                                    {{/block}}
                                    {{#block 'body-main'}}
                                        {{!-- Adding a section here causes heading to bump down H1 > H2, etc. --}}
                                        <div id="jsdoc-main" role="main">
                                            {{#block 'body-main-content'}}
                                                {{!--
                                                    Override the `body-main-content` block
                                                    to add content.
                                                --}}
                                            {{/block}}
                                        </div>
                                    {{/block}}
                                </div>
                            {{/block}}
                            {{#block 'body-toc-navbar'}}
                                {{!-- content is inserted on page load --}}
                                <nav id="jsdoc-toc-nav" role="navigation"></nav>
                            {{/block}}
                        </div>
                    {{/block}}
                </div>
            {{/block}}
            {{#block 'body-footer'}}
            {{/block}}
            {{!-- No scripts in Devsite --}}
        </body>
    {{/block}}
</html>


================================================
FILE: infra/templates/reference-docs/jsdoc/views/params.hbs
================================================
{{#any params}}
    <section>
        {{#withOnly values=(reparentItems this 'params')}}
            {{#embed 'details-table'}}{{/embed}}
        {{/withOnly}}
    </section>
{{/any}}


================================================
FILE: infra/templates/reference-docs/jsdoc/views/properties.hbs
================================================
{{#any (filterProperties properties)}}
  <section>
    {{#unless isEnum}}
      <h>{{translateHeading 'properties' properties}}</h>
    {{/unless}}
    {{#withOnly values=(reparentItems this 'properties') isEnum=isEnum}}
      {{#embed 'details-table'}}{{/embed}}
    {{/withOnly}}
  </section>
{{/any}}


================================================
FILE: infra/templates/reference-docs/jsdoc/views/see.hbs
================================================
{{#any see}}
    <dt>{{translateHeading 'see' see}}</dt>
    {{#each see}}
        <dd><small>{{link (see this ../longname)}}</small></dd>
    {{/each}}
{{/any}}


================================================
FILE: infra/templates/reference-docs/jsdoc/views/signature.hbs
================================================
{{!--
    Note that this section omits the return type for:
    + Constructors
    + Methods with no explicit return type
--}}
{{#with symbol}}
  {{~#if (needsSignature this)~}}
    {{!-- CONSTRUCTOR PREFIX --}}
    {{#is kind 'class'}}
      {{#embed 'constructor-prefix'}}{{/embed}}
    {{/is}}
    {{name}}{{~formatParams params~}}
    {{~#isnt kind 'class'~}}
      {{~#if (returnTypes this)~}}
        {{~translate 'returnTypesSeparator'~}}
        {{describeType (returnTypes this)~}}
      {{~/if~}}
    {{~/isnt~}}
  {{~else~}}
    {{~#if type~}}
      {{~describeType type.parsedType~}}
    {{~/if~}}
  {{~/if~}}
{{/with}}


================================================
FILE: infra/templates/reference-docs/jsdoc/views/symbol-content.hbs
================================================
<section>
  {{#block 'symbol-content-classes'}}
    {{#withOnly items=members.classes headingKey='classes'}}
      {{#embed 'classes-links'}}{{/embed}}
    {{/withOnly}}
  {{/block}}

  {{#block 'symbol-content-interfaces'}}
    {{#withOnly items=members.interfaces headingKey='interfaces'}}
      {{#embed 'members-links'}}{{/embed}}
    {{/withOnly}}
  {{/block}}

  {{#block 'symbol-content-namespaces'}}
    {{#withOnly items=members.namespaces headingKey='namespaces'}}
      {{#embed 'members-links'}}{{/embed}}
    {{/withOnly}}
  {{/block}}

  {{#block 'symbol-content-enums'}}
    {{#withOnly items=(where members.properties isEnum=true) headingKey='enums'}}
      {{#embed 'members-details'}}{{/embed}}
    {{/withOnly}}
  {{/block}}

  {{#block 'symbol-content-properties'}}
    {{#withOnly items=(where members.properties isEnum=undefined) headingKey='properties'}}
      {{#embed 'members-details'}}{{/embed}}
    {{/withOnly}}
  {{/block}}

  {{#block 'symbol-content-methods'}}
    {{#withOnly items=members.functions headingKey='functions'}}
      {{#embed 'members-details'}}{{/embed}}
    {{/withOnly}}
  {{/block}}

  {{#block 'symbol-content-typedefs'}}
    {{#withOnly items=members.typedefs headingKey='typedefs'}}
      {{#embed 'members-details'}}{{/embed}}
    {{/withOnly}}
  {{/block}}

  {{#block 'symbol-content-events'}}
    {{#withOnly items=members.events headingKey='events'}}
      {{#embed 'members-details'}}{{/embed}}
    {{/withOnly}}
  {{/block}}
</section>

================================================
FILE: infra/templates/reference-docs/jsdoc/views/symbol-detail.hbs
================================================
{{~#unless symbol.hideconstructor~}}
  <h id="{{id symbol}}" {{~cssClass '!symbol-name'}}>
    {{~#with symbol~}}
      {{name}}
    {{~/with~}}
  </h>
{{~/unless~}}
{{!--
    Note that we omit the labels for classes, modules, and namespaces, since
    these labels would duplicate the labels for the page's main heading.
--}}
{{~#if symbol.kind~}}
  {{~#contains 'class' 'module' 'namespace' value=symbol.kind~}}
  {{~else~}}
    {{~#embed 'symbol-labels'}}{{/embed~}}
  {{~/contains~}}
{{~/if~}}
{{~#unless symbol.hideconstructor~}}
  <p {{~cssClass '!type-signature'}}>
    {{~#embed 'signature'}}{{/embed~}}
  </p>
{{~/unless~}}
{{#with symbol}}
  {{~#unless symbol.hideconstructor~}}
    {{#embed 'description'}}{{/embed}}
    {{#embed 'params'}}{{/embed}}
    {{#embed 'properties'}}{{/embed}}
    <dl {{~cssClass '!dl-compact'}}>
      {{#embed 'details'}}{{/embed}}
    </dl>
    {{#embed 'examples'}}{{/embed}}
  {{~/unless~}}
{{/with}}


================================================
FILE: infra/templates/reference-docs/jsdoc/views/symbol-header.hbs
================================================
<header {{~cssClass '!page-header'}}>
  {{#block 'symbol-header-heading'}}
      <h>
        {{~#isnt longname memberof}}<small>{{ancestors longname}}</small>{{/isnt~}}
        <span {{~cssClass '!symbol-name'}}>{{name}}</span></h>
  {{~/block}}
  {{~#withOnly symbol=this~}}
    {{~#embed 'symbol-labels'}}{{/embed~}}
  {{/withOnly~}}
  {{#block 'symbol-header-classdesc'}}
    {{#if classdesc}}
      {{#markdown}}{{resolveLinks classdesc}}{{/markdown}}
    {{/if}}
  {{/block}}
  {{#block 'symbol-header-description'}}
    {{!--
      We don't put a description here for classes, or for namespaces that are
      also functions.
    --}}
    {{#isnt kind 'class'}}
      {{#is kind 'namespace'}}
        {{#unless (needsSignature this)}}
          {{#embed 'description'}}{{/embed}}
        {{/unless}}
      {{else}}
        {{#embed 'description'}}{{/embed}}
      {{/is}}
    {{/isnt}}
  {{/block}}
  {{#block 'symbol-header-class-details'}}
    {{!--
      For classes where we're not displaying the constructor, we show the
      details here.
    --}}
    {{#if hideconstructor}}
      <dl {{~cssClass '!dl-compact'}}>
        {{#embed 'details'}}{{/embed}}
      </dl>
    {{/if}}
  {{/block}}
</header>


================================================
FILE: infra/templates/reference-docs/jsdoc/views/symbol-index-section.hbs
================================================
<div {{~cssClass '!symbol-index-column'}}>
  {{#each doclets}}
    <p {{~cssClass '!symbol-index-name'}}>
      {{linkLongnameWithSignature this '!symbol-index-name'}}
    </p>
  {{/each}}
</div>


================================================
FILE: infra/templates/reference-docs/jsdoc/views/symbol-index.hbs
================================================
<div {{~cssClass '!symbol-index'}}>
  {{#eachIndexGroup allLongnamesTree}}
    <section>
      <div {{~cssClass '!symbol-index-content'}}>
        <h id="{{@groupName}}" {{~cssClass '!symbol-header'}}>{{@groupName}}</h>
        <div {{~cssClass '!symbol-index-section'}}>
          {{#each (group this 3)}}
            {{#withOnly doclets=this}}
              {{#embed 'symbol-index-section'}}{{/embed}}
            {{/withOnly}}
          {{/each}}
        </div>
      </div>
    </section>
  {{/eachIndexGroup}}
</div>


================================================
FILE: infra/templates/reference-docs/jsdoc/views/symbol-labels.hbs
================================================
{{~#withOnly allLabels=(labels symbol)~}}
  {{~#any allLabels~}}
    <div {{~cssClass '!symbol-detail-labels'}}>
      {{~#each allLabels~}}
        <span {{~cssClass '!label' class}}><small>{{text}}</small></span>
        {{~#unless @last}}&nbsp;&nbsp;&nbsp;{{/unless~}}
      {{~/each~}}
    </div>
  {{~/any~}}
{{~/withOnly~}}


================================================
FILE: infra/templates/reference-docs/jsdoc/views/symbol-overview.hbs
================================================
{{#any docs}}
  {{#first docs}}
    {{#embed 'symbol-header'}}{{/embed}}
  {{/first}}
{{/any}}

{{#each docs}}
  {{#if @first}}
    {{!-- heading that indicates what we're about to list --}}
    {{#is pageCategory 'classes'}}
      <section>
    {{else}}
      {{#any exports}}
        <section>
          <h>{{translateHeading 'exports' docs}}</h>
      {{/any}}
    {{/is}}
  {{/if}}

  {{!--
      If a module exports only one symbol, document the symbol in the overview, since it's not a
      member of anything else.
  --}}
  {{#is kind 'module'}}
    {{#if exports}}
      {{#each exports}}
        {{#withOnly symbol=this}}
          <section>
            {{#embed 'symbol-detail'}}{{/embed}}
          </section>
        {{/withOnly}}
      {{/each}}
    {{/if}}
  {{!-- Classes also need additional information in the overview. --}}
  {{else is kind 'class'}}
    {{#unless hideconstructor}}
      <section>
        <h>Constructor</h>
        <section>
          {{#withOnly symbol=this}}
            {{#embed 'symbol-detail'}}{{/embed}}
          {{/withOnly}}
        </section>
      </section>
    {{/unless}}
  {{!-- Externals also need additional information in the overview. --}}
  {{else is kind 'external'}}
    <section>
      {{#with this}}
        <dl {{~cssClass '!dl-compact'}}>
          {{#embed 'details'}}{{/embed}}
        </dl>
      {{/with}}
    </section>
  {{!-- Namespaces that are functions also need additional information in the overview. --}}
  {{else is kind 'namespace'}}
    {{#if (needsSignature this)}}
      <section>
        {{#withOnly symbol=this}}
          {{#embed 'symbol-detail'}}{{/embed}}
        {{/withOnly}}
      </section>
    {{/if}}
  {{/is}}

  {{#if @last}}
    {{#is pageCategory 'classes'}}
      </section>
    {{else}}
      {{#any exports}}
        </section>
      {{/any}}
    {{/is}}
  {{/if}}
{{/each}}

================================================
FILE: infra/templates/reference-docs/jsdoc/views/toc-yaml.hbs
================================================
toc:
{{#each symbols~}}
- title: "{{tocYamlName}}"
  path: {{../basepath}}/{{basename (url longname) '.html'}}
{{/each}}
- title: "Index of all"
  path: {{basepath}}/index-all


================================================
FILE: infra/testing/activate-and-control.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

const activateSWSafari = require('./activate-sw-safari');

// TODO(philipwalton): remove this in favor of using workbox-window.
module.exports = async (swURL) => {
  if (global.__workbox.seleniumBrowser.getId() === 'safari') {
    return activateSWSafari(swURL);
  }

  const error = await global.__workbox.webdriver.executeAsyncScript(
    (swURL, cb) => {
      function _onStateChangePromise(registration, desiredState) {
        return new Promise((resolve, reject) => {
          if (desiredState === 'activated' && registration.active) {
            resolve();
            return;
          }

          if (registration.installing === null) {
            reject(new Error('No installing service worker found.'));
            return;
          }

          const serviceWorker = registration.installing;

          // We unregister all service workers after each test - this should
          // always trigger an install state change
          const stateChangeListener = (event) => {
            if (event.target.state === desiredState) {
              serviceWorker.removeEventListener(
                'statechange',
                stateChangeListener,
              );
              resolve();
              return;
            }

            if (event.target.state === 'redundant') {
              serviceWorker.removeEventListener(
                'statechange',
                stateChangeListener,
              );
              reject(new Error('Installing service worker became redundant.'));
              return;
            }
          };

          serviceWorker.addEventListener('statechange', stateChangeListener);
        });
      }

      navigator.serviceWorker
        .register(swURL)
        .then((registration) => {
          return _onStateChangePromise(registration, 'activated');
        })
        .then(() => {
          // Ensure the page is being controlled by the SW.
          if (
            navigator.serviceWorker.controller &&
            navigator.serviceWorker.controller.scriptURL === swURL
          ) {
            return;
          } else {
            return new Promise((resolve) => {
              navigator.serviceWorker.addEventListener(
                'controllerchange',
                () => {
                  if (navigator.serviceWorker.controller.scriptURL === swURL) {
                    resolve();
                  }
                },
              );
            });
          }
        })
        .then(() => cb())
        .catch((error) => cb(error.message));
    },
    swURL,
  );

  if (error) {
    throw new Error(error);
  }
};


================================================
FILE: infra/testing/activate-sw-safari.js
================================================
/*
  Copyright 2018 Google LLC

  Use of this source code is governed by an MIT-style
  license that can be found in the LICENSE file or at
  https://opensource.org/licenses/MIT.
*/

// TODO(philipwalton): remove this in favor of using workbox-window.
module.exports = async (swURL) => {
  // First step: Wait for the page to activate
  let error = await global.__workbox.webdriver.executeAsyncScript(
    (swURL, cb) => {
      const onStateChangePromise = (registration, desiredState) => {
        return new Promise((resolve, reject) => {
          if (
            desiredState === 'activated' &&
            registration.active &&
            // Checking
Download .txt
gitextract_424215io/

├── .gitattributes
├── .github/
│   ├── ISSUE_TEMPLATE.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       ├── pull-request.yml
│       └── scorecards-analysis.yml
├── .gitignore
├── .husky/
│   ├── .gitignore
│   ├── pre-commit
│   └── pre-push
├── .ncurc.js
├── .nvmrc
├── .prettierignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── cdn-details.json
├── demos/
│   ├── README.md
│   └── src/
│       ├── workbox-background-sync-demo/
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── public/
│       │   │   └── example.txt
│       │   ├── sw.js
│       │   └── updateServer.js
│       ├── workbox-broadcast-update-demo/
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── sw.js
│       │   └── updateServer.js
│       ├── workbox-cacheable-response/
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── server.js
│       │   └── sw.js
│       ├── workbox-core/
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── sw.js
│       │   └── updateServer.js
│       ├── workbox-expiration/
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── sw.js
│       │   └── updateServer.js
│       ├── workbox-google-analytics/
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── sw.js
│       │   └── updateServer.js
│       ├── workbox-navigation-preload/
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── sw.js
│       │   └── updateServer.js
│       ├── workbox-precaching/
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── public/
│       │   │   ├── hello-world.1234.txt
│       │   │   ├── hello-world.5678.txt
│       │   │   └── test-file.txt
│       │   ├── sw-1.js
│       │   ├── sw-2.js
│       │   └── updateServer.js
│       ├── workbox-range-requests/
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── sw.js
│       │   └── updateServer.js
│       ├── workbox-routing/
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── sw.js
│       │   └── updateServer.js
│       ├── workbox-strategies/
│       │   ├── index.html
│       │   ├── public/
│       │   │   ├── cache-first.txt
│       │   │   ├── network-first.txt
│       │   │   ├── network-only.txt
│       │   │   └── stale-while-revalidate.txt
│       │   ├── sw.js
│       │   └── updateServer.js
│       ├── workbox-streams/
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── server.js
│       │   └── sw.js
│       ├── workbox-sw/
│       │   ├── README.md
│       │   ├── index.html
│       │   ├── package.json
│       │   ├── sw.js
│       │   └── updateServer.js
│       └── workbox-window/
│           ├── index.html
│           ├── package.json
│           ├── sw.js
│           └── updateServer.js
├── gulp-tasks/
│   ├── analyze-properties.js
│   ├── build-node-packages.js
│   ├── build-packages.js
│   ├── build-sw-packages.js
│   ├── build-window-packages.js
│   ├── build.js
│   ├── docs.js
│   ├── lint.js
│   ├── publish-cdn.js
│   ├── publish-github.js
│   ├── publish-glitch.js
│   ├── publish-lerna.js
│   ├── publish.js
│   ├── test-integration.js
│   ├── test-node.js
│   ├── test-server.js
│   ├── test.js
│   ├── transpile-typescript.js
│   └── utils/
│       ├── analyse-properties.js
│       ├── cdn-helper.js
│       ├── constants.js
│       ├── get-packages.js
│       ├── github-helper.js
│       ├── node-projects-babel.config.json
│       ├── output-filename-to-package-map.js
│       ├── package-runner.js
│       ├── pkg-path-to-name.js
│       ├── publish-helpers.js
│       ├── rollup-helper.js
│       ├── version-module.js
│       └── versioned-cdn-url.js
├── gulpfile.js
├── infra/
│   ├── pr-bot/
│   │   └── aggregate-size-plugin.js
│   ├── templates/
│   │   └── reference-docs/
│   │       └── jsdoc/
│   │           ├── lang/
│   │           │   └── en.yaml
│   │           ├── lib/
│   │           │   └── publishjob.js
│   │           ├── publish.js
│   │           ├── static/
│   │           │   └── jsdoc.css
│   │           └── views/
│   │               ├── augments.hbs
│   │               ├── classes-links.hbs
│   │               ├── details-table-row.hbs
│   │               ├── details-table.hbs
│   │               ├── implements.hbs
│   │               ├── index-all.hbs
│   │               ├── index.hbs
│   │               ├── layout.hbs
│   │               ├── params.hbs
│   │               ├── properties.hbs
│   │               ├── see.hbs
│   │               ├── signature.hbs
│   │               ├── symbol-content.hbs
│   │               ├── symbol-detail.hbs
│   │               ├── symbol-header.hbs
│   │               ├── symbol-index-section.hbs
│   │               ├── symbol-index.hbs
│   │               ├── symbol-labels.hbs
│   │               ├── symbol-overview.hbs
│   │               └── toc-yaml.hbs
│   ├── testing/
│   │   ├── activate-and-control.js
│   │   ├── activate-sw-safari.js
│   │   ├── auto-stub-logger.mjs
│   │   ├── clean-sw.js
│   │   ├── comlink/
│   │   │   ├── node-interface.js
│   │   │   ├── sw-interface.js
│   │   │   └── window-interface.js
│   │   ├── confirm-directory-contains.js
│   │   ├── env-it.js
│   │   ├── expectError.js
│   │   ├── generate-variant-tests.js
│   │   ├── helpers/
│   │   │   ├── compareResponses.mjs
│   │   │   ├── extendable-event-utils.mjs
│   │   │   ├── generateOpaqueResponse.mjs
│   │   │   ├── generateUniqueResponse.mjs
│   │   │   └── sleep.mjs
│   │   ├── server/
│   │   │   ├── cross-origin-server.js
│   │   │   ├── index.js
│   │   │   ├── request-counter.js
│   │   │   ├── routes/
│   │   │   │   ├── build-file.js
│   │   │   │   ├── comlink.js
│   │   │   │   ├── integration-html.js
│   │   │   │   ├── sw-bundle.js
│   │   │   │   ├── templates-update.js
│   │   │   │   ├── templates.js
│   │   │   │   ├── test-sw.js
│   │   │   │   ├── test-window.js
│   │   │   │   ├── unique-etag.js
│   │   │   │   └── unique-value.js
│   │   │   ├── static/
│   │   │   │   └── integration.html
│   │   │   ├── template-data.js
│   │   │   └── templates/
│   │   │       ├── integration.html.njk
│   │   │       ├── sw-clients-claim.js.njk
│   │   │       ├── sw-no-skip-waiting.js.njk
│   │   │       ├── sw-script-version.js.njk
│   │   │       ├── sw-skip-waiting-deferred.js.njk
│   │   │       ├── sw-skip-waiting-on-message.js.njk
│   │   │       ├── sw-skip-waiting.js.njk
│   │   │       ├── sw-window-ready.js.njk
│   │   │       ├── test-sw-runner.js.njk
│   │   │       ├── test-sw.html.njk
│   │   │       └── test-window.html.njk
│   │   ├── validator/
│   │   │   └── service-worker-runtime.js
│   │   ├── wait-until.js
│   │   ├── webdriver/
│   │   │   ├── IframeManager.js
│   │   │   ├── executeAsyncAndCatch.js
│   │   │   ├── runUnitTests.js
│   │   │   ├── unregisterAllSWs.js
│   │   │   └── windowLoaded.js
│   │   └── webpack-build-check.js
│   ├── type-overrides.d.ts
│   └── utils/
│       ├── AsyncDebounce.js
│       └── log-helper.js
├── javascript.eslintrc.js
├── jsdoc.conf
├── lerna.json
├── package.json
├── packages/
│   ├── workbox-background-sync/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── BackgroundSyncPlugin.ts
│   │   │   ├── Queue.ts
│   │   │   ├── QueueStore.ts
│   │   │   ├── StorableRequest.ts
│   │   │   ├── _version.ts
│   │   │   ├── index.ts
│   │   │   └── lib/
│   │   │       ├── QueueDb.ts
│   │   │       ├── QueueStore.ts
│   │   │       └── StorableRequest.ts
│   │   └── tsconfig.json
│   ├── workbox-broadcast-update/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── BroadcastCacheUpdate.ts
│   │   │   ├── BroadcastUpdatePlugin.ts
│   │   │   ├── _version.ts
│   │   │   ├── index.ts
│   │   │   ├── responsesAreSame.ts
│   │   │   └── utils/
│   │   │       └── constants.ts
│   │   └── tsconfig.json
│   ├── workbox-build/
│   │   ├── .ncurc.js
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── _types.js
│   │   │   ├── cdn-details.json
│   │   │   ├── generate-sw.ts
│   │   │   ├── get-manifest.ts
│   │   │   ├── index.ts
│   │   │   ├── inject-manifest.ts
│   │   │   ├── lib/
│   │   │   │   ├── additional-manifest-entries-transform.ts
│   │   │   │   ├── bundle.ts
│   │   │   │   ├── cdn-utils.ts
│   │   │   │   ├── copy-workbox-libraries.ts
│   │   │   │   ├── errors.ts
│   │   │   │   ├── escape-regexp.ts
│   │   │   │   ├── get-composite-details.ts
│   │   │   │   ├── get-file-details.ts
│   │   │   │   ├── get-file-hash.ts
│   │   │   │   ├── get-file-manifest-entries.ts
│   │   │   │   ├── get-file-size.ts
│   │   │   │   ├── get-source-map-url.ts
│   │   │   │   ├── get-string-details.ts
│   │   │   │   ├── get-string-hash.ts
│   │   │   │   ├── maximum-size-transform.ts
│   │   │   │   ├── modify-url-prefix-transform.ts
│   │   │   │   ├── module-registry.ts
│   │   │   │   ├── no-revision-for-urls-matching-transform.ts
│   │   │   │   ├── populate-sw-template.ts
│   │   │   │   ├── rebase-path.ts
│   │   │   │   ├── replace-and-update-source-map.ts
│   │   │   │   ├── runtime-caching-converter.ts
│   │   │   │   ├── stringify-without-comments.ts
│   │   │   │   ├── transform-manifest.ts
│   │   │   │   ├── translate-url-to-sourcemap-paths.ts
│   │   │   │   ├── validate-options.ts
│   │   │   │   └── write-sw-using-default-template.ts
│   │   │   ├── rollup-plugin-off-main-thread.d.ts
│   │   │   ├── schema/
│   │   │   │   ├── GenerateSWOptions.json
│   │   │   │   ├── GetManifestOptions.json
│   │   │   │   ├── InjectManifestOptions.json
│   │   │   │   ├── WebpackGenerateSWOptions.json
│   │   │   │   └── WebpackInjectManifestOptions.json
│   │   │   ├── strip-comments.d.ts
│   │   │   ├── templates/
│   │   │   │   └── sw-template.ts
│   │   │   └── types.ts
│   │   └── tsconfig.json
│   ├── workbox-cacheable-response/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── CacheableResponse.ts
│   │   │   ├── CacheableResponsePlugin.ts
│   │   │   ├── _version.ts
│   │   │   └── index.ts
│   │   └── tsconfig.json
│   ├── workbox-cli/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── app.ts
│   │   │   ├── bin.ts
│   │   │   └── lib/
│   │   │       ├── cleanup-stack-trace.ts
│   │   │       ├── constants.ts
│   │   │       ├── errors.ts
│   │   │       ├── help-text.ts
│   │   │       ├── logger.ts
│   │   │       ├── questions/
│   │   │       │   ├── ask-config-location.ts
│   │   │       │   ├── ask-extensions-to-cache.ts
│   │   │       │   ├── ask-questions.ts
│   │   │       │   ├── ask-root-of-web-app.ts
│   │   │       │   ├── ask-start_url-query-params.ts
│   │   │       │   ├── ask-sw-dest.ts
│   │   │       │   └── ask-sw-src.ts
│   │   │       ├── read-config.ts
│   │   │       └── run-wizard.ts
│   │   └── tsconfig.json
│   ├── workbox-core/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── _private/
│   │   │   │   ├── Deferred.ts
│   │   │   │   ├── WorkboxError.ts
│   │   │   │   ├── assert.ts
│   │   │   │   ├── cacheMatchIgnoreParams.ts
│   │   │   │   ├── cacheNames.ts
│   │   │   │   ├── canConstructReadableStream.ts
│   │   │   │   ├── canConstructResponseFromBodyStream.ts
│   │   │   │   ├── dontWaitFor.ts
│   │   │   │   ├── executeQuotaErrorCallbacks.ts
│   │   │   │   ├── getFriendlyURL.ts
│   │   │   │   ├── logger.ts
│   │   │   │   ├── resultingClientExists.ts
│   │   │   │   ├── timeout.ts
│   │   │   │   └── waitUntil.ts
│   │   │   ├── _private.ts
│   │   │   ├── _version.ts
│   │   │   ├── cacheNames.ts
│   │   │   ├── clientsClaim.ts
│   │   │   ├── copyResponse.ts
│   │   │   ├── index.ts
│   │   │   ├── models/
│   │   │   │   ├── messages/
│   │   │   │   │   ├── messageGenerator.ts
│   │   │   │   │   └── messages.ts
│   │   │   │   ├── pluginEvents.ts
│   │   │   │   └── quotaErrorCallbacks.ts
│   │   │   ├── registerQuotaErrorCallback.ts
│   │   │   ├── setCacheNameDetails.ts
│   │   │   ├── skipWaiting.ts
│   │   │   ├── types.ts
│   │   │   └── utils/
│   │   │       ├── pluginUtils.ts
│   │   │       └── welcome.ts
│   │   └── tsconfig.json
│   ├── workbox-expiration/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── CacheExpiration.ts
│   │   │   ├── ExpirationPlugin.ts
│   │   │   ├── _version.ts
│   │   │   ├── index.ts
│   │   │   └── models/
│   │   │       └── CacheTimestampsModel.ts
│   │   └── tsconfig.json
│   ├── workbox-google-analytics/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── _version.ts
│   │   │   ├── index.ts
│   │   │   ├── initialize.ts
│   │   │   └── utils/
│   │   │       └── constants.ts
│   │   └── tsconfig.json
│   ├── workbox-navigation-preload/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── _version.ts
│   │   │   ├── disable.ts
│   │   │   ├── enable.ts
│   │   │   ├── index.ts
│   │   │   └── isSupported.ts
│   │   └── tsconfig.json
│   ├── workbox-precaching/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── PrecacheController.ts
│   │   │   ├── PrecacheFallbackPlugin.ts
│   │   │   ├── PrecacheRoute.ts
│   │   │   ├── PrecacheStrategy.ts
│   │   │   ├── _types.ts
│   │   │   ├── _version.ts
│   │   │   ├── addPlugins.ts
│   │   │   ├── addRoute.ts
│   │   │   ├── cleanupOutdatedCaches.ts
│   │   │   ├── createHandlerBoundToURL.ts
│   │   │   ├── getCacheKeyForURL.ts
│   │   │   ├── index.ts
│   │   │   ├── matchPrecache.ts
│   │   │   ├── precache.ts
│   │   │   ├── precacheAndRoute.ts
│   │   │   └── utils/
│   │   │       ├── PrecacheCacheKeyPlugin.ts
│   │   │       ├── PrecacheInstallReportPlugin.ts
│   │   │       ├── createCacheKey.ts
│   │   │       ├── deleteOutdatedCaches.ts
│   │   │       ├── generateURLVariations.ts
│   │   │       ├── getCacheKeyForURL.ts
│   │   │       ├── getOrCreatePrecacheController.ts
│   │   │       ├── printCleanupDetails.ts
│   │   │       ├── printInstallDetails.ts
│   │   │       └── removeIgnoredSearchParams.ts
│   │   └── tsconfig.json
│   ├── workbox-range-requests/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── RangeRequestsPlugin.ts
│   │   │   ├── _version.ts
│   │   │   ├── createPartialResponse.ts
│   │   │   ├── index.ts
│   │   │   └── utils/
│   │   │       ├── calculateEffectiveBoundaries.ts
│   │   │       └── parseRangeHeader.ts
│   │   └── tsconfig.json
│   ├── workbox-recipes/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── _version.ts
│   │   │   ├── googleFontsCache.ts
│   │   │   ├── imageCache.ts
│   │   │   ├── index.ts
│   │   │   ├── offlineFallback.ts
│   │   │   ├── pageCache.ts
│   │   │   ├── staticResourceCache.ts
│   │   │   └── warmStrategyCache.ts
│   │   └── tsconfig.json
│   ├── workbox-routing/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── NavigationRoute.ts
│   │   │   ├── RegExpRoute.ts
│   │   │   ├── Route.ts
│   │   │   ├── Router.ts
│   │   │   ├── _types.ts
│   │   │   ├── _version.ts
│   │   │   ├── index.ts
│   │   │   ├── registerRoute.ts
│   │   │   ├── setCatchHandler.ts
│   │   │   ├── setDefaultHandler.ts
│   │   │   └── utils/
│   │   │       ├── constants.ts
│   │   │       ├── getOrCreateDefaultRouter.ts
│   │   │       └── normalizeHandler.ts
│   │   └── tsconfig.json
│   ├── workbox-strategies/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── CacheFirst.ts
│   │   │   ├── CacheOnly.ts
│   │   │   ├── NetworkFirst.ts
│   │   │   ├── NetworkOnly.ts
│   │   │   ├── StaleWhileRevalidate.ts
│   │   │   ├── Strategy.ts
│   │   │   ├── StrategyHandler.ts
│   │   │   ├── _version.ts
│   │   │   ├── index.ts
│   │   │   ├── plugins/
│   │   │   │   └── cacheOkAndOpaquePlugin.ts
│   │   │   └── utils/
│   │   │       └── messages.ts
│   │   └── tsconfig.json
│   ├── workbox-streams/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── _types.ts
│   │   │   ├── _version.ts
│   │   │   ├── concatenate.ts
│   │   │   ├── concatenateToResponse.ts
│   │   │   ├── index.ts
│   │   │   ├── isSupported.ts
│   │   │   ├── strategy.ts
│   │   │   └── utils/
│   │   │       └── createHeaders.ts
│   │   └── tsconfig.json
│   ├── workbox-sw/
│   │   ├── README.md
│   │   ├── _types.mjs
│   │   ├── _version.mjs
│   │   ├── controllers/
│   │   │   └── WorkboxSW.mjs
│   │   ├── index.mjs
│   │   └── package.json
│   ├── workbox-webpack-plugin/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── generate-sw.ts
│   │   │   ├── index.ts
│   │   │   ├── inject-manifest.ts
│   │   │   └── lib/
│   │   │       ├── get-asset-hash.ts
│   │   │       ├── get-manifest-entries-from-compilation.ts
│   │   │       ├── get-script-files-for-chunks.ts
│   │   │       ├── get-sourcemap-asset-name.ts
│   │   │       ├── relative-to-output-path.ts
│   │   │       └── resolve-webpack-url.ts
│   │   └── tsconfig.json
│   └── workbox-window/
│       ├── README.md
│       ├── package.json
│       ├── src/
│       │   ├── Workbox.ts
│       │   ├── _version.ts
│       │   ├── index.ts
│       │   ├── messageSW.ts
│       │   └── utils/
│       │       ├── WorkboxEvent.ts
│       │       ├── WorkboxEventTarget.ts
│       │       └── urlsMatch.ts
│       └── tsconfig.json
├── prettier.config.js
├── test/
│   ├── all/
│   │   └── node/
│   │       ├── test-exports.js
│   │       ├── test-jsdocs.js
│   │       ├── test-package.js
│   │       ├── test-prod-builds.js
│   │       └── test-yarn-installation.js
│   ├── workbox-background-sync/
│   │   ├── integration/
│   │   │   └── test-all.js
│   │   ├── static/
│   │   │   └── basic-example/
│   │   │       ├── example.txt
│   │   │       ├── index.html
│   │   │       └── sw.js
│   │   └── sw/
│   │       ├── lib/
│   │       │   ├── test-QueueDb.mjs
│   │       │   ├── test-QueueStore.mjs
│   │       │   └── test-StorableRequest.mjs
│   │       ├── test-BackgroundSyncPlugin.mjs
│   │       └── test-Queue.mjs
│   ├── workbox-broadcast-update/
│   │   ├── integration/
│   │   │   └── test-all.js
│   │   ├── static/
│   │   │   ├── index.html
│   │   │   └── sw.js
│   │   └── sw/
│   │       ├── test-BroadcastCacheUpdate.mjs
│   │       ├── test-BroadcastUpdatePlugin.mjs
│   │       └── test-responsesAreSame.mjs
│   ├── workbox-build/
│   │   ├── node/
│   │   │   ├── dependency-check.js
│   │   │   ├── generate-sw.js
│   │   │   ├── get-manifest.js
│   │   │   ├── inject-manifest.js
│   │   │   └── lib/
│   │   │       ├── additional-manifest-entries-transform.js
│   │   │       ├── bundle.js
│   │   │       ├── cdn-utils.js
│   │   │       ├── copy-workbox-libraries.js
│   │   │       ├── escape-regexp.js
│   │   │       ├── get-composite-details.js
│   │   │       ├── get-file-details.js
│   │   │       ├── get-file-hash.js
│   │   │       ├── get-file-manifest-entries.js
│   │   │       ├── get-file-size.js
│   │   │       ├── get-string-details.js
│   │   │       ├── get-string-hash.js
│   │   │       ├── modify-url-prefix-transform.js
│   │   │       ├── module-registry.js
│   │   │       ├── no-revision-for-urls-matching-transform.js
│   │   │       ├── populate-sw-template.js
│   │   │       ├── replace-and-update-source-map.js
│   │   │       ├── runtime-caching-converter.js
│   │   │       ├── transform-manifest.js
│   │   │       ├── translate-url-to-sourcemap-paths.js
│   │   │       ├── validate-options.js
│   │   │       └── write-sw-using-default-template.js
│   │   └── static/
│   │       ├── example-project-1/
│   │       │   ├── .hidden-directory/
│   │       │   │   ├── hello.html
│   │       │   │   └── hello.js
│   │       │   ├── index.html
│   │       │   ├── page-1.html
│   │       │   ├── page-2.html
│   │       │   ├── styles/
│   │       │   │   ├── stylesheet-1.css
│   │       │   │   └── stylesheet-2.css
│   │       │   └── webpackEntry.js
│   │       └── sw-injections/
│   │           ├── bad-multiple-injection.js
│   │           ├── bad-no-injection.js
│   │           ├── basic-with-invalid-sourcemap.js.nolint
│   │           ├── basic-with-sourcemap-data-url.js.nolint
│   │           ├── basic-with-sourcemap.js.nolint
│   │           ├── basic.js
│   │           ├── custom-injection-point.js
│   │           ├── multiple-calls.js
│   │           ├── precache-and-route-options.js
│   │           └── sample-import.js
│   ├── workbox-cacheable-response/
│   │   ├── integration/
│   │   │   └── test-all.js
│   │   ├── static/
│   │   │   └── cacheable-response-plugin/
│   │   │       ├── example-1.txt
│   │   │       └── sw.js
│   │   └── sw/
│   │       ├── test-CacheableResponse.mjs
│   │       └── test-CacheableResponsePlugin.mjs
│   ├── workbox-cli/
│   │   └── node/
│   │       ├── app.js
│   │       ├── dependency-check.js
│   │       └── lib/
│   │           ├── cleanup-stack-trace.js
│   │           ├── help-text.js
│   │           ├── logger.js
│   │           ├── questions/
│   │           │   ├── ask-config-location.js
│   │           │   ├── ask-extensions-to-cache.js
│   │           │   ├── ask-questions.js
│   │           │   ├── ask-root-of-web-app.js
│   │           │   ├── ask-start_url-query-params.js
│   │           │   ├── ask-sw-dest.js
│   │           │   └── ask-sw-src.js
│   │           └── run-wizard.js
│   ├── workbox-core/
│   │   ├── integration/
│   │   │   └── test-all.js
│   │   ├── static/
│   │   │   ├── core-in-browser/
│   │   │   │   ├── index.html
│   │   │   │   └── sw.js
│   │   │   └── logger.html
│   │   └── sw/
│   │       ├── _private/
│   │       │   ├── test-Deferred.mjs
│   │       │   ├── test-assert.mjs
│   │       │   ├── test-cacheMatchIgnoreParams.mjs
│   │       │   ├── test-executeQuotaErrorCallbacks.mjs
│   │       │   ├── test-getFriendlyURL.mjs
│   │       │   ├── test-logger.mjs
│   │       │   ├── test-resultingClientExists.mjs
│   │       │   ├── test-timeout.mjs
│   │       │   └── test-waitUntil.mjs
│   │       ├── models/
│   │       │   └── messages/
│   │       │       └── test-messageGenerator.mjs
│   │       ├── test-cacheNames.mjs
│   │       ├── test-clientsClaim.mjs
│   │       ├── test-copyResponse.mjs
│   │       ├── test-registerQuotaErrorCallback.mjs
│   │       └── test-skipWaiting.mjs
│   ├── workbox-expiration/
│   │   ├── integration/
│   │   │   └── test-all.js
│   │   ├── static/
│   │   │   ├── expiration-plugin/
│   │   │   │   ├── example-1.txt
│   │   │   │   ├── example-2.txt
│   │   │   │   ├── sw-deletion.js
│   │   │   │   ├── sw-max-age-seconds.js
│   │   │   │   └── sw-max-entries.js
│   │   │   └── isURLExpired.html
│   │   └── sw/
│   │       ├── test-CacheExpiration.mjs
│   │       ├── test-CacheTimestampsModel.mjs
│   │       └── test-ExpirationPlugin.mjs
│   ├── workbox-google-analytics/
│   │   ├── integration/
│   │   │   └── test-all.js
│   │   ├── static/
│   │   │   └── basic-example/
│   │   │       ├── index.html
│   │   │       └── sw.js
│   │   └── sw/
│   │       └── test-initialize.mjs
│   ├── workbox-navigation-preload/
│   │   ├── integration/
│   │   │   ├── test-disable.js
│   │   │   ├── test-enable.js
│   │   │   └── test-sw.js
│   │   ├── static/
│   │   │   ├── sw-custom-header.js
│   │   │   ├── sw-default-header.js
│   │   │   └── sw-disable.js
│   │   └── sw/
│   │       ├── test-disable.mjs
│   │       ├── test-enable.mjs
│   │       └── test-isSupported.mjs
│   ├── workbox-precaching/
│   │   ├── integration/
│   │   │   ├── test-cleanup-outdated-caches.js
│   │   │   ├── test-precache-and-update.js
│   │   │   └── test-sw.js
│   │   ├── static/
│   │   │   ├── addToCacheList.html
│   │   │   ├── cleanup-outdated-caches/
│   │   │   │   ├── sw.js
│   │   │   │   └── test.txt
│   │   │   ├── precache-and-update/
│   │   │   │   ├── hashed-file.abcd1234.txt
│   │   │   │   ├── index.html
│   │   │   │   ├── styles/
│   │   │   │   │   └── index.css
│   │   │   │   ├── sw-1.js
│   │   │   │   └── sw-2.js
│   │   │   ├── precache.html
│   │   │   └── project/
│   │   │       ├── example-2.html
│   │   │       ├── example-a.html
│   │   │       ├── example-b.html
│   │   │       ├── example-timestamp.html
│   │   │       ├── example.html
│   │   │       └── index.html
│   │   └── sw/
│   │       ├── resetDefaultPrecacheController.mjs
│   │       ├── test-PrecacheController.mjs
│   │       ├── test-PrecacheFallbackPlugin.mjs
│   │       ├── test-PrecacheRoute.mjs
│   │       ├── test-PrecacheStrategy.mjs
│   │       ├── test-addPlugins.mjs
│   │       ├── test-addRoute.mjs
│   │       ├── test-cleanupOutdatedCaches.mjs
│   │       ├── test-createHandlerBoundToURL.mjs
│   │       ├── test-getCacheKeyForURL.mjs
│   │       ├── test-matchPrecache.mjs
│   │       ├── test-precache.mjs
│   │       ├── test-precacheAndRoute.mjs
│   │       └── utils/
│   │           ├── test-deleteOutdatedCaches.mjs
│   │           ├── test-printCleanupDetails.mjs
│   │           └── test-printInstallDetails.mjs
│   ├── workbox-range-requests/
│   │   ├── integration/
│   │   │   └── test-all.js
│   │   ├── static/
│   │   │   ├── index.html
│   │   │   └── sw.js
│   │   └── sw/
│   │       ├── test-RangeRequestsPlugin.mjs
│   │       ├── test-createPartialResponse.mjs
│   │       └── utils/
│   │           ├── test-calculateEffectiveBoundaries.mjs
│   │           └── test-parseRangeHeader.mjs
│   ├── workbox-routing/
│   │   ├── integration/
│   │   │   ├── test-navigation-route.js
│   │   │   ├── test-routing-basic.js
│   │   │   ├── test-routing-regex.js
│   │   │   └── test-sw.js
│   │   ├── static/
│   │   │   ├── routing-basic/
│   │   │   │   ├── index.html
│   │   │   │   └── sw.js
│   │   │   ├── routing-navigation/
│   │   │   │   ├── index.html
│   │   │   │   └── sw.js
│   │   │   ├── routing-regex/
│   │   │   │   ├── index.html
│   │   │   │   └── sw.js
│   │   │   ├── routing.html
│   │   │   └── sw.js
│   │   └── sw/
│   │       ├── test-NavigationRoute.mjs
│   │       ├── test-RegExpRoute.mjs
│   │       ├── test-Route.mjs
│   │       ├── test-Router.mjs
│   │       ├── test-registerRoute.mjs
│   │       ├── test-setCatchHandler.mjs
│   │       ├── test-setDefaultHandler.mjs
│   │       └── utils/
│   │           └── test-normalizeHandler.mjs
│   ├── workbox-strategies/
│   │   ├── integration/
│   │   │   ├── test-cacheFirst.js
│   │   │   ├── test-cacheOnly.js
│   │   │   ├── test-networkFirst.js
│   │   │   ├── test-networkOnly.js
│   │   │   ├── test-staleWhileRevalidate.js
│   │   │   └── test-sw.js
│   │   ├── static/
│   │   │   ├── cache-first/
│   │   │   │   ├── example.txt
│   │   │   │   └── sw.js
│   │   │   ├── cache-only/
│   │   │   │   └── sw.js
│   │   │   ├── network-first/
│   │   │   │   └── sw.js
│   │   │   ├── network-only/
│   │   │   │   └── sw.js
│   │   │   └── stale-while-revalidate/
│   │   │       └── sw.js
│   │   └── sw/
│   │       ├── plugins/
│   │       │   └── test-cacheOkAndOpaquePlugin.mjs
│   │       ├── test-CacheFirst.mjs
│   │       ├── test-CacheOnly.mjs
│   │       ├── test-NetworkFirst.mjs
│   │       ├── test-NetworkOnly.mjs
│   │       ├── test-StaleWhileRevalidate.mjs
│   │       ├── test-Strategy.mjs
│   │       ├── test-StrategyHandler.mjs
│   │       └── test-UsageWithRouter.mjs
│   ├── workbox-streams/
│   │   ├── integration/
│   │   │   └── test-all.js
│   │   ├── static/
│   │   │   ├── 4.txt
│   │   │   ├── index.html
│   │   │   └── sw.js
│   │   └── sw/
│   │       ├── test-isSupported.mjs
│   │       └── utils/
│   │           └── test-createHeaders.mjs
│   ├── workbox-sw/
│   │   ├── integration/
│   │   │   └── test-all.js
│   │   ├── static/
│   │   │   ├── example.css
│   │   │   ├── example.js
│   │   │   ├── index.html
│   │   │   ├── integration/
│   │   │   │   ├── index.html
│   │   │   │   ├── invalid-sw.js
│   │   │   │   └── valid-sw.js
│   │   │   └── sw.js
│   │   └── sw/
│   │       └── controllers/
│   │           └── test-WorkboxSW.mjs
│   ├── workbox-webpack-plugin/
│   │   ├── node/
│   │   │   ├── dependency-check.js
│   │   │   ├── v4/
│   │   │   │   ├── generate-sw.js
│   │   │   │   ├── inject-manifest.js
│   │   │   │   └── lib/
│   │   │   │       └── create-webpack-asset-plugin.js
│   │   │   └── v5/
│   │   │       ├── generate-sw.js
│   │   │       ├── inject-manifest.js
│   │   │       └── lib/
│   │   │           └── create-webpack-asset-plugin.js
│   │   └── static/
│   │       ├── bad-multiple-injection.js
│   │       ├── example-project-1/
│   │       │   ├── index.html
│   │       │   ├── page-1.html
│   │       │   ├── page-2.html
│   │       │   ├── splitChunksEntry.js
│   │       │   ├── styles/
│   │       │   │   ├── stylesheet-1.css
│   │       │   │   └── stylesheet-2.css
│   │       │   └── webpackEntry.js
│   │       ├── injected-manifest.js
│   │       ├── injected-manifest.json
│   │       ├── module-import-sw.js
│   │       ├── sw-src-define-plugin.js
│   │       ├── sw-src-missing-sourcemap.js
│   │       ├── sw-src.js
│   │       ├── sw.ts
│   │       └── wasm-project/
│   │           ├── add.wasm
│   │           ├── index.js
│   │           └── worker.js
│   └── workbox-window/
│       ├── integration/
│       │   └── test-all.js
│       ├── static/
│       │   └── index.html
│       └── window/
│           ├── sw-error.js
│           ├── sw-message-reply.js
│           └── test-Workbox.mjs
├── tsconfig.json
└── typescript.eslintrc.js
Download .txt
SYMBOL INDEX (723 symbols across 226 files)

FILE: demos/src/workbox-routing/sw.js
  constant GLITCH_ICO_URL (line 25) | const GLITCH_ICO_URL = 'https://glitch.com/edit/favicon-app.ico';

FILE: demos/src/workbox-streams/sw.js
  constant CACHE_NAME (line 9) | const CACHE_NAME = 'my-cache';
  constant START_CACHE_KEY (line 10) | const START_CACHE_KEY = 'start';
  constant END_CACHE_KEY (line 11) | const END_CACHE_KEY = 'end';

FILE: demos/src/workbox-window/sw.js
  constant SW_VERSION (line 9) | const SW_VERSION = '5.0.0';

FILE: gulp-tasks/analyze-properties.js
  function analyze_properties (line 11) | async function analyze_properties() {

FILE: gulp-tasks/build-node-packages.js
  constant TJS (line 12) | const TJS = require('typescript-json-schema');
  function buildNodePackage (line 18) | async function buildNodePackage(packagePath) {
  function generateWorkboxBuildJSONSchema (line 44) | async function generateWorkboxBuildJSONSchema(packagePath) {

FILE: gulp-tasks/build-packages.js
  function cleanPackage (line 24) | async function cleanPackage(packagePath) {
  function cleanSequence (line 56) | function cleanSequence() {

FILE: gulp-tasks/build-sw-packages.js
  function globals (line 24) | function globals(moduleId) {
  function externalAndPure (line 76) | function externalAndPure(importPath) {
  function buildSWBundle (line 80) | async function buildSWBundle(packagePath, buildType) {
  function swBundleSequence (line 156) | function swBundleSequence() {

FILE: gulp-tasks/build-window-packages.js
  function buildWindowBundle (line 22) | async function buildWindowBundle(packagePath, buildType) {
  function windowBundleSequence (line 98) | function windowBundleSequence() {

FILE: gulp-tasks/build.js
  function build_update_cdn_details (line 19) | async function build_update_cdn_details() {
  function build_lerna_bootstrap (line 48) | async function build_lerna_bootstrap() {

FILE: gulp-tasks/docs.js
  constant DOCS_DIRECTORY (line 16) | const DOCS_DIRECTORY = upath.join(__dirname, '..', 'docs');
  function docs_build (line 18) | async function docs_build() {
  function docs_watch (line 66) | function docs_watch() {

FILE: gulp-tasks/lint.js
  function lint_js (line 12) | async function lint_js() {
  function lint_ts (line 26) | async function lint_ts() {

FILE: gulp-tasks/publish-cdn.js
  function cleanTagName (line 18) | function cleanTagName(name) {
  function findMissingCDNTags (line 28) | async function findMissingCDNTags(tagsData) {
  function handleCDNUpload (line 42) | async function handleCDNUpload(tagName, gitBranch) {
  function publish_cdn (line 59) | async function publish_cdn() {

FILE: gulp-tasks/publish-github.js
  function publishReleaseOnGithub (line 14) | async function publishReleaseOnGithub(tagName, releaseInfo) {
  function handleGithubRelease (line 26) | async function handleGithubRelease(tagName, gitBranch, releaseInfo) {
  function filterTagsWithReleaseBundles (line 32) | function filterTagsWithReleaseBundles(allTags, taggedReleases) {
  function publish_github (line 46) | async function publish_github() {

FILE: gulp-tasks/publish-glitch.js
  constant DEMOS_DIR (line 20) | const DEMOS_DIR = 'demos/src';
  function publish_glitch (line 22) | async function publish_glitch() {

FILE: gulp-tasks/publish-lerna.js
  function publish_lerna (line 14) | async function publish_lerna() {

FILE: gulp-tasks/publish.js
  function publish_clean (line 22) | async function publish_clean() {
  function publish_sign_in_check (line 26) | async function publish_sign_in_check() {
  function dist_tag_check (line 30) | async function dist_tag_check() {

FILE: gulp-tasks/test-integration.js
  function runFiles (line 20) | function runFiles(filePaths) {
  function runTestSuite (line 46) | async function runTestSuite(testPath, nodeEnv, seleniumBrowser, webdrive...
  function runIntegrationForBrowser (line 76) | async function runIntegrationForBrowser(browser) {
  function test_integration (line 106) | async function test_integration() {

FILE: gulp-tasks/test-node.js
  function runNodeTestSuite (line 19) | async function runNodeTestSuite(testPath, nodeEnv) {
  function runNodeTestsWithEnv (line 52) | async function runNodeTestsWithEnv(testGroup, nodeEnv) {
  function test_node_prod (line 74) | async function test_node_prod() {
  function test_node_dev (line 78) | async function test_node_dev() {
  function test_node_all (line 82) | async function test_node_all() {
  function test_node_clean (line 86) | async function test_node_clean() {
  function test_node_coverage (line 90) | async function test_node_coverage() {

FILE: gulp-tasks/test-server.js
  function handleExit (line 18) | function handleExit() {
  function startServer (line 23) | function startServer() {

FILE: gulp-tasks/test.js
  function logSkip (line 16) | async function logSkip() {
  function runTestsUnlessSkipped (line 20) | function runTestsUnlessSkipped() {

FILE: gulp-tasks/transpile-typescript.js
  function queueTranspile (line 33) | async function queueTranspile(packageName, options) {
  function needsTranspile (line 57) | function needsTranspile(packageName) {
  function transpile_typescript (line 71) | async function transpile_typescript() {
  function transpile_typescript_watch (line 86) | async function transpile_typescript_watch() {

FILE: gulp-tasks/utils/analyse-properties.js
  class AnalyseBuildForProperties (line 30) | class AnalyseBuildForProperties {
    method run (line 31) | run() {
    method getBuildFiles (line 46) | getBuildFiles() {
    method analyzeFile (line 60) | analyzeFile(filePath) {
    method tidyData (line 87) | tidyData(analysisEntries) {
    method printDetails (line 108) | printDetails({filePath, analysis}) {

FILE: gulp-tasks/utils/cdn-helper.js
  constant PROJECT_ID (line 16) | const PROJECT_ID = 'workbox-bab1f';
  class CDNHelper (line 18) | class CDNHelper {
    method constructor (line 19) | constructor() {
    method _getReleaseTagPath (line 23) | _getReleaseTagPath(tagName) {
    method getGCS (line 27) | async getGCS() {
    method tagExists (line 39) | async tagExists(tagName) {
    method upload (line 56) | async upload(tagName, directoryToUpload) {

FILE: gulp-tasks/utils/get-packages.js
  constant DEFAULT_ROOT (line 12) | const DEFAULT_ROOT = path.join(__dirname, '..', '..');

FILE: gulp-tasks/utils/package-runner.js
  function getPackages (line 21) | function getPackages(typeFilter) {

FILE: gulp-tasks/utils/publish-helpers.js
  constant SOURCE_CODE_DIR (line 19) | const SOURCE_CODE_DIR = 'source-code';
  constant GROUPED_BUILD_FILES (line 20) | const GROUPED_BUILD_FILES = 'grouped-build-files';

FILE: infra/pr-bot/aggregate-size-plugin.js
  constant MAX_SIZE_GZIP (line 17) | const MAX_SIZE_GZIP = 15 * 1024;
  class AggregateSizePlugin (line 19) | class AggregateSizePlugin extends PluginInterface {
    method constructor (line 20) | constructor() {
    method run (line 24) | async run({afterPath} = {}) {

FILE: infra/templates/reference-docs/jsdoc/lib/publishjob.js
  class PublishJob (line 15) | class PublishJob extends BaselinePublishJob {
    method constructor (line 16) | constructor(...args) {
    method generateTocYaml (line 22) | generateTocYaml(symbols, basepath) {
    method generateIndex (line 85) | generateIndex(readme) {
    method generateIndexAll (line 98) | generateIndexAll(longnames) {

FILE: infra/testing/activate-and-control.js
  function _onStateChangePromise (line 19) | function _onStateChangePromise(registration, desiredState) {

FILE: infra/testing/comlink/window-interface.js
  function initComlink (line 9) | function initComlink() {

FILE: infra/testing/server/cross-origin-server.js
  constant PORT (line 11) | const PORT = 3010;
  function initApp (line 16) | function initApp(staticDir) {
  function start (line 21) | function start(staticDir) {
  function stop (line 37) | function stop() {

FILE: infra/testing/server/index.js
  constant PORT (line 19) | const PORT = 3004;
  function initApp (line 25) | function initApp() {
  function start (line 51) | function start() {
  function stop (line 68) | function stop() {
  function getAddress (line 74) | function getAddress() {
  function startCountingRequests (line 78) | function startCountingRequests(headerValue) {
  function stopCountingRequests (line 84) | function stopCountingRequests(requestCounter) {

FILE: infra/testing/server/request-counter.js
  class RequestCounter (line 9) | class RequestCounter {
    method constructor (line 10) | constructor(headerName) {
    method count (line 16) | count(req) {
    method getHeaderCount (line 34) | getHeaderCount(headerValue) {
    method getURLCount (line 38) | getURLCount(url) {

FILE: infra/testing/server/routes/build-file.js
  function handler (line 16) | async function handler(req, res) {

FILE: infra/testing/server/routes/comlink.js
  function handler (line 11) | async function handler(req, res) {

FILE: infra/testing/server/routes/integration-html.js
  function handler (line 13) | async function handler(req, res) {

FILE: infra/testing/server/routes/sw-bundle.js
  constant SW_NAMESPACES (line 18) | const SW_NAMESPACES = getPackages({type: 'sw'}).map((pkg) => {
  function handler (line 25) | async function handler(req, res) {

FILE: infra/testing/server/routes/templates-update.js
  function handler (line 15) | async function handler(req, res) {

FILE: infra/testing/server/routes/templates.js
  function handler (line 18) | async function handler(req, res) {

FILE: infra/testing/server/routes/test-sw.js
  function handler (line 15) | async function handler(req, res) {

FILE: infra/testing/server/routes/test-window.js
  function handler (line 15) | async function handler(req, res) {

FILE: infra/testing/server/routes/unique-etag.js
  function handler (line 12) | async function handler(req, res) {

FILE: infra/testing/server/routes/unique-value.js
  function handler (line 12) | async function handler(req, res) {

FILE: infra/testing/validator/service-worker-runtime.js
  function stringifyFunctionsInArray (line 21) | function stringifyFunctionsInArray(arr) {
  function setupSpiesAndContextForInjectManifest (line 27) | function setupSpiesAndContextForInjectManifest() {
  function setupSpiesAndContextForGenerateSW (line 113) | function setupSpiesAndContextForGenerateSW() {
  function validateMethodCalls (line 152) | function validateMethodCalls({methodsToSpies, expectedMethodCalls, conte...

FILE: infra/testing/webdriver/IframeManager.js
  constant PREFIX (line 9) | const PREFIX = 'iframe-';
  class Client (line 12) | class Client {
    method constructor (line 13) | constructor(driver, id) {
    method executeAsyncScript (line 18) | async executeAsyncScript(code) {
    method wait (line 33) | async wait(code) {
    method remove (line 37) | remove() {
  class IframeManager (line 49) | class IframeManager {
    method constructor (line 55) | constructor(driver) {
    method createIframeClient (line 60) | async createIframeClient(url) {

FILE: infra/testing/webpack-build-check.js
  function joinMessages (line 9) | function joinMessages(errorsOrWarnings) {

FILE: infra/type-overrides.d.ts
  type IDBIndex (line 4) | interface IDBIndex {
  type IDBObjectStore (line 15) | interface IDBObjectStore {
  type CacheStorage (line 29) | interface CacheStorage {
  type Headers (line 39) | interface Headers {
  type URLSearchParams (line 55) | interface URLSearchParams {

FILE: infra/utils/AsyncDebounce.js
  class AsyncDebounce (line 9) | class AsyncDebounce {
    method constructor (line 10) | constructor(fn) {
    method call (line 15) | call() {

FILE: packages/workbox-background-sync/src/BackgroundSyncPlugin.ts
  class BackgroundSyncPlugin (line 19) | class BackgroundSyncPlugin implements WorkboxPlugin {
    method constructor (line 29) | constructor(name: string, options?: QueueOptions) {

FILE: packages/workbox-background-sync/src/Queue.ts
  type OnSyncCallbackOptions (line 21) | interface OnSyncCallbackOptions {
  type OnSyncCallback (line 25) | interface OnSyncCallback {
  type QueueOptions (line 29) | interface QueueOptions {
  type QueueEntry (line 35) | interface QueueEntry {
  constant TAG_PREFIX (line 44) | const TAG_PREFIX = 'workbox-background-sync';
  constant MAX_RETENTION_TIME (line 45) | const MAX_RETENTION_TIME = 60 * 24 * 7;
  class Queue (line 78) | class Queue {
    method constructor (line 112) | constructor(
    method name (line 135) | get name(): string {
    method pushRequest (line 155) | async pushRequest(entry: QueueEntry): Promise<void> {
    method unshiftRequest (line 190) | async unshiftRequest(entry: QueueEntry): Promise<void> {
    method popRequest (line 216) | async popRequest(): Promise<QueueEntry | undefined> {
    method shiftRequest (line 227) | async shiftRequest(): Promise<QueueEntry | undefined> {
    method getAll (line 237) | async getAll(): Promise<Array<QueueEntry>> {
    method size (line 262) | async size(): Promise<number> {
    method _addRequest (line 276) | async _addRequest(
    method _removeRequest (line 325) | async _removeRequest(
    method replayRequests (line 358) | async replayRequests(): Promise<void> {
    method registerSync (line 393) | async registerSync(): Promise<void> {
    method _addSyncListener (line 418) | private _addSyncListener() {
    method _queueNames (line 482) | static get _queueNames(): Set<string> {

FILE: packages/workbox-background-sync/src/index.ts
  type SyncManager (line 17) | interface SyncManager {
  type ServiceWorkerRegistration (line 23) | interface ServiceWorkerRegistration {
  type SyncEvent (line 27) | interface SyncEvent extends ExtendableEvent {
  type ServiceWorkerGlobalScopeEventMap (line 32) | interface ServiceWorkerGlobalScopeEventMap {

FILE: packages/workbox-background-sync/src/lib/QueueDb.ts
  type QueueDBSchema (line 13) | interface QueueDBSchema extends DBSchema {
  constant DB_VERSION (line 21) | const DB_VERSION = 3;
  constant DB_NAME (line 22) | const DB_NAME = 'workbox-background-sync';
  constant REQUEST_OBJECT_STORE_NAME (line 23) | const REQUEST_OBJECT_STORE_NAME = 'requests';
  constant QUEUE_NAME_INDEX (line 24) | const QUEUE_NAME_INDEX = 'queueName';
  type UnidentifiedQueueStoreEntry (line 26) | interface UnidentifiedQueueStoreEntry {
  type QueueStoreEntry (line 37) | interface QueueStoreEntry extends UnidentifiedQueueStoreEntry {
  class QueueDb (line 49) | class QueueDb {
    method addEntry (line 57) | async addEntry(entry: UnidentifiedQueueStoreEntry): Promise<void> {
    method getFirstEntryId (line 71) | async getFirstEntryId(): Promise<number | undefined> {
    method getAllEntriesByQueueName (line 85) | async getAllEntriesByQueueName(
    method getEntryCountByQueueName (line 103) | async getEntryCountByQueueName(queueName: string): Promise<number> {
    method deleteEntry (line 117) | async deleteEntry(id: number): Promise<void> {
    method getFirstEntryByQueueName (line 127) | async getFirstEntryByQueueName(
    method getLastEntryByQueueName (line 138) | async getLastEntryByQueueName(
    method getEndEntryFromIndex (line 153) | async getEndEntryFromIndex(
    method getDb (line 171) | private async getDb() {
    method _upgradeDb (line 187) | private _upgradeDb(db: IDBPDatabase<QueueDBSchema>, oldVersion: number) {

FILE: packages/workbox-background-sync/src/lib/QueueStore.ts
  class QueueStore (line 24) | class QueueStore {
    method constructor (line 34) | constructor(queueName: string) {
    method pushEntry (line 47) | async pushEntry(entry: UnidentifiedQueueStoreEntry): Promise<void> {
    method unshiftEntry (line 78) | async unshiftEntry(entry: UnidentifiedQueueStoreEntry): Promise<void> {
    method popEntry (line 113) | async popEntry(): Promise<QueueStoreEntry | undefined> {
    method shiftEntry (line 124) | async shiftEntry(): Promise<QueueStoreEntry | undefined> {
    method getAll (line 136) | async getAll(): Promise<QueueStoreEntry[]> {
    method size (line 146) | async size(): Promise<number> {
    method deleteEntry (line 160) | async deleteEntry(id: number): Promise<void> {
    method _removeEntry (line 171) | async _removeEntry(

FILE: packages/workbox-background-sync/src/lib/StorableRequest.ts
  type SerializableProperties (line 13) | type SerializableProperties =
  type RequestData (line 36) | interface RequestData extends MapLikeObject {
  class StorableRequest (line 49) | class StorableRequest {
    method fromRequest (line 59) | static async fromRequest(request: Request): Promise<StorableRequest> {
    method constructor (line 97) | constructor(requestData: RequestData) {
    method toObject (line 127) | toObject(): RequestData {
    method toRequest (line 142) | toRequest(): Request {
    method clone (line 151) | clone(): StorableRequest {

FILE: packages/workbox-broadcast-update/src/BroadcastCacheUpdate.ts
  type BroadcastCacheUpdateOptions (line 32) | interface BroadcastCacheUpdateOptions {
  function defaultPayloadGenerator (line 47) | function defaultPayloadGenerator(
  class BroadcastCacheUpdate (line 65) | class BroadcastCacheUpdate {
    method constructor (line 87) | constructor({
    method notifyIfUpdated (line 128) | async notifyIfUpdated(options: CacheDidUpdateCallbackParam): Promise<v...

FILE: packages/workbox-broadcast-update/src/BroadcastUpdatePlugin.ts
  class BroadcastUpdatePlugin (line 25) | class BroadcastUpdatePlugin implements WorkboxPlugin {
    method constructor (line 41) | constructor(options?: BroadcastCacheUpdateOptions) {

FILE: packages/workbox-broadcast-update/src/utils/constants.ts
  constant CACHE_UPDATED_MESSAGE_TYPE (line 11) | const CACHE_UPDATED_MESSAGE_TYPE = 'CACHE_UPDATED';
  constant CACHE_UPDATED_MESSAGE_META (line 12) | const CACHE_UPDATED_MESSAGE_META = 'workbox-broadcast-update';
  constant NOTIFY_ALL_CLIENTS (line 13) | const NOTIFY_ALL_CLIENTS = true;
  constant DEFAULT_HEADERS_TO_CHECK (line 14) | const DEFAULT_HEADERS_TO_CHECK: string[] = [

FILE: packages/workbox-build/src/generate-sw.ts
  function generateSW (line 62) | async function generateSW(

FILE: packages/workbox-build/src/get-manifest.ts
  function getManifest (line 31) | async function getManifest(

FILE: packages/workbox-build/src/inject-manifest.ts
  function injectManifest (line 53) | async function injectManifest(

FILE: packages/workbox-build/src/lib/additional-manifest-entries-transform.ts
  type AdditionalManifestEntriesTransform (line 12) | type AdditionalManifestEntriesTransform = {
  function additionalManifestEntriesTransform (line 19) | function additionalManifestEntriesTransform(

FILE: packages/workbox-build/src/lib/bundle.ts
  type NameAndContents (line 22) | interface NameAndContents {
  function bundle (line 27) | async function bundle({

FILE: packages/workbox-build/src/lib/cdn-utils.ts
  function getVersionedURL (line 15) | function getVersionedURL(): string {
  function getCDNPrefix (line 19) | function getCDNPrefix() {
  function getModuleURL (line 23) | function getModuleURL(moduleName: string, buildType: BuildType): string {

FILE: packages/workbox-build/src/lib/copy-workbox-libraries.ts
  constant WORKBOX_PREFIX (line 16) | const WORKBOX_PREFIX = 'workbox-';
  constant BUILD_DIR (line 19) | const BUILD_DIR = 'build';
  function copyWorkboxLibraries (line 40) | async function copyWorkboxLibraries(

FILE: packages/workbox-build/src/lib/escape-regexp.ts
  function escapeRegExp (line 10) | function escapeRegExp(str: string): string {

FILE: packages/workbox-build/src/lib/get-composite-details.ts
  function getCompositeDetails (line 13) | function getCompositeDetails(

FILE: packages/workbox-build/src/lib/get-file-details.ts
  type FileDetails (line 18) | interface FileDetails {
  function getFileDetails (line 24) | function getFileDetails({

FILE: packages/workbox-build/src/lib/get-file-hash.ts
  function getFileHash (line 14) | function getFileHash(file: string): string {

FILE: packages/workbox-build/src/lib/get-file-manifest-entries.ts
  function getFileManifestEntries (line 18) | async function getFileManifestEntries({

FILE: packages/workbox-build/src/lib/get-file-size.ts
  function getFileSize (line 13) | function getFileSize(file: string): number | null {

FILE: packages/workbox-build/src/lib/get-source-map-url.ts
  function getSourceMapURL (line 29) | function getSourceMapURL(srcContents: string): string | null {

FILE: packages/workbox-build/src/lib/get-string-details.ts
  function getStringDetails (line 12) | function getStringDetails(url: string, str: string): FileDetails {

FILE: packages/workbox-build/src/lib/get-string-hash.ts
  function getStringHash (line 11) | function getStringHash(input: crypto.BinaryLike): string {

FILE: packages/workbox-build/src/lib/maximum-size-transform.ts
  function maximumSizeTransform (line 13) | function maximumSizeTransform(

FILE: packages/workbox-build/src/lib/modify-url-prefix-transform.ts
  function modifyURLPrefixTransform (line 13) | function modifyURLPrefixTransform(modifyURLPrefix: {

FILE: packages/workbox-build/src/lib/module-registry.ts
  class ModuleRegistry (line 18) | class ModuleRegistry {
    method constructor (line 23) | constructor() {
    method getImportStatements (line 32) | getImportStatements(): Array<string> {
    method getLocalName (line 57) | getLocalName(pkg: string, moduleName: string): string {
    method use (line 67) | use(pkg: string, moduleName: string): string {

FILE: packages/workbox-build/src/lib/no-revision-for-urls-matching-transform.ts
  function noRevisionForURLsMatchingTransform (line 12) | function noRevisionForURLsMatchingTransform(

FILE: packages/workbox-build/src/lib/populate-sw-template.ts
  function populateSWTemplate (line 18) | function populateSWTemplate({

FILE: packages/workbox-build/src/lib/rebase-path.ts
  function rebasePath (line 11) | function rebasePath({

FILE: packages/workbox-build/src/lib/replace-and-update-source-map.ts
  function replaceAndUpdateSourceMap (line 30) | async function replaceAndUpdateSourceMap({

FILE: packages/workbox-build/src/lib/runtime-caching-converter.ts
  function getOptionsString (line 27) | function getOptionsString(
  function runtimeCachingConverter (line 166) | function runtimeCachingConverter(

FILE: packages/workbox-build/src/lib/stringify-without-comments.ts
  function stringifyWithoutComments (line 12) | function stringifyWithoutComments(obj: {[key: string]: any}): string {

FILE: packages/workbox-build/src/lib/transform-manifest.ts
  type ManifestTransformResultWithWarnings (line 73) | interface ManifestTransformResultWithWarnings {
  function transformManifest (line 79) | async function transformManifest({

FILE: packages/workbox-build/src/lib/translate-url-to-sourcemap-paths.ts
  function translateURLToSourcemapPaths (line 14) | function translateURLToSourcemapPaths(

FILE: packages/workbox-build/src/lib/validate-options.ts
  type MethodNames (line 23) | type MethodNames =
  constant DEFAULT_EXCLUDE_VALUE (line 34) | const DEFAULT_EXCLUDE_VALUE = [/\.map$/, /^manifest.*\.js$/];
  class WorkboxConfigError (line 36) | class WorkboxConfigError extends Error {
    method constructor (line 37) | constructor(message?: string) {
  function validate (line 45) | function validate<T>(
  function ensureValidManifestTransforms (line 76) | function ensureValidManifestTransforms(
  function ensureValidNavigationPreloadConfig (line 95) | function ensureValidNavigationPreloadConfig(
  function ensureValidCacheExpiration (line 107) | function ensureValidCacheExpiration(
  function ensureValidRuntimeCachingOrGlobDirectory (line 120) | function ensureValidRuntimeCachingOrGlobDirectory(
  function ensureValidStringHandler (line 138) | function ensureValidStringHandler(
  function validateGenerateSWOptions (line 165) | function validateGenerateSWOptions(input: unknown): GenerateSWOptions {
  function validateGetManifestOptions (line 178) | function validateGetManifestOptions(input: unknown): GetManifestOptions {
  function validateInjectManifestOptions (line 184) | function validateInjectManifestOptions(
  function validateWebpackGenerateSWOptions (line 197) | function validateWebpackGenerateSWOptions(
  function validateWebpackInjectManifestOptions (line 219) | function validateWebpackInjectManifestOptions(

FILE: packages/workbox-build/src/lib/write-sw-using-default-template.ts
  function writeSWUsingDefaultTemplate (line 17) | async function writeSWUsingDefaultTemplate({

FILE: packages/workbox-build/src/types.ts
  type ManifestEntry (line 12) | interface ManifestEntry {
  type StrategyName (line 18) | type StrategyName =
  type RuntimeCaching (line 25) | interface RuntimeCaching {
  type ManifestTransformResult (line 130) | interface ManifestTransformResult {
  type ManifestTransform (line 135) | type ManifestTransform = (
  type BasePartial (line 140) | interface BasePartial {
  type GeneratePartial (line 192) | interface GeneratePartial {
  type RequiredGlobDirectoryPartial (line 369) | interface RequiredGlobDirectoryPartial {
  type OptionalGlobDirectoryPartial (line 377) | interface OptionalGlobDirectoryPartial {
  type GlobPartial (line 385) | interface GlobPartial {
  type InjectPartial (line 421) | interface InjectPartial {
  type WebpackPartial (line 435) | interface WebpackPartial {
  type RequiredSWDestPartial (line 476) | interface RequiredSWDestPartial {
  type WebpackGenerateSWPartial (line 485) | interface WebpackGenerateSWPartial {
  type WebpackInjectManifestPartial (line 498) | interface WebpackInjectManifestPartial {
  type GenerateSWOptions (line 524) | type GenerateSWOptions = BasePartial &
  type GetManifestOptions (line 530) | type GetManifestOptions = BasePartial &
  type InjectManifestOptions (line 534) | type InjectManifestOptions = BasePartial &
  type WebpackGenerateSWOptions (line 540) | type WebpackGenerateSWOptions = BasePartial &
  type WebpackInjectManifestOptions (line 545) | type WebpackInjectManifestOptions = BasePartial &
  type GetManifestResult (line 550) | interface GetManifestResult {
  type BuildResult (line 557) | type BuildResult = Omit<GetManifestResult, 'manifestEntries'> & {
  type FileDetails (line 564) | interface FileDetails {
  type BuildType (line 573) | type BuildType = 'dev' | 'prod';
  type WorkboxPackageJSON (line 578) | interface WorkboxPackageJSON extends PackageJson {

FILE: packages/workbox-cacheable-response/src/CacheableResponse.ts
  type CacheableResponseOptions (line 15) | interface CacheableResponseOptions {
  class CacheableResponse (line 28) | class CacheableResponse {
    method constructor (line 46) | constructor(config: CacheableResponseOptions = {}) {
    method isResponseCacheable (line 88) | isResponseCacheable(response: Response): boolean {

FILE: packages/workbox-cacheable-response/src/CacheableResponsePlugin.ts
  class CacheableResponsePlugin (line 23) | class CacheableResponsePlugin implements WorkboxPlugin {
    method constructor (line 40) | constructor(config: CacheableResponseOptions) {

FILE: packages/workbox-cli/src/app.ts
  type BuildCommand (line 24) | interface BuildCommand {
  function runBuildCommand (line 35) | async function runBuildCommand({command, config, watch}: BuildCommand) {

FILE: packages/workbox-cli/src/bin.ts
  type SupportedFlags (line 19) | interface SupportedFlags extends meow.AnyFlags {

FILE: packages/workbox-cli/src/lib/cleanup-stack-trace.ts
  function cleanupStackTrace (line 13) | function cleanupStackTrace(error: Error, moduleName: string): string {

FILE: packages/workbox-cli/src/lib/questions/ask-config-location.ts
  function askQuestion (line 29) | function askQuestion(): Promise<Answers> {
  function askConfigLocation (line 33) | async function askConfigLocation(): Promise<string> {

FILE: packages/workbox-cli/src/lib/questions/ask-extensions-to-cache.ts
  function getAllFileExtensions (line 27) | async function getAllFileExtensions(globDirectory: string) {
  function askQuestion (line 55) | async function askQuestion(globDirectory: string): Promise<Answers> {
  function askExtensionsToCache (line 79) | async function askExtensionsToCache(

FILE: packages/workbox-cli/src/lib/questions/ask-questions.ts
  type ConfigWithConfigLocation (line 16) | interface ConfigWithConfigLocation {
  function askQuestions (line 23) | async function askQuestions(

FILE: packages/workbox-cli/src/lib/questions/ask-root-of-web-app.ts
  constant ROOT_PROMPT (line 18) | const ROOT_PROMPT = 'Please enter the path to the root of your web app:';
  function getSubdirectories (line 28) | async function getSubdirectories(): Promise<Array<string>> {
  function askQuestion (line 37) | async function askQuestion(): Promise<{
  function askRootOfWebApp (line 75) | async function askRootOfWebApp(): Promise<string> {

FILE: packages/workbox-cli/src/lib/questions/ask-start_url-query-params.ts
  constant START_URL_QUERY_PARAMS_PROMPT (line 16) | const START_URL_QUERY_PARAMS_PROMPT =
  function askQuestion (line 27) | async function askQuestion(): Promise<{
  function askQueryParametersInStartUrl (line 50) | async function askQueryParametersInStartUrl(

FILE: packages/workbox-cli/src/lib/questions/ask-sw-dest.ts
  function askQuestion (line 23) | function askQuestion(defaultDir: string): Promise<Answers> {
  function askSWDest (line 34) | async function askSWDest(defaultDir = '.'): Promise<string> {

FILE: packages/workbox-cli/src/lib/questions/ask-sw-src.ts
  function askQuestion (line 19) | function askQuestion(): Promise<Answers> {
  function askSWSrc (line 31) | async function askSWSrc(): Promise<string | null> {

FILE: packages/workbox-cli/src/lib/read-config.ts
  function readConfig (line 13) | function readConfig(

FILE: packages/workbox-cli/src/lib/run-wizard.ts
  function runWizard (line 16) | async function runWizard(options = {}): Promise<void> {

FILE: packages/workbox-core/src/_private/Deferred.ts
  class Deferred (line 19) | class Deferred<T> {
    method constructor (line 27) | constructor() {

FILE: packages/workbox-core/src/_private/WorkboxError.ts
  class WorkboxError (line 22) | class WorkboxError extends Error {
    method constructor (line 33) | constructor(errorCode: string, details?: MapLikeObject) {

FILE: packages/workbox-core/src/_private/cacheMatchIgnoreParams.ts
  function stripParams (line 10) | function stripParams(fullURL: string, ignoreParams: string[]) {
  function cacheMatchIgnoreParams (line 30) | async function cacheMatchIgnoreParams(

FILE: packages/workbox-core/src/_private/cacheNames.ts
  type CacheNameDetails (line 13) | interface CacheNameDetails {
  type PartialCacheNameDetails (line 21) | interface PartialCacheNameDetails {
  type CacheNameDetailsProp (line 25) | type CacheNameDetailsProp =

FILE: packages/workbox-core/src/_private/canConstructReadableStream.ts
  function canConstructReadableStream (line 23) | function canConstructReadableStream(): boolean {

FILE: packages/workbox-core/src/_private/canConstructResponseFromBodyStream.ts
  function canConstructResponseFromBodyStream (line 22) | function canConstructResponseFromBodyStream(): boolean {

FILE: packages/workbox-core/src/_private/dontWaitFor.ts
  function dontWaitFor (line 15) | function dontWaitFor(promise: Promise<any>): void {

FILE: packages/workbox-core/src/_private/executeQuotaErrorCallbacks.ts
  function executeQuotaErrorCallbacks (line 20) | async function executeQuotaErrorCallbacks(): Promise<void> {

FILE: packages/workbox-core/src/_private/logger.ts
  type WorkerGlobalScope (line 12) | interface WorkerGlobalScope {
  type Window (line 16) | interface Window {
  type LoggerMethods (line 21) | type LoggerMethods =

FILE: packages/workbox-core/src/_private/resultingClientExists.ts
  constant MAX_RETRY_TIME (line 14) | const MAX_RETRY_TIME = 2000;
  function resultingClientExists (line 26) | async function resultingClientExists(

FILE: packages/workbox-core/src/_private/timeout.ts
  function timeout (line 19) | function timeout(ms: number): Promise<unknown> {

FILE: packages/workbox-core/src/_private/waitUntil.ts
  function waitUntil (line 19) | function waitUntil(

FILE: packages/workbox-core/src/cacheNames.ts
  method googleAnalytics (line 28) | get googleAnalytics(): string {
  method precache (line 31) | get precache(): string {
  method prefix (line 34) | get prefix(): string {
  method runtime (line 37) | get runtime(): string {
  method suffix (line 40) | get suffix(): string {

FILE: packages/workbox-core/src/clientsClaim.ts
  function clientsClaim (line 20) | function clientsClaim(): void {

FILE: packages/workbox-core/src/copyResponse.ts
  function copyResponse (line 33) | async function copyResponse(

FILE: packages/workbox-core/src/models/messages/messages.ts
  type LoggableObject (line 11) | interface LoggableObject {
  type MessageMap (line 14) | interface MessageMap {

FILE: packages/workbox-core/src/models/pluginEvents.ts
  type pluginEvents (line 11) | const enum pluginEvents {

FILE: packages/workbox-core/src/registerQuotaErrorCallback.ts
  function registerQuotaErrorCallback (line 23) | function registerQuotaErrorCallback(callback: Function): void {

FILE: packages/workbox-core/src/setCacheNameDetails.ts
  function setCacheNameDetails (line 31) | function setCacheNameDetails(details: PartialCacheNameDetails): void {

FILE: packages/workbox-core/src/skipWaiting.ts
  function skipWaiting (line 23) | function skipWaiting(): void {

FILE: packages/workbox-core/src/types.ts
  type MapLikeObject (line 11) | interface MapLikeObject {
  type PluginState (line 19) | type PluginState = MapLikeObject;
  type RouteMatchCallbackOptions (line 24) | interface RouteMatchCallbackOptions {
  type RouteMatchCallback (line 42) | interface RouteMatchCallback {
  type RouteHandlerCallbackOptions (line 49) | interface RouteHandlerCallbackOptions {
  type ManualHandlerCallbackOptions (line 59) | interface ManualHandlerCallbackOptions {
  type HandlerCallbackOptions (line 64) | type HandlerCallbackOptions =
  type RouteHandlerCallback (line 76) | interface RouteHandlerCallback {
  type ManualHandlerCallback (line 88) | interface ManualHandlerCallback {
  type RouteHandlerObject (line 99) | interface RouteHandlerObject {
  type RouteHandler (line 107) | type RouteHandler = RouteHandlerCallback | RouteHandlerObject;
  type HandlerWillStartCallbackParam (line 109) | interface HandlerWillStartCallbackParam {
  type HandlerWillStartCallback (line 115) | interface HandlerWillStartCallback {
  type CacheDidUpdateCallbackParam (line 119) | interface CacheDidUpdateCallbackParam {
  type CacheDidUpdateCallback (line 128) | interface CacheDidUpdateCallback {
  type CacheKeyWillBeUsedCallbackParam (line 132) | interface CacheKeyWillBeUsedCallbackParam {
  type CacheKeyWillBeUsedCallback (line 140) | interface CacheKeyWillBeUsedCallback {
  type CacheWillUpdateCallbackParam (line 144) | interface CacheWillUpdateCallbackParam {
  type CacheWillUpdateCallback (line 151) | interface CacheWillUpdateCallback {
  type CachedResponseWillBeUsedCallbackParam (line 157) | interface CachedResponseWillBeUsedCallbackParam {
  type CachedResponseWillBeUsedCallback (line 166) | interface CachedResponseWillBeUsedCallback {
  type FetchDidFailCallbackParam (line 172) | interface FetchDidFailCallbackParam {
  type FetchDidFailCallback (line 180) | interface FetchDidFailCallback {
  type FetchDidSucceedCallbackParam (line 184) | interface FetchDidSucceedCallbackParam {
  type FetchDidSucceedCallback (line 191) | interface FetchDidSucceedCallback {
  type RequestWillFetchCallbackParam (line 195) | interface RequestWillFetchCallbackParam {
  type RequestWillFetchCallback (line 201) | interface RequestWillFetchCallback {
  type HandlerWillRespondCallbackParam (line 205) | interface HandlerWillRespondCallbackParam {
  type HandlerWillRespondCallback (line 212) | interface HandlerWillRespondCallback {
  type HandlerDidErrorCallbackParam (line 216) | interface HandlerDidErrorCallbackParam {
  type HandlerDidErrorCallback (line 223) | interface HandlerDidErrorCallback {
  type HandlerDidRespondCallbackParam (line 227) | interface HandlerDidRespondCallbackParam {
  type HandlerDidRespondCallback (line 234) | interface HandlerDidRespondCallback {
  type HandlerDidCompleteCallbackParam (line 238) | interface HandlerDidCompleteCallbackParam {
  type HandlerDidCompleteCallback (line 246) | interface HandlerDidCompleteCallback {
  type WorkboxPlugin (line 254) | interface WorkboxPlugin {
  type WorkboxPluginCallbackParam (line 269) | interface WorkboxPluginCallbackParam {

FILE: packages/workbox-expiration/src/CacheExpiration.ts
  type CacheExpirationConfig (line 18) | interface CacheExpirationConfig {
  class CacheExpiration (line 31) | class CacheExpiration {
    method constructor (line 53) | constructor(cacheName: string, config: CacheExpirationConfig = {}) {
    method expireEntries (line 99) | async expireEntries(): Promise<void> {
    method updateTimestamp (line 153) | async updateTimestamp(url: string): Promise<void> {
    method isURLExpired (line 177) | async isURLExpired(url: string): Promise<boolean> {
    method delete (line 197) | async delete(): Promise<void> {

FILE: packages/workbox-expiration/src/ExpirationPlugin.ts
  type ExpirationPluginOptions (line 22) | interface ExpirationPluginOptions {
  class ExpirationPlugin (line 52) | class ExpirationPlugin implements WorkboxPlugin {
    method constructor (line 68) | constructor(config: ExpirationPluginOptions = {}) {
    method _getCacheExpiration (line 115) | private _getCacheExpiration(cacheName: string): CacheExpiration {
    method _isResponseDateFresh (line 191) | private _isResponseDateFresh(cachedResponse: Response): boolean {
    method _getDateHeaderTimestamp (line 221) | private _getDateHeaderTimestamp(cachedResponse: Response): number | nu...
    method deleteCacheAndMetadata (line 289) | async deleteCacheAndMetadata(): Promise<void> {

FILE: packages/workbox-expiration/src/models/CacheTimestampsModel.ts
  constant DB_NAME (line 12) | const DB_NAME = 'workbox-expiration';
  constant CACHE_OBJECT_STORE (line 13) | const CACHE_OBJECT_STORE = 'cache-entries';
  type CacheTimestampsModelEntry (line 22) | interface CacheTimestampsModelEntry {
  type CacheDbSchema (line 29) | interface CacheDbSchema extends DBSchema {
  class CacheTimestampsModel (line 42) | class CacheTimestampsModel {
    method constructor (line 52) | constructor(cacheName: string) {
    method _upgradeDb (line 63) | private _upgradeDb(db: IDBPDatabase<CacheDbSchema>) {
    method _upgradeDbAndDeleteOldDbs (line 84) | private _upgradeDbAndDeleteOldDbs(db: IDBPDatabase<CacheDbSchema>) {
    method setTimestamp (line 97) | async setTimestamp(url: string, timestamp: number): Promise<void> {
    method getTimestamp (line 125) | async getTimestamp(url: string): Promise<number | undefined> {
    method expireEntries (line 142) | async expireEntries(
    method _getId (line 202) | private _getId(url: string): string {
    method getDb (line 214) | private async getDb() {

FILE: packages/workbox-google-analytics/src/initialize.ts
  type GoogleAnalyticsInitializeOptions (line 31) | interface GoogleAnalyticsInitializeOptions {

FILE: packages/workbox-google-analytics/src/utils/constants.ts
  constant QUEUE_NAME (line 11) | const QUEUE_NAME = 'workbox-google-analytics';
  constant MAX_RETENTION_TIME (line 12) | const MAX_RETENTION_TIME = 60 * 48;
  constant GOOGLE_ANALYTICS_HOST (line 13) | const GOOGLE_ANALYTICS_HOST = 'www.google-analytics.com';
  constant GTM_HOST (line 14) | const GTM_HOST = 'www.googletagmanager.com';
  constant ANALYTICS_JS_PATH (line 15) | const ANALYTICS_JS_PATH = '/analytics.js';
  constant GTAG_JS_PATH (line 16) | const GTAG_JS_PATH = '/gtag/js';
  constant GTM_JS_PATH (line 17) | const GTM_JS_PATH = '/gtm.js';
  constant COLLECT_DEFAULT_PATH (line 18) | const COLLECT_DEFAULT_PATH = '/collect';
  constant COLLECT_PATHS_REGEX (line 24) | const COLLECT_PATHS_REGEX = /^\/(\w+\/)?collect/;

FILE: packages/workbox-navigation-preload/src/disable.ts
  function disable (line 21) | function disable(): void {

FILE: packages/workbox-navigation-preload/src/enable.ts
  function enable (line 26) | function enable(headerValue?: string): void {

FILE: packages/workbox-navigation-preload/src/index.ts
  type NavigationPreloadState (line 15) | interface NavigationPreloadState {
  type NavigationPreloadManager (line 20) | interface NavigationPreloadManager {
  type ServiceWorkerRegistration (line 28) | interface ServiceWorkerRegistration {

FILE: packages/workbox-navigation-preload/src/isSupported.ts
  function isSupported (line 20) | function isSupported(): boolean {

FILE: packages/workbox-precaching/src/PrecacheController.ts
  type ServiceWorkerGlobalScope (line 30) | interface ServiceWorkerGlobalScope {
  type PrecacheControllerOptions (line 35) | interface PrecacheControllerOptions {
  class PrecacheController (line 46) | class PrecacheController {
    method constructor (line 71) | constructor({
    method strategy (line 94) | get strategy(): Strategy {
    method precache (line 108) | precache(entries: Array<PrecacheEntry | string>): void {
    method addToCacheList (line 125) | addToCacheList(entries: Array<PrecacheEntry | string>): void {
    method install (line 199) | install(event: ExtendableEvent): Promise<InstallResult> {
    method activate (line 247) | activate(event: ExtendableEvent): Promise<CleanupResult> {
    method getURLsToCacheKeys (line 277) | getURLsToCacheKeys(): Map<string, string> {
    method getCachedURLs (line 287) | getCachedURLs(): Array<string> {
    method getCacheKeyForURL (line 300) | getCacheKeyForURL(url: string): string | undefined {
    method getIntegrityForCacheKey (line 310) | getIntegrityForCacheKey(cacheKey: string): string | undefined {
    method matchPrecache (line 332) | async matchPrecache(
    method createHandlerBoundToURL (line 352) | createHandlerBoundToURL(url: string): RouteHandlerCallback {

FILE: packages/workbox-precaching/src/PrecacheFallbackPlugin.ts
  class PrecacheFallbackPlugin (line 30) | class PrecacheFallbackPlugin implements WorkboxPlugin {
    method constructor (line 44) | constructor({

FILE: packages/workbox-precaching/src/PrecacheRoute.ts
  class PrecacheRoute (line 32) | class PrecacheRoute extends Route {
    method constructor (line 49) | constructor(

FILE: packages/workbox-precaching/src/PrecacheStrategy.ts
  type PrecacheStrategyOptions (line 20) | interface PrecacheStrategyOptions extends StrategyOptions {
  class PrecacheStrategy (line 36) | class PrecacheStrategy extends Strategy {
    method cacheWillUpdate (line 40) | async cacheWillUpdate({response}) {
    method cacheWillUpdate (line 50) | async cacheWillUpdate({response}) {
    method constructor (line 72) | constructor(options: PrecacheStrategyOptions = {}) {
    method _handle (line 93) | async _handle(request: Request, handler: StrategyHandler): Promise<Res...
    method _handleFetch (line 110) | async _handleFetch(
    method _handleInstall (line 207) | async _handleInstall(
    method _useDefaultCacheabilityPluginIfNeeded (line 257) | _useDefaultCacheabilityPluginIfNeeded(): void {

FILE: packages/workbox-precaching/src/_types.ts
  type InstallResult (line 11) | interface InstallResult {
  type CleanupResult (line 16) | interface CleanupResult {
  type PrecacheEntry (line 20) | interface PrecacheEntry {
  type PrecacheRouteOptions (line 26) | interface PrecacheRouteOptions {
  type urlManipulation (line 33) | type urlManipulation = ({url}: {url: URL}) => URL[];

FILE: packages/workbox-precaching/src/addPlugins.ts
  function addPlugins (line 20) | function addPlugins(plugins: WorkboxPlugin[]): void {

FILE: packages/workbox-precaching/src/addRoute.ts
  function addRoute (line 31) | function addRoute(options?: PrecacheRouteOptions): void {

FILE: packages/workbox-precaching/src/cleanupOutdatedCaches.ts
  function cleanupOutdatedCaches (line 20) | function cleanupOutdatedCaches(): void {

FILE: packages/workbox-precaching/src/createHandlerBoundToURL.ts
  function createHandlerBoundToURL (line 30) | function createHandlerBoundToURL(url: string): RouteHandlerCallback {

FILE: packages/workbox-precaching/src/getCacheKeyForURL.ts
  function getCacheKeyForURL (line 31) | function getCacheKeyForURL(url: string): string | undefined {

FILE: packages/workbox-precaching/src/matchPrecache.ts
  function matchPrecache (line 28) | function matchPrecache(

FILE: packages/workbox-precaching/src/precache.ts
  function precache (line 32) | function precache(entries: Array<PrecacheEntry | string>): void {

FILE: packages/workbox-precaching/src/precacheAndRoute.ts
  function precacheAndRoute (line 28) | function precacheAndRoute(

FILE: packages/workbox-precaching/src/utils/PrecacheCacheKeyPlugin.ts
  class PrecacheCacheKeyPlugin (line 21) | class PrecacheCacheKeyPlugin implements WorkboxPlugin {
    method constructor (line 24) | constructor({precacheController}: {precacheController: PrecacheControl...

FILE: packages/workbox-precaching/src/utils/PrecacheInstallReportPlugin.ts
  class PrecacheInstallReportPlugin (line 19) | class PrecacheInstallReportPlugin implements WorkboxPlugin {

FILE: packages/workbox-precaching/src/utils/createCacheKey.ts
  type CacheKey (line 13) | interface CacheKey {
  constant REVISION_SEARCH_PARAM (line 19) | const REVISION_SEARCH_PARAM = '__WB_REVISION__';
  function createCacheKey (line 30) | function createCacheKey(entry: PrecacheEntry | string): CacheKey {

FILE: packages/workbox-precaching/src/utils/deleteOutdatedCaches.ts
  constant SUBSTRING_TO_FIND (line 14) | const SUBSTRING_TO_FIND = '-precache-';

FILE: packages/workbox-precaching/src/utils/printCleanupDetails.ts
  function printCleanupDetails (line 34) | function printCleanupDetails(deletedURLs: string[]): void {

FILE: packages/workbox-precaching/src/utils/printInstallDetails.ts
  function _nestedGroup (line 18) | function _nestedGroup(groupTitle: string, urls: string[]): void {
  function printInstallDetails (line 39) | function printInstallDetails(

FILE: packages/workbox-precaching/src/utils/removeIgnoredSearchParams.ts
  function removeIgnoredSearchParams (line 23) | function removeIgnoredSearchParams(

FILE: packages/workbox-range-requests/src/RangeRequestsPlugin.ts
  class RangeRequestsPlugin (line 22) | class RangeRequestsPlugin implements WorkboxPlugin {

FILE: packages/workbox-range-requests/src/createPartialResponse.ts
  function createPartialResponse (line 34) | async function createPartialResponse(

FILE: packages/workbox-range-requests/src/utils/calculateEffectiveBoundaries.ts
  function calculateEffectiveBoundaries (line 23) | function calculateEffectiveBoundaries(

FILE: packages/workbox-range-requests/src/utils/parseRangeHeader.ts
  function parseRangeHeader (line 21) | function parseRangeHeader(rangeHeader: string): {start?: number; end?: n...

FILE: packages/workbox-recipes/src/googleFontsCache.ts
  type GoogleFontCacheOptions (line 16) | interface GoogleFontCacheOptions {
  function googleFontsCache (line 32) | function googleFontsCache(options: GoogleFontCacheOptions = {}): void {

FILE: packages/workbox-recipes/src/imageCache.ts
  type ImageCacheOptions (line 21) | interface ImageCacheOptions {
  function imageCache (line 43) | function imageCache(options: ImageCacheOptions = {}): void {

FILE: packages/workbox-recipes/src/offlineFallback.ts
  type OfflineFallbackOptions (line 14) | interface OfflineFallbackOptions {
  function offlineFallback (line 33) | function offlineFallback(options: OfflineFallbackOptions = {}): void {

FILE: packages/workbox-recipes/src/pageCache.ts
  type PageCacheOptions (line 20) | interface PageCacheOptions {
  function pageCache (line 40) | function pageCache(options: PageCacheOptions = {}): void {

FILE: packages/workbox-recipes/src/staticResourceCache.ts
  type StaticResourceOptions (line 20) | interface StaticResourceOptions {
  function staticResourceCache (line 38) | function staticResourceCache(options: StaticResourceOptions = {}): void {

FILE: packages/workbox-recipes/src/warmStrategyCache.ts
  type WarmStrategyCacheOptions (line 5) | interface WarmStrategyCacheOptions {
  function warmStrategyCache (line 20) | function warmStrategyCache(options: WarmStrategyCacheOptions): void {

FILE: packages/workbox-routing/src/NavigationRoute.ts
  type NavigationRouteMatchOptions (line 17) | interface NavigationRouteMatchOptions {
  class NavigationRoute (line 37) | class NavigationRoute extends Route {
    method constructor (line 65) | constructor(
    method _match (line 103) | private _match({url, request}: RouteMatchCallbackOptions): boolean {

FILE: packages/workbox-routing/src/RegExpRoute.ts
  class RegExpRoute (line 33) | class RegExpRoute extends Route {
    method constructor (line 47) | constructor(regExp: RegExp, handler: RouteHandler, method?: HTTPMethod) {

FILE: packages/workbox-routing/src/Route.ts
  class Route (line 28) | class Route {
    method constructor (line 45) | constructor(
    method setCatchHandler (line 75) | setCatchHandler(handler: RouteHandler): void {

FILE: packages/workbox-routing/src/Router.ts
  type RequestArgs (line 25) | type RequestArgs = string | [string, RequestInit?];
  type CacheURLsMessageData (line 27) | interface CacheURLsMessageData {
  class Router (line 51) | class Router {
    method constructor (line 59) | constructor() {
    method routes (line 69) | get routes(): Map<HTTPMethod, Route[]> {
    method addFetchListener (line 77) | addFetchListener(): void {
    method addCacheListener (line 110) | addCacheListener(): void {
    method handleRequest (line 160) | handleRequest({
    method findMatchingRoute (line 328) | findMatchingRoute({
    method setDefaultHandler (line 398) | setDefaultHandler(
    method setCatchHandler (line 412) | setCatchHandler(handler: RouteHandler): void {
    method registerRoute (line 421) | registerRoute(route: Route): void {
    method unregisterRoute (line 473) | unregisterRoute(route: Route): void {

FILE: packages/workbox-routing/src/registerRoute.ts
  function registerRoute (line 38) | function registerRoute(

FILE: packages/workbox-routing/src/setCatchHandler.ts
  function setCatchHandler (line 24) | function setCatchHandler(handler: RouteHandler): void {

FILE: packages/workbox-routing/src/setDefaultHandler.ts
  function setDefaultHandler (line 27) | function setDefaultHandler(handler: RouteHandler): void {

FILE: packages/workbox-routing/src/utils/constants.ts
  type HTTPMethod (line 11) | type HTTPMethod = 'DELETE' | 'GET' | 'HEAD' | 'PATCH' | 'POST' | 'PUT';

FILE: packages/workbox-strategies/src/CacheFirst.ts
  class CacheFirst (line 32) | class CacheFirst extends Strategy {
    method _handle (line 40) | async _handle(request: Request, handler: StrategyHandler): Promise<Res...

FILE: packages/workbox-strategies/src/CacheOnly.ts
  class CacheOnly (line 30) | class CacheOnly extends Strategy {
    method _handle (line 38) | async _handle(request: Request, handler: StrategyHandler): Promise<Res...

FILE: packages/workbox-strategies/src/NetworkFirst.ts
  type NetworkFirstOptions (line 19) | interface NetworkFirstOptions extends StrategyOptions {
  class NetworkFirst (line 39) | class NetworkFirst extends Strategy {
    method constructor (line 61) | constructor(options: NetworkFirstOptions = {}) {
    method _handle (line 90) | async _handle(request: Request, handler: StrategyHandler): Promise<Res...
    method _getTimeoutPromise (line 161) | private _getTimeoutPromise({
    method _getNetworkPromise (line 205) | async _getNetworkPromise({

FILE: packages/workbox-strategies/src/NetworkOnly.ts
  type NetworkOnlyOptions (line 19) | interface NetworkOnlyOptions
  class NetworkOnly (line 37) | class NetworkOnly extends Strategy {
    method constructor (line 51) | constructor(options: NetworkOnlyOptions = {}) {
    method _handle (line 64) | async _handle(request: Request, handler: StrategyHandler): Promise<Res...

FILE: packages/workbox-strategies/src/StaleWhileRevalidate.ts
  class StaleWhileRevalidate (line 40) | class StaleWhileRevalidate extends Strategy {
    method constructor (line 54) | constructor(options: StrategyOptions = {}) {
    method _handle (line 71) | async _handle(request: Request, handler: StrategyHandler): Promise<Res...

FILE: packages/workbox-strategies/src/Strategy.ts
  type StrategyOptions (line 23) | interface StrategyOptions {
  method constructor (line 68) | constructor(options: StrategyOptions = {}) {
  method handle (line 122) | handle(options: FetchEvent | HandlerCallbackOptions): Promise<Response> {
  method handleAll (line 149) | handleAll(
  method _getResponse (line 181) | async _getResponse(
  method _awaitComplete (line 227) | async _awaitComplete(

FILE: packages/workbox-strategies/src/StrategyHandler.ts
  function toRequest (line 27) | function toRequest(input: RequestInfo) {
  class StrategyHandler (line 40) | class StrategyHandler {
    method constructor (line 70) | constructor(strategy: Strategy, options: HandlerCallbackOptions) {
    method fetch (line 148) | async fetch(input: RequestInfo): Promise<Response> {
    method fetchAndCachePut (line 253) | async fetchAndCachePut(input: RequestInfo): Promise<Response> {
    method cacheMatch (line 274) | async cacheMatch(key: RequestInfo): Promise<Response | undefined> {
    method cachePut (line 320) | async cachePut(key: RequestInfo, response: Response): Promise<boolean> {
    method getCacheKey (line 437) | async getCacheKey(
    method hasCallback (line 469) | hasCallback<C extends keyof WorkboxPlugin>(name: C): boolean {
    method runCallbacks (line 494) | async runCallbacks<C extends keyof NonNullable<WorkboxPlugin>>(
    method iterateCallbacks (line 514) | *iterateCallbacks<C extends keyof WorkboxPlugin>(
    method waitUntil (line 547) | waitUntil<T>(promise: Promise<T>): Promise<T> {
    method doneWaiting (line 562) | async doneWaiting(): Promise<void> {
    method destroy (line 577) | destroy(): void {
    method _ensureResponseSafeToCache (line 591) | async _ensureResponseSafeToCache(

FILE: packages/workbox-strategies/src/index.ts
  type FetchEvent (line 20) | interface FetchEvent {

FILE: packages/workbox-streams/src/_types.ts
  type StreamSource (line 11) | type StreamSource = Response | ReadableStream | BodyInit;

FILE: packages/workbox-streams/src/concatenate.ts
  function _getReaderFromSource (line 26) | function _getReaderFromSource(
  function concatenate (line 55) | function concatenate(sourcePromises: Promise<StreamSource>[]): {

FILE: packages/workbox-streams/src/concatenateToResponse.ts
  function concatenateToResponse (line 31) | function concatenateToResponse(

FILE: packages/workbox-streams/src/isSupported.ts
  function isSupported (line 23) | function isSupported(): boolean {

FILE: packages/workbox-streams/src/strategy.ts
  type StreamsHandlerCallback (line 20) | interface StreamsHandlerCallback {
  function strategy (line 42) | function strategy(

FILE: packages/workbox-streams/src/utils/createHeaders.ts
  function createHeaders (line 25) | function createHeaders(headersInit = {}): Headers {

FILE: packages/workbox-sw/controllers/WorkboxSW.mjs
  constant CDN_PATH (line 11) | const CDN_PATH = `WORKBOX_CDN_ROOT_URL`;
  constant MODULE_KEY_TO_NAME_MAPPING (line 13) | const MODULE_KEY_TO_NAME_MAPPING = {
  class WorkboxSW (line 100) | class WorkboxSW {
    method constructor (line 106) | constructor() {
    method setConfig (line 150) | setConfig(options = {}) {
    method loadModule (line 170) | loadModule(moduleName) {
    method _getImportPath (line 194) | _getImportPath(moduleName) {

FILE: packages/workbox-webpack-plugin/src/generate-sw.ts
  type GenerateSWConfig (line 27) | interface GenerateSWConfig extends WebpackGenerateSWOptions {
  class GenerateSW (line 71) | class GenerateSW {
    method constructor (line 78) | constructor(config: GenerateSWConfig = {}) {
    method propagateWebpackConfig (line 88) | propagateWebpackConfig(compiler: webpack.Compiler): void {
    method apply (line 105) | apply(compiler: webpack.Compiler): void {
    method addAssets (line 147) | async addAssets(compilation: webpack.Compilation): Promise<void> {

FILE: packages/workbox-webpack-plugin/src/inject-manifest.ts
  class InjectManifest (line 56) | class InjectManifest {
    method constructor (line 63) | constructor(config: WebpackInjectManifestOptions) {
    method propagateWebpackConfig (line 73) | propagateWebpackConfig(compiler: webpack.Compiler): void {
    method apply (line 91) | apply(compiler: webpack.Compiler): void {
    method performChildCompilation (line 142) | async performChildCompilation(
    method addSrcToAssets (line 200) | addSrcToAssets(
    method handleMake (line 217) | async handleMake(
    method addAssets (line 260) | async addAssets(compilation: webpack.Compilation): Promise<void> {

FILE: packages/workbox-webpack-plugin/src/lib/get-asset-hash.ts
  function getAssetHash (line 18) | function getAssetHash(asset: Asset): string | null {

FILE: packages/workbox-webpack-plugin/src/lib/get-manifest-entries-from-compilation.ts
  function checkConditions (line 38) | function checkConditions(
  function getNamesOfAssetsInChunkOrGroup (line 73) | function getNamesOfAssetsInChunkOrGroup(
  function getNamesOfAssetsInChunk (line 105) | function getNamesOfAssetsInChunk(chunk: Chunk): Array<string> {
  function filterAssets (line 129) | function filterAssets(
  function getManifestEntriesFromCompilation (line 215) | async function getManifestEntriesFromCompilation(

FILE: packages/workbox-webpack-plugin/src/lib/get-script-files-for-chunks.ts
  function getScriptFilesForChunks (line 14) | function getScriptFilesForChunks(

FILE: packages/workbox-webpack-plugin/src/lib/get-sourcemap-asset-name.ts
  function getSourcemapAssetName (line 31) | function getSourcemapAssetName(

FILE: packages/workbox-webpack-plugin/src/lib/relative-to-output-path.ts
  function relativeToOutputPath (line 21) | function relativeToOutputPath(

FILE: packages/workbox-webpack-plugin/src/lib/resolve-webpack-url.ts
  function resolveWebpackURL (line 22) | function resolveWebpackURL(

FILE: packages/workbox-window/src/Workbox.ts
  constant WAITING_TIMEOUT_DURATION (line 24) | const WAITING_TIMEOUT_DURATION = 200;
  constant REGISTRATION_TIMEOUT_DURATION (line 28) | const REGISTRATION_TIMEOUT_DURATION = 60000;
  constant SKIP_WAITING_MESSAGE (line 32) | const SKIP_WAITING_MESSAGE = {type: 'SKIP_WAITING'};
  class Workbox (line 46) | class Workbox extends WorkboxEventTarget {
    method constructor (line 78) | constructor(scriptURL: string | TrustedScriptURL, registerOptions: {} ...
    method register (line 100) | async register({immediate = false} = {}): Promise<
    method update (line 231) | async update(): Promise<void> {
    method active (line 255) | get active(): Promise<ServiceWorker> {
    method controlling (line 271) | get controlling(): Promise<ServiceWorker> {
    method getSW (line 290) | getSW(): Promise<ServiceWorker> {
    method messageSW (line 313) | async messageSW(data: object): Promise<any> {
    method messageSkipWaiting (line 325) | messageSkipWaiting(): void {
    method _getControllingSWIfCompatible (line 338) | private _getControllingSWIfCompatible() {
    method _registerScript (line 356) | private async _registerScript() {

FILE: packages/workbox-window/src/messageSW.ts
  function messageSW (line 27) | function messageSW(sw: ServiceWorker, data: {}): Promise<any> {

FILE: packages/workbox-window/src/utils/WorkboxEvent.ts
  class WorkboxEvent (line 18) | class WorkboxEvent<K extends keyof WorkboxEventMap> {
    method constructor (line 24) | constructor(
  type WorkboxMessageEvent (line 32) | interface WorkboxMessageEvent extends WorkboxEvent<'message'> {
  type WorkboxLifecycleEvent (line 38) | interface WorkboxLifecycleEvent
  type WorkboxLifecycleWaitingEvent (line 43) | interface WorkboxLifecycleWaitingEvent extends WorkboxLifecycleEvent {
  type WorkboxLifecycleEventMap (line 47) | interface WorkboxLifecycleEventMap {
  type WorkboxEventMap (line 57) | interface WorkboxEventMap extends WorkboxLifecycleEventMap {

FILE: packages/workbox-window/src/utils/WorkboxEventTarget.ts
  type ListenerCallback (line 11) | type ListenerCallback = (event: WorkboxEvent<any>) => any;
  class WorkboxEventTarget (line 19) | class WorkboxEventTarget {
    method addEventListener (line 30) | addEventListener<K extends keyof WorkboxEventMap>(
    method removeEventListener (line 43) | removeEventListener<K extends keyof WorkboxEventMap>(
    method dispatchEvent (line 54) | dispatchEvent(event: WorkboxEvent<any>): void {
    method _getEventListenersByType (line 71) | private _getEventListenersByType(type: keyof WorkboxEventMap) {

FILE: packages/workbox-window/src/utils/urlsMatch.ts
  function urlsMatch (line 20) | function urlsMatch(url1: string, url2: string): boolean {

FILE: test/workbox-background-sync/sw/lib/test-QueueDb.mjs
  method blocked (line 126) | blocked() {
  method upgrade (line 136) | upgrade(db) {
  method blocked (line 180) | blocked() {
  method blocked (line 198) | blocked() {
  method upgrade (line 208) | upgrade(db) {
  method blocked (line 247) | blocked() {
  method blocked (line 265) | blocked() {

FILE: test/workbox-background-sync/sw/test-BackgroundSyncPlugin.mjs
  function getUniqueQueueName (line 13) | function getUniqueQueueName() {

FILE: test/workbox-background-sync/sw/test-Queue.mjs
  constant MINUTES (line 16) | const MINUTES = 60 * 1000;

FILE: test/workbox-build/node/lib/additional-manifest-entries-transform.js
  function getManifest (line 17) | function getManifest() {

FILE: test/workbox-build/node/lib/modify-url-prefix-transform.js
  function getManifest (line 17) | function getManifest() {

FILE: test/workbox-build/node/lib/runtime-caching-converter.js
  function validate (line 30) | function validate(runtimeCachingOptions, convertedOptions) {

FILE: test/workbox-build/node/lib/validate-options.js
  class AJVFailsValidation (line 13) | class AJVFailsValidation {
    method compile (line 14) | compile() {
    method addKeyword (line 19) | addKeyword() {
  class AJVPassesValidation (line 24) | class AJVPassesValidation {
    method compile (line 25) | compile() {
    method addKeyword (line 28) | addKeyword() {

FILE: test/workbox-cli/node/lib/questions/ask-config-location.js
  constant MODULE_PATH (line 16) | const MODULE_PATH =
  constant QUESTION_NAME (line 20) | const QUESTION_NAME = 'configLocation';

FILE: test/workbox-cli/node/lib/questions/ask-extensions-to-cache.js
  constant MODULE_PATH (line 16) | const MODULE_PATH =
  constant QUESTION_NAME (line 20) | const QUESTION_NAME = 'globPatterns';
  constant GLOB_DIRECTORY (line 21) | const GLOB_DIRECTORY = '/path/to/fake';
  constant SINGLE_EXTENSION (line 22) | const SINGLE_EXTENSION = 'js';
  constant MULTIPLE_EXTENSIONS (line 23) | const MULTIPLE_EXTENSIONS = ['html', 'js'];

FILE: test/workbox-cli/node/lib/questions/ask-questions.js
  constant MODULE_PATH (line 13) | const MODULE_PATH =

FILE: test/workbox-cli/node/lib/questions/ask-root-of-web-app.js
  constant MODULE_PATH (line 16) | const MODULE_PATH =
  constant DIRECTORY (line 22) | const DIRECTORY = '/path/to/directory';
  constant CHILD_DIRECTORY (line 23) | const CHILD_DIRECTORY = '/path/to/directory/child';
  constant CHILD_DIRECTORY_WHITE_SPACE (line 24) | const CHILD_DIRECTORY_WHITE_SPACE = '/path/to/directory/   child';
  constant CHILD_DIRECTORY_BLANK (line 25) | const CHILD_DIRECTORY_BLANK = '  ';

FILE: test/workbox-cli/node/lib/questions/ask-start_url-query-params.js
  constant MODULE_PATH (line 19) | const MODULE_PATH =
  constant DEFAULT_IGNORED_URL_PARAMETERS (line 28) | const DEFAULT_IGNORED_URL_PARAMETERS = constants.ignoreURLParametersMatc...

FILE: test/workbox-cli/node/lib/questions/ask-sw-dest.js
  constant MODULE_PATH (line 16) | const MODULE_PATH =
  constant QUESTION_NAME (line 20) | const QUESTION_NAME = 'swDest';

FILE: test/workbox-cli/node/lib/questions/ask-sw-src.js
  constant MODULE_PATH (line 12) | const MODULE_PATH =
  constant QUESTION_NAME (line 16) | const QUESTION_NAME = 'swSrc';

FILE: test/workbox-cli/node/lib/run-wizard.js
  constant MODULE_PATH (line 14) | const MODULE_PATH = '../../../../packages/workbox-cli/build/lib/run-wiza...

FILE: test/workbox-core/sw/_private/test-assert.mjs
  class TestClass (line 51) | class TestClass {}
  class TestClass (line 67) | class TestClass {}
  class NotTestClass (line 68) | class NotTestClass {}
  class TestClass (line 86) | class TestClass {}
  class Example (line 128) | class Example {}
  class Example (line 142) | class Example {}

FILE: test/workbox-google-analytics/sw/test-initialize.mjs
  constant PAYLOAD (line 25) | const PAYLOAD = 'v=1&t=pageview&tid=UA-12345-1&cid=1&dp=%2F';

FILE: test/workbox-precaching/sw/resetDefaultPrecacheController.mjs
  function resetDefaultPrecacheController (line 11) | function resetDefaultPrecacheController() {

FILE: test/workbox-precaching/sw/test-PrecacheController.mjs
  function createFetchEvent (line 16) | function createFetchEvent(url) {
  class TestPlugin (line 600) | class TestPlugin {
    method cacheWillUpdate (line 601) | cacheWillUpdate({response}) {

FILE: test/workbox-precaching/sw/test-PrecacheRoute.mjs
  function createMatchParams (line 12) | function createMatchParams(path) {

FILE: test/workbox-precaching/sw/test-PrecacheStrategy.mjs
  function createFetchEvent (line 16) | function createFetchEvent(url, requestInit) {

FILE: test/workbox-precaching/sw/test-addRoute.mjs
  function getAddedFetchListeners (line 15) | function getAddedFetchListeners() {

FILE: test/workbox-range-requests/sw/test-createPartialResponse.mjs
  function constructBlob (line 14) | function constructBlob(length) {

FILE: test/workbox-range-requests/sw/utils/test-calculateEffectiveBoundaries.mjs
  function constructBlob (line 12) | function constructBlob(length) {

FILE: test/workbox-strategies/sw/test-Strategy.mjs
  class FetchStrategy (line 13) | class FetchStrategy extends Strategy {
    method _handle (line 14) | _handle(request, handler) {
  class LongWaitUntilStrategy (line 19) | class LongWaitUntilStrategy extends Strategy {
    method _handle (line 20) | _handle(request, handler) {
  class EmptyStrategy (line 26) | class EmptyStrategy extends Strategy {
    method _handle (line 27) | _handle(request, handler) {
  class ErrorStrategy (line 32) | class ErrorStrategy extends Strategy {
    method _handle (line 33) | _handle(request, handler) {
  class HandlerThrowsStrategy (line 39) | class HandlerThrowsStrategy extends Strategy {
    method constructor (line 40) | constructor(options) {
    method _handle (line 44) | async _handle(request, handler) {
  class HandlerReturnsUndefinedStrategy (line 49) | class HandlerReturnsUndefinedStrategy extends Strategy {
    method _handle (line 50) | async _handle(request, handler) {
  class HandlerReturnsResponseErrorStrategy (line 55) | class HandlerReturnsResponseErrorStrategy extends Strategy {
    method _handle (line 56) | async _handle(request, handler) {
  class ExtendingStrategy (line 61) | class ExtendingStrategy extends FetchStrategy {
    method constructor (line 62) | constructor(options) {
    method _handle (line 66) | async _handle(request, handler) {
  function generateOptions (line 75) | function generateOptions() {
  method handlerWillStart (line 106) | handlerWillStart() {}
  method handlerWillStart (line 126) | handlerWillStart() {}

FILE: test/workbox-strategies/sw/test-StrategyHandler.mjs
  class TestStrategy (line 21) | class TestStrategy extends Strategy {
    method _handle (line 22) | _handle() {
  method handlerWillStart (line 1245) | handlerWillStart({event, request}) {
  method handlerWillStart (line 1253) | handlerWillStart({event, request}) {
  method cacheKeyWillBeUsed (line 1274) | cacheKeyWillBeUsed({mode, request}) {
  method cacheKeyWillBeUsed (line 1279) | cacheKeyWillBeUsed({mode, request}) {
  method cacheKeyWillBeUsed (line 1286) | cacheKeyWillBeUsed({mode, request}) {
  method cacheKeyWillBeUsed (line 1305) | cacheKeyWillBeUsed({mode, request}) {

FILE: test/workbox-streams/sw/test-isSupported.mjs
  method start (line 14) | start() {}

FILE: test/workbox-webpack-plugin/node/v4/lib/create-webpack-asset-plugin.js
  class CreateWebpackAssetPlugin (line 13) | class CreateWebpackAssetPlugin {
    method constructor (line 14) | constructor(name) {
    method apply (line 21) | apply(compiler) {

FILE: test/workbox-webpack-plugin/node/v5/lib/create-webpack-asset-plugin.js
  class CreateWebpackAssetPlugin (line 11) | class CreateWebpackAssetPlugin {
    method constructor (line 12) | constructor(name) {
    method apply (line 19) | apply(compiler) {
Condensed preview — 717 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,084K chars).
[
  {
    "path": ".gitattributes",
    "chars": 34,
    "preview": "*.js text eol=lf\n*.mjs text eol=lf"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "chars": 575,
    "preview": "Welcome! Please use this template for reporting bugs or requesting features. For questions about using Workbox, the best"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 223,
    "preview": "**Prior to creating a pull request, please follow all the steps in the [contributing guide](https://github.com/GoogleChr"
  },
  {
    "path": ".github/workflows/pull-request.yml",
    "chars": 1362,
    "preview": "name: Test Suite\n\non: [pull_request]\n\njobs:\n  Node_Tests_Windows:\n    runs-on: windows-latest\n\n    steps:\n      - uses: "
  },
  {
    "path": ".github/workflows/scorecards-analysis.yml",
    "chars": 1894,
    "preview": "name: Scorecards supply-chain security\non:\n  # Only the default branch is supported.\n  branch_protection_rule:\n  schedul"
  },
  {
    "path": ".gitignore",
    "chars": 1114,
    "preview": ".DS_Store\nbuild\nlerna-debug.log\nnode_modules\nnpm-debug.log\npackages/**/LICENSE\ntemp\ntmp-*\n!packages/workbox-cli/test/sta"
  },
  {
    "path": ".husky/.gitignore",
    "chars": 2,
    "preview": "_\n"
  },
  {
    "path": ".husky/pre-commit",
    "chars": 178,
    "preview": "#!/bin/sh\n\n# Please see https://typicode.github.io/husky/#/?id=command-not-found\n# if you have trouble running this comm"
  },
  {
    "path": ".husky/pre-push",
    "chars": 171,
    "preview": "#!/bin/sh\n\n# Please see https://typicode.github.io/husky/#/?id=command-not-found\n# if you have trouble running this comm"
  },
  {
    "path": ".ncurc.js",
    "chars": 388,
    "preview": "// We use `npx npm-check-updates` to find updates to dependencies.\n// Some dependencies have breaking changes that we ca"
  },
  {
    "path": ".nvmrc",
    "chars": 3,
    "preview": "20\n"
  },
  {
    "path": ".prettierignore",
    "chars": 277,
    "preview": "_version.ts\n.nyc_output\n.vscode\n*.hbs\n*.log\nbuild\ncoverage\ndocs\ngenerated-release-files\nnode_modules\npackage-lock.json\np"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 205,
    "preview": "# Code of Conduct\n\nAll Google open source projects are covered by our [community guidelines](https://opensource.google/c"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 3595,
    "preview": "# How to become a contributor and submit your own code\n\n## Contributor License Agreements\n\nWe'd love to accept your patc"
  },
  {
    "path": "LICENSE",
    "chars": 1050,
    "preview": "Copyright 2018 Google LLC\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software"
  },
  {
    "path": "README.md",
    "chars": 1453,
    "preview": "<img src='https://user-images.githubusercontent.com/110953/28352645-7a8a66d8-6c0c-11e7-83af-752609e7e072.png' width='500"
  },
  {
    "path": "cdn-details.json",
    "chars": 109,
    "preview": "{\n  \"origin\": \"https://storage.googleapis.com\",\n  \"bucketName\": \"workbox-cdn\",\n  \"releasesDir\": \"releases\"\n}\n"
  },
  {
    "path": "demos/README.md",
    "chars": 200,
    "preview": "# workbox-module-demos\n\nContains sample demos that are deployed to Glitch at https://glitch.com/@philkrie/workbox-demos "
  },
  {
    "path": "demos/src/workbox-background-sync-demo/index.html",
    "chars": 2466,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <title>workbox-background-sync demo</title>\n    <meta\n      name=\"workbox-"
  },
  {
    "path": "demos/src/workbox-background-sync-demo/package.json",
    "chars": 288,
    "preview": "{\n  \"name\": \"workbox-background-sync\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Workbox Background Sync Demo Git Listener"
  },
  {
    "path": "demos/src/workbox-background-sync-demo/public/example.txt",
    "chars": 12,
    "preview": "example text"
  },
  {
    "path": "demos/src/workbox-background-sync-demo/sw.js",
    "chars": 515,
    "preview": "importScripts(\n  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',\n);\n\n// Note: Ignore the erro"
  },
  {
    "path": "demos/src/workbox-background-sync-demo/updateServer.js",
    "chars": 1238,
    "preview": "const express = require('express');\nconst app = express();\nconst path = require('path');\n\napp.get('/', (request, respons"
  },
  {
    "path": "demos/src/workbox-broadcast-update-demo/index.html",
    "chars": 2257,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <title>workbox-broadcast-update demo</title>\n    <meta\n      name=\"workbox"
  },
  {
    "path": "demos/src/workbox-broadcast-update-demo/package.json",
    "chars": 290,
    "preview": "{\n  \"name\": \"workbox-broadcast-update\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Workbox Broadcast Update Demo Git Listen"
  },
  {
    "path": "demos/src/workbox-broadcast-update-demo/sw.js",
    "chars": 1032,
    "preview": "importScripts(\n  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',\n);\n\nworkbox.setConfig({\n  de"
  },
  {
    "path": "demos/src/workbox-broadcast-update-demo/updateServer.js",
    "chars": 1238,
    "preview": "const express = require('express');\nconst app = express();\nconst path = require('path');\n\napp.get('/', (request, respons"
  },
  {
    "path": "demos/src/workbox-cacheable-response/index.html",
    "chars": 3034,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <title>workbox-cacheable-response demo</title>\n    <meta\n      name=\"workb"
  },
  {
    "path": "demos/src/workbox-cacheable-response/package.json",
    "chars": 307,
    "preview": "{\n  \"name\": \"workbox-cacheable-response\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Workbox Cacheable Response Demo Listen"
  },
  {
    "path": "demos/src/workbox-cacheable-response/server.js",
    "chars": 1794,
    "preview": "// server.js\n// where your node app starts\n\n// init project\nconst express = require('express');\nconst app = express();\n\n"
  },
  {
    "path": "demos/src/workbox-cacheable-response/sw.js",
    "chars": 848,
    "preview": "importScripts(\n  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',\n);\n\nworkbox.setConfig({\n  de"
  },
  {
    "path": "demos/src/workbox-core/index.html",
    "chars": 2722,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <title>workbox-core demo</title>\n    <meta\n      name=\"workbox-core demo\"\n"
  },
  {
    "path": "demos/src/workbox-core/package.json",
    "chars": 266,
    "preview": "{\n  \"name\": \"workbox-core\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Workbox Core Demo Git Listener\",\n  \"scripts\": {\n    "
  },
  {
    "path": "demos/src/workbox-core/sw.js",
    "chars": 1278,
    "preview": "importScripts(\n  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',\n);\n\n// Note: Ignore the erro"
  },
  {
    "path": "demos/src/workbox-core/updateServer.js",
    "chars": 1203,
    "preview": "const express = require('express');\nconst app = express();\nconst path = require('path');\n\napp.get('/', (request, respons"
  },
  {
    "path": "demos/src/workbox-expiration/index.html",
    "chars": 4824,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <title>workbox-expiration demo</title>\n    <meta\n      name=\"workbox-expir"
  },
  {
    "path": "demos/src/workbox-expiration/package.json",
    "chars": 278,
    "preview": "{\n  \"name\": \"workbox-expiration\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Workbox Expiration Demo Git Listener\",\n  \"scri"
  },
  {
    "path": "demos/src/workbox-expiration/sw.js",
    "chars": 984,
    "preview": "importScripts(\n  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',\n);\n\n// Note: Ignore the erro"
  },
  {
    "path": "demos/src/workbox-expiration/updateServer.js",
    "chars": 1238,
    "preview": "const express = require('express');\nconst app = express();\nconst path = require('path');\n\napp.get('/', (request, respons"
  },
  {
    "path": "demos/src/workbox-google-analytics/index.html",
    "chars": 2803,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <title>workbox-google-analytics demo</title>\n    <meta\n      name=\"workbox"
  },
  {
    "path": "demos/src/workbox-google-analytics/package.json",
    "chars": 290,
    "preview": "{\n  \"name\": \"workbox-google-analytics\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Workbox Google Analytics Demo Git Listen"
  },
  {
    "path": "demos/src/workbox-google-analytics/sw.js",
    "chars": 232,
    "preview": "importScripts(\n  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',\n);\n\nworkbox.setConfig({\n  de"
  },
  {
    "path": "demos/src/workbox-google-analytics/updateServer.js",
    "chars": 1238,
    "preview": "const express = require('express');\nconst app = express();\nconst path = require('path');\n\napp.get('/', (request, respons"
  },
  {
    "path": "demos/src/workbox-navigation-preload/index.html",
    "chars": 1766,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <title>workbox-navigation-preload demo</title>\n    <meta\n      name=\"workb"
  },
  {
    "path": "demos/src/workbox-navigation-preload/package.json",
    "chars": 294,
    "preview": "{\n  \"name\": \"workbox-navigation-preload\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Workbox Navigation Preload Demo Git Li"
  },
  {
    "path": "demos/src/workbox-navigation-preload/sw.js",
    "chars": 769,
    "preview": "importScripts(\n  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',\n);\n\nworkbox.setConfig({\n  de"
  },
  {
    "path": "demos/src/workbox-navigation-preload/updateServer.js",
    "chars": 1238,
    "preview": "const express = require('express');\nconst app = express();\nconst path = require('path');\n\napp.get('/', (request, respons"
  },
  {
    "path": "demos/src/workbox-precaching/index.html",
    "chars": 2479,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <title>workbox-precaching demo</title>\n    <meta\n      name=\"workbox-preca"
  },
  {
    "path": "demos/src/workbox-precaching/package.json",
    "chars": 278,
    "preview": "{\n  \"name\": \"workbox-precaching\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Workbox Precaching Demo Git Listener\",\n  \"scri"
  },
  {
    "path": "demos/src/workbox-precaching/public/hello-world.1234.txt",
    "chars": 50,
    "preview": "Hello, World!\n\nI'm the first version of this file."
  },
  {
    "path": "demos/src/workbox-precaching/public/hello-world.5678.txt",
    "chars": 51,
    "preview": "Hello, World!\n\nI'm the second version of this file."
  },
  {
    "path": "demos/src/workbox-precaching/public/test-file.txt",
    "chars": 37,
    "preview": "#Danger\n\nThis file is not revisioned."
  },
  {
    "path": "demos/src/workbox-precaching/sw-1.js",
    "chars": 274,
    "preview": "importScripts(\n  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',\n);\n\nworkbox.setConfig({\n  de"
  },
  {
    "path": "demos/src/workbox-precaching/sw-2.js",
    "chars": 274,
    "preview": "importScripts(\n  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',\n);\n\nworkbox.setConfig({\n  de"
  },
  {
    "path": "demos/src/workbox-precaching/updateServer.js",
    "chars": 1338,
    "preview": "const express = require('express');\nconst app = express();\nconst path = require('path');\n\napp.get('/', (request, respons"
  },
  {
    "path": "demos/src/workbox-range-requests/index.html",
    "chars": 2381,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <title>workbox-range-requests demo</title>\n    <meta\n      name=\"workbox-r"
  },
  {
    "path": "demos/src/workbox-range-requests/package.json",
    "chars": 286,
    "preview": "{\n  \"name\": \"workbox-range-requests\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Workbox Range Requests Demo Git Listener\","
  },
  {
    "path": "demos/src/workbox-range-requests/sw.js",
    "chars": 413,
    "preview": "importScripts(\n  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',\n);\n\nworkbox.setConfig({\n  de"
  },
  {
    "path": "demos/src/workbox-range-requests/updateServer.js",
    "chars": 1238,
    "preview": "const express = require('express');\nconst app = express();\nconst path = require('path');\n\napp.get('/', (request, respons"
  },
  {
    "path": "demos/src/workbox-routing/index.html",
    "chars": 1935,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <title>workbox-precaching demo</title>\n    <meta\n      name=\"workbox-preca"
  },
  {
    "path": "demos/src/workbox-routing/package.json",
    "chars": 272,
    "preview": "{\n  \"name\": \"workbox-routing\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Workbox Routing Demo Git Listener\",\n  \"scripts\": "
  },
  {
    "path": "demos/src/workbox-routing/sw.js",
    "chars": 1001,
    "preview": "importScripts(\n  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',\n);\n\nworkbox.setConfig({\n  de"
  },
  {
    "path": "demos/src/workbox-routing/updateServer.js",
    "chars": 1239,
    "preview": "const express = require('express');\nconst app = express();\nconst path = require('path');\n\napp.get('/', (request, respons"
  },
  {
    "path": "demos/src/workbox-strategies/index.html",
    "chars": 4778,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <title>workbox-strategies demo</title>\n    <meta\n      name=\"workbox-strat"
  },
  {
    "path": "demos/src/workbox-strategies/public/cache-first.txt",
    "chars": 21,
    "preview": "Hello from CacheFirst"
  },
  {
    "path": "demos/src/workbox-strategies/public/network-first.txt",
    "chars": 23,
    "preview": "Hello from NetworkFirst"
  },
  {
    "path": "demos/src/workbox-strategies/public/network-only.txt",
    "chars": 22,
    "preview": "Hello from NetworkOnly"
  },
  {
    "path": "demos/src/workbox-strategies/public/stale-while-revalidate.txt",
    "chars": 31,
    "preview": "Hello from StaleWhileRevalidate"
  },
  {
    "path": "demos/src/workbox-strategies/sw.js",
    "chars": 2311,
    "preview": "importScripts(\n  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',\n);\n// To avoid async issues,"
  },
  {
    "path": "demos/src/workbox-strategies/updateServer.js",
    "chars": 1240,
    "preview": "const express = require('express');\nconst app = express();\nconst path = require('path');\n\napp.get('/', (request, respons"
  },
  {
    "path": "demos/src/workbox-streams/index.html",
    "chars": 2150,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <title>workbox-streams demo</title>\n    <meta\n      name=\"workbox-streams "
  },
  {
    "path": "demos/src/workbox-streams/package.json",
    "chars": 266,
    "preview": "{\n  \"name\": \"workbox-streams\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Workbox Streams Demo Git Listener\",\n  \"scripts\": "
  },
  {
    "path": "demos/src/workbox-streams/server.js",
    "chars": 1658,
    "preview": "// server.js\n// where your node app starts\n\n// init project\nconst express = require('express');\nconst app = express();\n\n"
  },
  {
    "path": "demos/src/workbox-streams/sw.js",
    "chars": 1458,
    "preview": "importScripts(\n  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',\n);\n\nworkbox.setConfig({\n  de"
  },
  {
    "path": "demos/src/workbox-sw/README.md",
    "chars": 18,
    "preview": "# workbox-sw-demo\n"
  },
  {
    "path": "demos/src/workbox-sw/index.html",
    "chars": 1976,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <title>workbox-sw demo</title>\n    <meta\n      name=\"workbox-sw demo\"\n    "
  },
  {
    "path": "demos/src/workbox-sw/package.json",
    "chars": 262,
    "preview": "{\n  \"name\": \"workbox-sw\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Workbox SW Demo Git Listener\",\n  \"scripts\": {\n    \"sta"
  },
  {
    "path": "demos/src/workbox-sw/sw.js",
    "chars": 783,
    "preview": "importScripts(\n  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',\n);\n\n// Note: Ignore the erro"
  },
  {
    "path": "demos/src/workbox-sw/updateServer.js",
    "chars": 1238,
    "preview": "const express = require('express');\nconst app = express();\nconst path = require('path');\n\napp.get('/', (request, respons"
  },
  {
    "path": "demos/src/workbox-window/index.html",
    "chars": 2671,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <title>workbox-window demo</title>\n    <meta\n      name=\"workbox-window de"
  },
  {
    "path": "demos/src/workbox-window/package.json",
    "chars": 270,
    "preview": "{\n  \"name\": \"workbox-window\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Workbox Window Demo Git Listener\",\n  \"scripts\": {\n"
  },
  {
    "path": "demos/src/workbox-window/sw.js",
    "chars": 301,
    "preview": "importScripts(\n  'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-sw.js',\n);\n\nworkbox.setConfig({\n  de"
  },
  {
    "path": "demos/src/workbox-window/updateServer.js",
    "chars": 1238,
    "preview": "const express = require('express');\nconst app = express();\nconst path = require('path');\n\napp.get('/', (request, respons"
  },
  {
    "path": "gulp-tasks/analyze-properties.js",
    "chars": 519,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/build-node-packages.js",
    "chars": 3114,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/build-packages.js",
    "chars": 2478,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/build-sw-packages.js",
    "chars": 5718,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/build-window-packages.js",
    "chars": 3400,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/build.js",
    "chars": 1371,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/docs.js",
    "chars": 1585,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/lint.js",
    "chars": 837,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/publish-cdn.js",
    "chars": 2360,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/publish-github.js",
    "chars": 1852,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/publish-glitch.js",
    "chars": 2372,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/publish-lerna.js",
    "chars": 1074,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/publish.js",
    "chars": 1283,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/test-integration.js",
    "chars": 4729,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/test-node.js",
    "chars": 2940,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/test-server.js",
    "chars": 948,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/test.js",
    "chars": 861,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/transpile-typescript.js",
    "chars": 2948,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/utils/analyse-properties.js",
    "chars": 3633,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/utils/cdn-helper.js",
    "chars": 2367,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/utils/constants.js",
    "chars": 755,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/utils/get-packages.js",
    "chars": 724,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/utils/github-helper.js",
    "chars": 2105,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/utils/node-projects-babel.config.json",
    "chars": 72,
    "preview": "{\n  \"presets\": [[\"@babel/preset-env\", {\"targets\": {\"node\": \"10.0\"}}]]\n}\n"
  },
  {
    "path": "gulp-tasks/utils/output-filename-to-package-map.js",
    "chars": 650,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/utils/package-runner.js",
    "chars": 4365,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/utils/pkg-path-to-name.js",
    "chars": 450,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/utils/publish-helpers.js",
    "chars": 4055,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/utils/rollup-helper.js",
    "chars": 3285,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/utils/version-module.js",
    "chars": 1171,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulp-tasks/utils/versioned-cdn-url.js",
    "chars": 408,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "gulpfile.js",
    "chars": 1218,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/pr-bot/aggregate-size-plugin.js",
    "chars": 2491,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/lang/en.yaml",
    "chars": 1254,
    "preview": "# @license\n# Copyright 2018 Google LLC\n#\n# Use of this source code is governed by an MIT-style\n# license that can be fou"
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/lib/publishjob.js",
    "chars": 3091,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/publish.js",
    "chars": 2678,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/static/jsdoc.css",
    "chars": 917,
    "preview": ".label {\n  font-style: italic;\n  text-transform: uppercase;\n}\n\n.dl-compact dt {\n  margin: 8px 0px 0px 0px;\n}\n\nh1.devsite"
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/views/augments.hbs",
    "chars": 154,
    "preview": "{{#any augments}}\n  <dt>{{translateHeading 'augments' augments}}</dt>\n  {{#each augments}}\n    <dd><small>{{link this}}<"
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/views/classes-links.hbs",
    "chars": 374,
    "preview": "{{#any items}}\n<h>{{translateHeading headingKey items}}</h>\n  <section id='members-links'>\n  {{#each items}}\n    <h3 {{~"
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/views/details-table-row.hbs",
    "chars": 1223,
    "preview": "<tr>\n  {{#block 'details-table-name'}}\n    <td {{~cssClass '!details-table-name'}}>\n      <p>{{#if name}}{{name}}{{else}"
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/views/details-table.hbs",
    "chars": 482,
    "preview": "<table class=\"function param responsive\">\n  {{#block 'details-table-header'}}\n    <tr>\n      <th colspan=\"2\">\n        {{"
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/views/implements.hbs",
    "chars": 162,
    "preview": "{{#any implements}}\n  <dt>{{translateHeading 'implements' implements}}</dt>\n  {{#each implements}}\n    <dd><small>{{link"
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/views/index-all.hbs",
    "chars": 242,
    "preview": "{{#extend 'layout'}}\n  {{#content 'title'}}\n    <title>Index All</title>\n  {{/content}}\n  {{#content 'body-main-content'"
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/views/index.hbs",
    "chars": 312,
    "preview": "{{#extend 'layout'}}\n  {{#content 'title'}}\n    <title>Overview</title>\n  {{/content}}\n  {{#content 'body-main-content'}"
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/views/layout.hbs",
    "chars": 2967,
    "preview": "<!DOCTYPE html>\n<html devsite>\n    {{#block 'head'}}\n        <head>\n            {{#block 'meta'}}\n                <meta "
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/views/params.hbs",
    "chars": 184,
    "preview": "{{#any params}}\n    <section>\n        {{#withOnly values=(reparentItems this 'params')}}\n            {{#embed 'details-t"
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/views/properties.hbs",
    "chars": 304,
    "preview": "{{#any (filterProperties properties)}}\n  <section>\n    {{#unless isEnum}}\n      <h>{{translateHeading 'properties' prope"
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/views/see.hbs",
    "chars": 162,
    "preview": "{{#any see}}\n    <dt>{{translateHeading 'see' see}}</dt>\n    {{#each see}}\n        <dd><small>{{link (see this ../longna"
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/views/signature.hbs",
    "chars": 632,
    "preview": "{{!--\n    Note that this section omits the return type for:\n    + Constructors\n    + Methods with no explicit return typ"
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/views/symbol-content.hbs",
    "chars": 1496,
    "preview": "<section>\n  {{#block 'symbol-content-classes'}}\n    {{#withOnly items=members.classes headingKey='classes'}}\n      {{#em"
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/views/symbol-detail.hbs",
    "chars": 946,
    "preview": "{{~#unless symbol.hideconstructor~}}\n  <h id=\"{{id symbol}}\" {{~cssClass '!symbol-name'}}>\n    {{~#with symbol~}}\n      "
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/views/symbol-header.hbs",
    "chars": 1214,
    "preview": "<header {{~cssClass '!page-header'}}>\n  {{#block 'symbol-header-heading'}}\n      <h>\n        {{~#isnt longname memberof}"
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/views/symbol-index-section.hbs",
    "chars": 196,
    "preview": "<div {{~cssClass '!symbol-index-column'}}>\n  {{#each doclets}}\n    <p {{~cssClass '!symbol-index-name'}}>\n      {{linkLo"
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/views/symbol-index.hbs",
    "chars": 522,
    "preview": "<div {{~cssClass '!symbol-index'}}>\n  {{#eachIndexGroup allLongnamesTree}}\n    <section>\n      <div {{~cssClass '!symbol"
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/views/symbol-labels.hbs",
    "chars": 330,
    "preview": "{{~#withOnly allLabels=(labels symbol)~}}\n  {{~#any allLabels~}}\n    <div {{~cssClass '!symbol-detail-labels'}}>\n      {"
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/views/symbol-overview.hbs",
    "chars": 1875,
    "preview": "{{#any docs}}\n  {{#first docs}}\n    {{#embed 'symbol-header'}}{{/embed}}\n  {{/first}}\n{{/any}}\n\n{{#each docs}}\n  {{#if @"
  },
  {
    "path": "infra/templates/reference-docs/jsdoc/views/toc-yaml.hbs",
    "chars": 176,
    "preview": "toc:\n{{#each symbols~}}\n- title: \"{{tocYamlName}}\"\n  path: {{../basepath}}/{{basename (url longname) '.html'}}\n{{/each}}"
  },
  {
    "path": "infra/testing/activate-and-control.js",
    "chars": 2790,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/activate-sw-safari.js",
    "chars": 2865,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/auto-stub-logger.mjs",
    "chars": 780,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/clean-sw.js",
    "chars": 865,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/comlink/node-interface.js",
    "chars": 824,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/comlink/sw-interface.js",
    "chars": 2091,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/comlink/window-interface.js",
    "chars": 734,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/confirm-directory-contains.js",
    "chars": 628,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/env-it.js",
    "chars": 1341,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/expectError.js",
    "chars": 909,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/generate-variant-tests.js",
    "chars": 1389,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/helpers/compareResponses.mjs",
    "chars": 508,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/helpers/extendable-event-utils.mjs",
    "chars": 1623,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/helpers/generateOpaqueResponse.mjs",
    "chars": 445,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/helpers/generateUniqueResponse.mjs",
    "chars": 312,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/helpers/sleep.mjs",
    "chars": 380,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/server/cross-origin-server.js",
    "chars": 737,
    "preview": "/*\n  Copyright 2021 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/server/index.js",
    "chars": 2113,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/server/request-counter.js",
    "chars": 926,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/server/routes/build-file.js",
    "chars": 1446,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/server/routes/comlink.js",
    "chars": 382,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/server/routes/integration-html.js",
    "chars": 435,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/server/routes/sw-bundle.js",
    "chars": 2734,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/server/routes/templates-update.js",
    "chars": 557,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/server/routes/templates.js",
    "chars": 1201,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/server/routes/test-sw.js",
    "chars": 1404,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/server/routes/test-window.js",
    "chars": 1130,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/server/routes/unique-etag.js",
    "chars": 385,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/server/routes/unique-value.js",
    "chars": 366,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/server/static/integration.html",
    "chars": 282,
    "preview": "<html>\n  <head>\n    <title>Integration Test Harness</title>\n  </head>\n  <body>\n    <p>You need to manually register the "
  },
  {
    "path": "infra/testing/server/template-data.js",
    "chars": 720,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/server/templates/integration.html.njk",
    "chars": 360,
    "preview": "<!DOCTYPE html>\n<!--\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that c"
  },
  {
    "path": "infra/testing/server/templates/sw-clients-claim.js.njk",
    "chars": 390,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/server/templates/sw-no-skip-waiting.js.njk",
    "chars": 200,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/server/templates/sw-script-version.js.njk",
    "chars": 585,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/server/templates/sw-skip-waiting-deferred.js.njk",
    "chars": 413,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/server/templates/sw-skip-waiting-on-message.js.njk",
    "chars": 313,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/server/templates/sw-skip-waiting.js.njk",
    "chars": 273,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/server/templates/sw-window-ready.js.njk",
    "chars": 735,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/server/templates/test-sw-runner.js.njk",
    "chars": 2878,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/server/templates/test-sw.html.njk",
    "chars": 2046,
    "preview": "<!DOCTYPE html>\n<!--\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that c"
  },
  {
    "path": "infra/testing/server/templates/test-window.html.njk",
    "chars": 2463,
    "preview": "<!DOCTYPE html>\n<!--\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that c"
  },
  {
    "path": "infra/testing/validator/service-worker-runtime.js",
    "chars": 6831,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/wait-until.js",
    "chars": 511,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/webdriver/IframeManager.js",
    "chars": 1873,
    "preview": "/*\n  Copyright 2021 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/webdriver/executeAsyncAndCatch.js",
    "chars": 786,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/webdriver/runUnitTests.js",
    "chars": 1142,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/webdriver/unregisterAllSWs.js",
    "chars": 758,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/webdriver/windowLoaded.js",
    "chars": 934,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/testing/webpack-build-check.js",
    "chars": 744,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/type-overrides.d.ts",
    "chars": 2111,
    "preview": "// TODO(philipwalton): remove these once this PR makes its way to a release:\n// https://github.com/microsoft/TSJS-lib-ge"
  },
  {
    "path": "infra/utils/AsyncDebounce.js",
    "chars": 733,
    "preview": "/*\n  Copyright 2019 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "infra/utils/log-helper.js",
    "chars": 686,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  },
  {
    "path": "javascript.eslintrc.js",
    "chars": 3068,
    "preview": "module.exports = {\n  extends: ['eslint:recommended', 'google'],\n  env: {\n    serviceworker: true,\n    browser: true,\n   "
  },
  {
    "path": "jsdoc.conf",
    "chars": 360,
    "preview": "{\n  \"source\": {\n    \"include\": [\n      \"packages\"\n    ],\n    \"exclude\": [\n      \"packages/workbox-cli\"\n    ],\n    \"inclu"
  },
  {
    "path": "lerna.json",
    "chars": 75,
    "preview": "{\n  \"lerna\": \"5.6.2\",\n  \"packages\": [\"packages/*\"],\n  \"version\": \"7.4.0\"\n}\n"
  },
  {
    "path": "package.json",
    "chars": 3868,
    "preview": "{\n  \"author\": \"Google's Web DevRel Team and Google's Aurora Team\",\n  \"bugs\": {\n    \"url\": \"https://github.com/GoogleChro"
  },
  {
    "path": "packages/workbox-background-sync/README.md",
    "chars": 124,
    "preview": "This module's documentation can be found at https://developers.google.com/web/tools/workbox/modules/workbox-background-s"
  },
  {
    "path": "packages/workbox-background-sync/package.json",
    "chars": 864,
    "preview": "{\n  \"name\": \"workbox-background-sync\",\n  \"version\": \"7.4.0\",\n  \"license\": \"MIT\",\n  \"author\": \"Google's Web DevRel Team a"
  },
  {
    "path": "packages/workbox-background-sync/src/BackgroundSyncPlugin.ts",
    "chars": 1198,
    "preview": "/*\n  Copyright 2018 Google LLC\n\n  Use of this source code is governed by an MIT-style\n  license that can be found in the"
  }
]

// ... and 517 more files (download for full content)

About this extraction

This page contains the full source code of the GoogleChrome/workbox GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 717 files (1.9 MB), approximately 479.1k tokens, and a symbol index with 723 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!