Compare commits

...
Author SHA1 Message Date
ohif-bot 669717d27b chore(release): publish [skip ci]
- @ohif/extension-vtk@1.11.15
 - @ohif/core@2.13.14
 - @ohif/viewer@4.9.23
2021-08-30 13:04:58 +00:00
Alireza 715dfc556a fix: MPR metadata parsing for spacings (#2517)
* fix: MPR metadata parsing for spacings

* fix: OHIF Metadata provider for validNumbers for imagePlaneModule
2021-08-30 09:01:46 -04:00
ohif-bot cafb7d3f7b chore(release): publish [skip ci]
- @ohif/viewer@4.9.22
2021-08-19 13:05:04 +00:00
matthiasg 5f92f6ec7f fix: Remove internet dependency for workbox (addressing #2109) (#2151)
* Ignoring *.js.map files as generated in the extensions directories for example

* Fix for #2109. Removed internet dependency to google workbox
2021-08-19 15:00:20 +02:00
Matthias SchmiederandMatthias Schmieder eea610dfe8 fix CVE-2019-5021 caused by nginx-apline (#2514)
Co-authored-by: Matthias Schmieder <matthias.schmieder@stryker.com>
2021-08-19 13:42:04 +02:00
Erik Ziegler e8733a9bd9 Update CITATION.cff (#2504) 2021-08-04 17:16:35 +02:00
Erik Ziegler d292931073 Create CITATION.cff (#2503) 2021-08-04 15:43:10 +02:00
ohif-bot 4cf17185da chore(release): publish [skip ci]
- @ohif/extension-cornerstone@2.10.10
 - @ohif/viewer@4.9.21
2021-07-26 11:44:06 +00:00
b8ae92c2d4 fix: changed new image handler conditional for 0 edge case (#2338)
Co-authored-by: Michael Andersen <Michael.Andersen@rmp.uhn.ca>
Co-authored-by: Erik Ziegler <erik.sweed@gmail.com>
2021-07-26 13:35:37 +02:00
Woonchan Cho bad67020cc chore(#2483) make client-side code debuggable right from the source code (#2484) 2021-07-26 13:34:55 +02:00
ohif-bot 2afcd498f3 chore(release): publish [skip ci]
- @ohif/extension-debugging@0.2.2
 - @ohif/extension-dicom-tag-browser@0.2.11
 - @ohif/extension-vtk@1.11.14
 - @ohif/core@2.13.13
 - @ohif/viewer@4.9.20
2021-06-03 20:56:43 +00:00
Igor Octaviano ce4c3d5360 Merge pull request #2408 from OHIF/feat/idc-2374
IDC-2374: Exponential backoff and retry after 500 error
2021-06-03 17:52:49 -03:00
igoroctaviano d575e36879 Expose retryable option 2021-06-03 17:24:39 -03:00
igoroctaviano 98fcabfcb5 Resolve opening connection before previsouly setting headers 2021-06-03 17:05:45 -03:00
Davide Punzo 1e2773345a Merge branch 'feat/idc-2374' of https://github.com/OHIF/Viewers into feat/idc-2374 2021-06-03 16:25:29 +02:00
Davide Punzo f847633cf3 update dicomweb-client to version 0.8.1 2021-06-03 16:25:06 +02:00
igoroctaviano bd2ddd7702 Remove metadata check 2021-06-03 07:20:49 -03:00
igoroctaviano 26b7b34bd4 Add check for metadata 2021-06-03 07:10:33 -03:00
Davide Punzo 6f3e446a79 Merge branch 'master' into feat/idc-2374 2021-06-03 10:11:45 +02:00
Davide Punzo c8f7abfd53 Merge branch 'master' into feat/idc-2374 2021-06-03 10:04:02 +02:00
Davide Punzo 5627e9c919 update dicomweb-client to version 0.8.0 2021-06-03 09:37:57 +02:00
Davide Punzo 582b713b84 Merge branch 'master' into feat/idc-2374 2021-06-03 09:25:50 +02:00
igoroctaviano 05444f48d4 Improve docs remove env variables 2021-05-13 09:30:52 -03:00
igoroctaviano 2ea227ca06 Extract hook and add config and documentation 2021-05-13 09:06:11 -03:00
igoroctaviano 35aaad175c Update naming 2021-05-13 08:11:09 -03:00
igoroctaviano 863fe05907 Update naming 2021-05-13 08:11:03 -03:00
igoroctaviano 1c9560044f Implement handlers to retry metadata requests 2021-05-13 08:10:53 -03:00
97 changed files with 11385 additions and 43 deletions

No files matched your search

+2
View File
@@ -9,6 +9,7 @@ src/version.js
junit.xml
coverage/
.docz/
*.js.map
# YALC (for Erik)
.yalc
@@ -34,3 +35,4 @@ screenshots/
# Locize settings
.locize
+15
View File
@@ -0,0 +1,15 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "pwa-chrome",
"request": "launch",
"name": "Launch Chrome against localhost",
"url": "http://localhost:3000",
"webRoot": "${workspaceFolder}"
}
]
}
+24
View File
@@ -0,0 +1,24 @@
cff-version: 1.2.0
message: "If you use this software, please cite it as below."
authors:
- family-names: "Ziegler"
given-names: "Erik"
orcid: "https://orcid.org/0000-0003-1857-8129"
- family-names: "Urban"
given-names: "Trinity"
- family-names: "Brown"
given-names: "Danny"
- family-names: "Petts"
given-names: "James"
- family-names: "Pieper"
given-names: "Steve D"
- family-names: "Lewis"
given-names: "Rob"
- family-names: "Hafey"
given-names: "Chris"
- family-names: "Harris"
given-names: "Gordon J"
title: "Open Health Imaging Foundation Viewer: An Extensible Open-Source Framework for Building Web-Based Imaging Applications to Support Cancer Research"
doi: 10.1200/CCI.19.00131
version: 1.0.0
url: "https://github.com/OHIF/Viewers"
+1 -1
View File
@@ -53,7 +53,7 @@ RUN yarn run build
# Stage 2: Bundle the built application into a Docker container
# which runs Nginx using Alpine Linux
FROM nginx:1.15.5-alpine
FROM nginx:1.21.1-alpine
RUN apk add --no-cache bash
RUN rm -rf /etc/nginx/conf.d
COPY .docker/Viewer-v2.x /etc/nginx/conf.d
+11
View File
@@ -3,6 +3,17 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.10.10](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.10.9...@ohif/extension-cornerstone@2.10.10) (2021-07-26)
### Bug Fixes
* changed new image handler conditional for 0 edge case ([#2338](https://github.com/OHIF/Viewers/issues/2338)) ([b8ae92c](https://github.com/OHIF/Viewers/commit/b8ae92c2d4f733b3ca89826118029685650b396a))
## [2.10.9](https://github.com/OHIF/Viewers/compare/@ohif/extension-cornerstone@2.10.8...@ohif/extension-cornerstone@2.10.9) (2021-06-02)
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-cornerstone",
"version": "2.10.9",
"version": "2.10.10",
"description": "OHIF extension for Cornerstone",
"author": "OHIF",
"license": "MIT",
@@ -180,7 +180,7 @@ class OHIFCornerstoneViewport extends Component {
if (
displaySet.displaySetInstanceUID !==
prevDisplaySet.displaySetInstanceUID ||
prevDisplaySet.displaySetInstanceUID ||
displaySet.SOPInstanceUID !== prevDisplaySet.SOPInstanceUID ||
displaySet.frameIndex !== prevDisplaySet.frameIndex
) {
@@ -221,7 +221,7 @@ class OHIFCornerstoneViewport extends Component {
const { displaySet } = this.props.viewportData;
const { StudyInstanceUID } = displaySet;
if (currentImageIdIndex > 0) {
if (currentImageIdIndex >= 0) {
this.props.onNewImage({
StudyInstanceUID,
SOPInstanceUID: sopInstanceUid,
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [0.2.2](https://github.com/OHIF/Viewers/compare/@ohif/extension-debugging@0.2.1...@ohif/extension-debugging@0.2.2) (2021-06-03)
**Note:** Version bump only for package @ohif/extension-debugging
## [0.2.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-debugging@0.2.0...@ohif/extension-debugging@0.2.1) (2021-03-19)
**Note:** Version bump only for package @ohif/extension-debugging
+3 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-debugging",
"version": "0.2.1",
"version": "0.2.2",
"description": "OHIF extension for debugging.",
"author": "OHIF",
"license": "MIT",
@@ -28,13 +28,12 @@
},
"peerDependencies": {
"@ohif/core": "^2.6.0",
"dicom-parser": "^1.8.3",
"dicomweb-client": "^0.5.2"
"dicom-parser": "^1.8.3"
},
"dependencies": {
"@babel/runtime": "^7.5.5",
"detect-browser": "5.1.1",
"dicomweb-client": "^0.6.0",
"dicomweb-client": "^0.8.1",
"file-saver": "^2.0.2",
"jszip": "^3.2.2"
}
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [0.2.11](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-tag-browser@0.2.10...@ohif/extension-dicom-tag-browser@0.2.11) (2021-06-03)
**Note:** Version bump only for package @ohif/extension-dicom-tag-browser
## [0.2.10](https://github.com/OHIF/Viewers/compare/@ohif/extension-dicom-tag-browser@0.2.9...@ohif/extension-dicom-tag-browser@0.2.10) (2021-06-02)
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-dicom-tag-browser",
"version": "0.2.10",
"version": "0.2.11",
"description": "OHIF extension for checking DICOM headers.",
"author": "OHIF",
"license": "MIT",
@@ -33,7 +33,7 @@
},
"dependencies": {
"@babel/runtime": "^7.5.5",
"dicomweb-client": "^0.6.0",
"dicomweb-client": "^0.8.1",
"moment": "2.24.0",
"react-select": "^3.0.8"
}
+19
View File
@@ -3,6 +3,25 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.11.15](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.11.14...@ohif/extension-vtk@1.11.15) (2021-08-30)
### Bug Fixes
* MPR metadata parsing for spacings ([#2517](https://github.com/OHIF/Viewers/issues/2517)) ([715dfc5](https://github.com/OHIF/Viewers/commit/715dfc556a3883de31d74012dcc99e431d91f57d))
## [1.11.14](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.11.13...@ohif/extension-vtk@1.11.14) (2021-06-03)
**Note:** Version bump only for package @ohif/extension-vtk
## [1.11.13](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@1.11.12...@ohif/extension-vtk@1.11.13) (2021-06-02)
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/extension-vtk",
"version": "1.11.13",
"version": "1.11.15",
"description": "OHIF extension for VTK.js",
"author": "OHIF",
"license": "MIT",
@@ -53,7 +53,7 @@
"react-vtkjs-viewport": "^0.14.2"
},
"devDependencies": {
"@ohif/core": "^2.13.12",
"@ohif/core": "^2.13.14",
"@ohif/ui": "^1.9.2",
"cornerstone-tools": "^4.20.1",
"cornerstone-wado-image-loader": "^3.1.0",
+3 -3
View File
@@ -72,7 +72,7 @@ class OHIFVTKViewport extends Component {
};
static defaultProps = {
onScroll: () => {},
onScroll: () => { },
};
static id = 'OHIFVTKViewport';
@@ -271,7 +271,7 @@ class OHIFVTKViewport extends Component {
volumeMapper.setSampleDistance(sampleDistance);
// Be generous to surpress warnings, as the logging really hurts performance.
// Be generous to suppress warnings, as the logging really hurts performance.
// TODO: maybe we should auto adjust samples to 1000.
volumeMapper.setMaximumSamplesPerRay(4000);
@@ -398,7 +398,7 @@ class OHIFVTKViewport extends Component {
if (
displaySet.displaySetInstanceUID !==
prevDisplaySet.displaySetInstanceUID ||
prevDisplaySet.displaySetInstanceUID ||
displaySet.SOPInstanceUID !== prevDisplaySet.SOPInstanceUID ||
displaySet.frameIndex !== prevDisplaySet.frameIndex
) {
+19
View File
@@ -3,6 +3,25 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.13.14](https://github.com/OHIF/Viewers/compare/@ohif/core@2.13.13...@ohif/core@2.13.14) (2021-08-30)
### Bug Fixes
* MPR metadata parsing for spacings ([#2517](https://github.com/OHIF/Viewers/issues/2517)) ([715dfc5](https://github.com/OHIF/Viewers/commit/715dfc556a3883de31d74012dcc99e431d91f57d))
## [2.13.13](https://github.com/OHIF/Viewers/compare/@ohif/core@2.13.12...@ohif/core@2.13.13) (2021-06-03)
**Note:** Version bump only for package @ohif/core
## [2.13.12](https://github.com/OHIF/Viewers/compare/@ohif/core@2.13.11...@ohif/core@2.13.12) (2021-06-02)
+3 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/core",
"version": "2.13.12",
"version": "2.13.14",
"description": "Generic business logic for web-based medical imaging applications",
"author": "OHIF Core Team",
"license": "MIT",
@@ -40,12 +40,13 @@
"@babel/runtime": "^7.5.5",
"ajv": "^6.10.0",
"dcmjs": "0.18.8",
"dicomweb-client": "^0.6.0",
"dicomweb-client": "^0.8.1",
"immer": "6.0.2",
"isomorphic-base64": "^1.0.2",
"lodash.clonedeep": "^4.5.0",
"lodash.merge": "^4.6.1",
"mousetrap": "^1.6.3",
"retry": "^0.12.0",
"validate.js": "^0.12.0"
}
}
@@ -6,6 +6,7 @@ import parseDicomStructuredReport from './parseDicomStructuredReport';
import parseMeasurementsData from './parseMeasurementsData';
import getAllDisplaySets from './utils/getAllDisplaySets';
import errorHandler from '../errorHandler';
import getXHRRetryRequestHook from '../utils/xhrRetryRequestHook';
const VERSION_NAME = 'dcmjs-0.0';
const TRANSFER_SYNTAX_UID = '1.2.840.10008.1.2.1';
@@ -23,6 +24,7 @@ const retrieveMeasurementFromSR = async (series, studies, serverUrl) => {
url: serverUrl,
headers: DICOMWeb.getAuthorizationHeader(),
errorInterceptor: errorHandler.getHTTPErrorHandler(),
requestHooks: [getXHRRetryRequestHook()],
};
const dicomWeb = new api.DICOMwebClient(config);
@@ -74,6 +76,7 @@ const stowSRFromMeasurements = async (measurements, serverUrl) => {
url: serverUrl,
headers: DICOMWeb.getAuthorizationHeader(),
errorInterceptor: errorHandler.getHTTPErrorHandler(),
requestHooks: [getXHRRetryRequestHook()],
};
const dicomWeb = new api.DICOMwebClient(config);
@@ -231,26 +231,26 @@ class MetadataProvider {
let columnCosines;
if (PixelSpacing) {
rowPixelSpacing = PixelSpacing[0];
columnPixelSpacing = PixelSpacing[1];
rowPixelSpacing = validNumber(PixelSpacing[0]);
columnPixelSpacing = validNumber(PixelSpacing[1]);
}
if (ImageOrientationPatient) {
rowCosines = ImageOrientationPatient.slice(0, 3);
columnCosines = ImageOrientationPatient.slice(3, 6);
rowCosines = validNumber(ImageOrientationPatient.slice(0, 3));
columnCosines = validNumber(ImageOrientationPatient.slice(3, 6));
}
metadata = {
frameOfReferenceUID: instance.FrameOfReferenceUID,
rows: instance.Rows,
columns: instance.Columns,
imageOrientationPatient: ImageOrientationPatient,
imageOrientationPatient: validNumber(ImageOrientationPatient),
rowCosines,
columnCosines,
imagePositionPatient: instance.ImagePositionPatient,
sliceThickness: instance.SliceThickness,
sliceLocation: instance.SliceLocation,
pixelSpacing: PixelSpacing,
imagePositionPatient: validNumber(instance.ImagePositionPatient),
sliceThickness: validNumber(instance.SliceThickness),
sliceLocation: validNumber(instance.SliceLocation),
pixelSpacing: validNumber(PixelSpacing),
rowPixelSpacing,
columnPixelSpacing,
};
@@ -12,6 +12,7 @@ import { isImage } from '../../utils/isImage';
import { isDisplaySetReconstructable, isSpacingUniform } from '../../utils/isDisplaySetReconstructable';
import errorHandler from '../../errorHandler';
import isLowPriorityModality from '../../utils/isLowPriorityModality';
import getXHRRetryRequestHook from '../../utils/xhrRetryRequestHook';
class StudyMetadata extends Metadata {
constructor(data, uid) {
@@ -939,6 +940,7 @@ function _getDisplaySetFromSopClassModule(
url: study.getData().wadoRoot,
headers,
errorInterceptor,
requestHooks: [getXHRRetryRequestHook()],
});
let displaySet = plugin.getDisplaySetFromSeries(
@@ -2,6 +2,7 @@ import { api } from 'dicomweb-client';
import DICOMWeb from '../../../DICOMWeb/';
import errorHandler from '../../../errorHandler';
import getXHRRetryRequestHook from '../../../utils/xhrRetryRequestHook';
/**
* Creates a QIDO date string for a date range query
@@ -118,6 +119,7 @@ export default function Studies(server, filter) {
url: server.qidoRoot,
headers: DICOMWeb.getAuthorizationHeader(server),
errorInterceptor: errorHandler.getHTTPErrorHandler(),
requestHooks: [getXHRRetryRequestHook()],
};
const dicomWeb = new api.DICOMwebClient(config);
@@ -10,6 +10,7 @@ import {
} from './studyInstanceHelpers';
import errorHandler from '../../../errorHandler';
import { getXHRRetryRequestHook } from '../../../utils/xhrRetryRequestHook';
const { naturalizeDataset } = dcmjs.data.DicomMetaDictionary;
@@ -76,6 +77,7 @@ export default class RetrieveMetadataLoaderAsync extends RetrieveMetadataLoader
url: server.qidoRoot,
headers: DICOMWeb.getAuthorizationHeader(server),
errorInterceptor: errorHandler.getHTTPErrorHandler(),
requestHooks: [getXHRRetryRequestHook()],
});
this.client = client;
@@ -4,6 +4,7 @@ import { createStudyFromSOPInstanceList } from './studyInstanceHelpers';
import RetrieveMetadataLoader from './retrieveMetadataLoader';
import errorHandler from '../../../errorHandler';
import getXHRRetryRequestHook from '../../../utils/xhrRetryRequestHook';
/**
* Class for sync load of study metadata.
@@ -61,6 +62,7 @@ export default class RetrieveMetadataLoaderSync extends RetrieveMetadataLoader {
url: server.wadoRoot,
headers: DICOMWeb.getAuthorizationHeader(server),
errorInterceptor: errorHandler.getHTTPErrorHandler(),
requestHooks: [getXHRRetryRequestHook()],
});
this.client = client;
@@ -4,6 +4,7 @@ import { api } from 'dicomweb-client';
import DICOMWeb from '../DICOMWeb';
import errorHandler from '../errorHandler';
import getXHRRetryRequestHook from './xhrRetryRequestHook';
const getImageId = imageObj => {
if (!imageObj) {
@@ -66,6 +67,7 @@ const wadorsRetriever = (
url,
headers,
errorInterceptor,
requestHooks: [getXHRRetryRequestHook()],
};
const dicomWeb = new api.DICOMwebClient(config);
+3
View File
@@ -18,6 +18,7 @@ import isDicomUid from './isDicomUid';
import resolveObjectPath from './resolveObjectPath';
import * as hierarchicalListUtils from './hierarchicalListUtils';
import * as progressTrackingUtils from './progressTrackingUtils';
import xhrRetryRequestHook from './xhrRetryRequestHook';
const utils = {
guid,
@@ -40,6 +41,7 @@ const utils = {
resolveObjectPath,
hierarchicalListUtils,
progressTrackingUtils,
xhrRetryRequestHook,
};
export {
@@ -63,6 +65,7 @@ export {
resolveObjectPath,
hierarchicalListUtils,
progressTrackingUtils,
xhrRetryRequestHook,
};
export default utils;
+1
View File
@@ -23,6 +23,7 @@ describe('Top level exports', () => {
'resolveObjectPath',
'hierarchicalListUtils',
'progressTrackingUtils',
'xhrRetryRequestHook',
].sort();
const exports = Object.keys(utils.default).sort();
@@ -4,6 +4,7 @@ import str2ab from '../str2ab';
import unpackOverlay from './unpackOverlay';
import errorHandler from '../../errorHandler';
import getXHRRetryRequestHook from '../xhrRetryRequestHook';
export default async function fetchOverlayData(instance, server) {
const OverlayDataPromises = [];
@@ -69,6 +70,7 @@ async function _getOverlayData(tag, server) {
url: server.wadoRoot, //BulkDataURI is absolute, so this isn't used
headers: DICOMWeb.getAuthorizationHeader(server),
errorInterceptor: errorHandler.getHTTPErrorHandler(),
requestHooks: [getXHRRetryRequestHook()],
};
const dicomWeb = new api.DICOMwebClient(config);
const options = {
@@ -3,6 +3,7 @@ import DICOMWeb from '../../DICOMWeb';
import str2ab from '../str2ab';
import errorHandler from '../../errorHandler';
import getXHRRetryRequestHook from '../xhrRetryRequestHook';
export default async function fetchPaletteColorLookupTableData(
instance,
@@ -141,6 +142,7 @@ function _getPaletteColor(server, paletteColorLookupTableData, lutDescriptor) {
url: server.wadoRoot, //BulkDataURI is absolute, so this isn't used
headers: DICOMWeb.getAuthorizationHeader(server),
errorInterceptor: errorHandler.getHTTPErrorHandler(),
requestHooks: [getXHRRetryRequestHook()],
};
const dicomWeb = new api.DICOMwebClient(config);
const options = {
@@ -0,0 +1,103 @@
import retry from 'retry';
const defaultRetryOptions = {
retries: 5,
factor: 3,
minTimeout: 1 * 1000,
maxTimeout: 60 * 1000,
randomize: true,
retryableStatusCodes: [429, 500],
};
let retryOptions = { ...defaultRetryOptions };
/**
* Request hook used to add retry functionality to XHR requests.
*
* @param {XMLHttpRequest} request XHR request instance
* @param {object} metadata Metadata about the request
* @param {object} metadata.url URL
* @param {object} metadata.method HTTP method
* @returns {XMLHttpRequest} request instance optionally modified
*/
const xhrRetryRequestHook = (request, metadata) => {
const { url, method } = metadata;
function faultTolerantRequestSend(...args) {
const operation = retry.operation(retryOptions);
operation.attempt(function operationAttempt(currentAttempt) {
const originalOnReadyStateChange = request.onreadystatechange;
/** Overriding/extending XHR function */
request.onreadystatechange = function onReadyStateChange(...args) {
originalOnReadyStateChange.apply(request, args);
if (retryOptions.retryableStatusCodes.includes(request.status)) {
const errorMessage = `Attempt to request ${url} failed.`;
const attemptFailedError = new Error(errorMessage);
operation.retry(attemptFailedError);
}
};
/** Call open only on retry (after headers and other things were set in the xhr instance) */
if (currentAttempt > 1) {
console.warn(`Requesting ${url}... (attempt: ${currentAttempt})`);
request.open(method, url, true);
}
});
originalRequestSend.apply(request, args);
}
/** Overriding/extending XHR function */
const originalRequestSend = request.send;
request.send = faultTolerantRequestSend;
return request;
};
/**
* Returns a configured retry request hook function
* that can be used to add retry functionality to XHR request.
*
* Default options:
* retries: 5
* factor: 3
* minTimeout: 1 * 1000
* maxTimeout: 60 * 1000
* randomize: true
*
* @param {object} options
* @param {number} options.retires number of retries
* @param {number} options.factor factor
* @param {number} options.minTimeout the min timeout
* @param {number} options.maxTimeout the max timeout
* @param {boolean} options.randomize randomize
* @param {array} options.retryableStatusCodes status codes that can trigger retry
* @returns {function} the configured retry request function
*/
export const getXHRRetryRequestHook = (options = {}) => {
retryOptions = { ...defaultRetryOptions };
if ('retries' in options) {
retryOptions.retries = options.retries;
}
if ('factor' in options) {
retryOptions.factor = options.factor;
}
if ('minTimeout' in options) {
retryOptions.minTimeout = options.minTimeout;
}
if ('maxTimeout' in options) {
retryOptions.maxTimeout = options.maxTimeout;
}
if ('randomize' in options) {
retryOptions.randomize = options.randomize;
}
if ('retryableStatusCodes' in options) {
retryOptions.retryableStatusCodes = options.retryableStatusCodes;
}
return xhrRetryRequestHook;
};
export default getXHRRetryRequestHook;
+7
View File
@@ -41,6 +41,13 @@ module.exports = (env, argv) => {
path: DIST_DIR,
filename: isProdBuild ? '[name].bundle.[chunkhash].js' : '[name].js',
publicPath: PUBLIC_URL, // Used by HtmlWebPackPlugin for asset prefix
devtoolModuleFilenameTemplate: function(info) {
if (isProdBuild) {
return `webpack:///${info.resourcePath}`;
} else {
return 'file:///' + encodeURI(info.absoluteResourcePath);
}
},
},
module: {
rules: [...extractStyleChunksRule(isProdBuild)],
+38
View File
@@ -3,6 +3,44 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [4.9.23](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.9.22...@ohif/viewer@4.9.23) (2021-08-30)
### Bug Fixes
* MPR metadata parsing for spacings ([#2517](https://github.com/OHIF/Viewers/issues/2517)) ([715dfc5](https://github.com/OHIF/Viewers/commit/715dfc556a3883de31d74012dcc99e431d91f57d))
## [4.9.22](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.9.21...@ohif/viewer@4.9.22) (2021-08-19)
### Bug Fixes
* Remove internet dependency for workbox (addressing [#2109](https://github.com/OHIF/Viewers/issues/2109)) ([#2151](https://github.com/OHIF/Viewers/issues/2151)) ([5f92f6e](https://github.com/OHIF/Viewers/commit/5f92f6ec7faa11d3fdc33ef8f22971a0bab87a36))
## [4.9.21](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.9.20...@ohif/viewer@4.9.21) (2021-07-26)
**Note:** Version bump only for package @ohif/viewer
## [4.9.20](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.9.19...@ohif/viewer@4.9.20) (2021-06-03)
**Note:** Version bump only for package @ohif/viewer
## [4.9.19](https://github.com/OHIF/Viewers/compare/@ohif/viewer@4.9.18...@ohif/viewer@4.9.19) (2021-06-03)
**Note:** Version bump only for package @ohif/viewer
+6 -6
View File
@@ -1,6 +1,6 @@
{
"name": "@ohif/viewer",
"version": "4.9.19",
"version": "4.9.23",
"description": "OHIF Viewer",
"author": "OHIF Contributors",
"license": "MIT",
@@ -49,16 +49,16 @@
},
"dependencies": {
"@babel/runtime": "^7.5.5",
"@ohif/core": "^2.13.12",
"@ohif/extension-cornerstone": "^2.10.9",
"@ohif/extension-debugging": "^0.2.1",
"@ohif/core": "^2.13.14",
"@ohif/extension-cornerstone": "^2.10.10",
"@ohif/extension-debugging": "^0.2.2",
"@ohif/extension-dicom-html": "^1.3.10",
"@ohif/extension-dicom-microscopy": "^0.52.0",
"@ohif/extension-dicom-pdf": "^1.0.6",
"@ohif/extension-dicom-rt": "^0.6.13",
"@ohif/extension-dicom-segmentation": "^0.6.10",
"@ohif/extension-lesion-tracker": "^0.2.1",
"@ohif/extension-vtk": "^1.11.13",
"@ohif/extension-vtk": "^1.11.15",
"@ohif/i18n": "^0.53.0",
"@ohif/ui": "^1.9.2",
"@tanem/react-nprogress": "^1.1.25",
@@ -70,7 +70,7 @@
"cornerstone-wado-image-loader": "^3.1.0",
"dcmjs": "0.18.8",
"dicom-parser": "^1.8.3",
"dicomweb-client": "^0.4.4",
"dicomweb-client": "^0.8.1",
"hammerjs": "^2.0.8",
"i18next": "^17.0.3",
"i18next-browser-languagedetector": "^3.0.1",
+1 -1
View File
@@ -124,6 +124,6 @@ window.config = {
// If the server is particularly slow to respond to series metadata
// requests as it extracts the metadata from raw files everytime,
// try setting this to even lower value
// Leave it undefined for no limit, sutiable for HTTP/2 enabled servers
// Leave it undefined for no limit, suitable for HTTP/2 enabled servers
// maxConcurrentMetadataRequests: 5,
};
+12 -1
View File
@@ -3,7 +3,17 @@
// modules, so it's perfectly fine to serve this code to any browsers
// (older browsers will just ignore it)
//
import { Workbox } from 'https://storage.googleapis.com/workbox-cdn/releases/5.0.0-beta.1/workbox-window.prod.mjs';
// The workbox code is locally stored and can be updated
// by running `npx workbox-cli copyLibraries platform/viewer/public/third_party/workbox`
// from the root directory.
// Since the workbox version may change with copyLibraries ensure that the
// right version is used here and in `service-worker.js`
import { Workbox } from './third_party/workbox/workbox-v5.1.4/workbox-window.dev.mjs';
// Alternatively use the internet version by commenting out the above import and
// replace with this line and do the corresponding change in service-worker.js
// import { Workbox } from 'https://storage.googleapis.com/workbox-cdn/releases/5.0.0-beta.1/workbox-window.prod.mjs';
var supportsServiceWorker = 'serviceWorker' in navigator;
var isNotLocalDevelopment =
@@ -11,6 +21,7 @@ var isNotLocalDevelopment =
if (supportsServiceWorker && isNotLocalDevelopment) {
const swFileLocation = (window.PUBLIC_URL || '/') + 'sw.js';
const wb = new Workbox(swFileLocation);
// Add an event listener to detect when the registered
@@ -0,0 +1,818 @@
this.workbox = this.workbox || {};
this.workbox.backgroundSync = (function (exports, WorkboxError_js, logger_js, assert_js, getFriendlyURL_js, DBWrapper_js) {
'use strict';
try {
self['workbox:background-sync:5.1.4'] && _();
} catch (e) {}
/*
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 DB_VERSION = 3;
const DB_NAME = 'workbox-background-sync';
const OBJECT_STORE_NAME = 'requests';
const INDEXED_PROP = 'queueName';
/**
* A class to manage storing requests from a Queue in IndexedDB,
* indexed by their queue name for easier access.
*
* @private
*/
class QueueStore {
/**
* Associates this instance with a Queue instance, so entries added can be
* identified by their queue name.
*
* @param {string} queueName
* @private
*/
constructor(queueName) {
this._queueName = queueName;
this._db = new DBWrapper_js.DBWrapper(DB_NAME, DB_VERSION, {
onupgradeneeded: this._upgradeDb
});
}
/**
* Append an entry last in the queue.
*
* @param {Object} entry
* @param {Object} entry.requestData
* @param {number} [entry.timestamp]
* @param {Object} [entry.metadata]
* @private
*/
async pushEntry(entry) {
{
assert_js.assert.isType(entry, 'object', {
moduleName: 'workbox-background-sync',
className: 'QueueStore',
funcName: 'pushEntry',
paramName: 'entry'
});
assert_js.assert.isType(entry.requestData, 'object', {
moduleName: 'workbox-background-sync',
className: 'QueueStore',
funcName: 'pushEntry',
paramName: 'entry.requestData'
});
} // Don't specify an ID since one is automatically generated.
delete entry.id;
entry.queueName = this._queueName;
await this._db.add(OBJECT_STORE_NAME, entry);
}
/**
* Prepend an entry first in the queue.
*
* @param {Object} entry
* @param {Object} entry.requestData
* @param {number} [entry.timestamp]
* @param {Object} [entry.metadata]
* @private
*/
async unshiftEntry(entry) {
{
assert_js.assert.isType(entry, 'object', {
moduleName: 'workbox-background-sync',
className: 'QueueStore',
funcName: 'unshiftEntry',
paramName: 'entry'
});
assert_js.assert.isType(entry.requestData, 'object', {
moduleName: 'workbox-background-sync',
className: 'QueueStore',
funcName: 'unshiftEntry',
paramName: 'entry.requestData'
});
}
const [firstEntry] = await this._db.getAllMatching(OBJECT_STORE_NAME, {
count: 1
});
if (firstEntry) {
// Pick an ID one less than the lowest ID in the object store.
entry.id = firstEntry.id - 1;
} else {
// Otherwise let the auto-incrementor assign the ID.
delete entry.id;
}
entry.queueName = this._queueName;
await this._db.add(OBJECT_STORE_NAME, entry);
}
/**
* Removes and returns the last entry in the queue matching the `queueName`.
*
* @return {Promise<Object>}
* @private
*/
async popEntry() {
return this._removeEntry({
direction: 'prev'
});
}
/**
* Removes and returns the first entry in the queue matching the `queueName`.
*
* @return {Promise<Object>}
* @private
*/
async shiftEntry() {
return this._removeEntry({
direction: 'next'
});
}
/**
* Returns all entries in the store matching the `queueName`.
*
* @param {Object} options See {@link module:workbox-background-sync.Queue~getAll}
* @return {Promise<Array<Object>>}
* @private
*/
async getAll() {
return await this._db.getAllMatching(OBJECT_STORE_NAME, {
index: INDEXED_PROP,
query: IDBKeyRange.only(this._queueName)
});
}
/**
* Deletes the entry for the given ID.
*
* WARNING: this method does not ensure the deleted enry belongs to this
* queue (i.e. matches the `queueName`). But this limitation is acceptable
* as this class is not publicly exposed. An additional check would make
* this method slower than it needs to be.
*
* @private
* @param {number} id
*/
async deleteEntry(id) {
await this._db.delete(OBJECT_STORE_NAME, id);
}
/**
* Removes and returns the first or last entry in the queue (based on the
* `direction` argument) matching the `queueName`.
*
* @return {Promise<Object>}
* @private
*/
async _removeEntry({
direction
}) {
const [entry] = await this._db.getAllMatching(OBJECT_STORE_NAME, {
direction,
index: INDEXED_PROP,
query: IDBKeyRange.only(this._queueName),
count: 1
});
if (entry) {
await this.deleteEntry(entry.id);
return entry;
}
}
/**
* Upgrades the database given an `upgradeneeded` event.
*
* @param {Event} event
* @private
*/
_upgradeDb(event) {
const db = event.target.result;
if (event.oldVersion > 0 && event.oldVersion < DB_VERSION) {
if (db.objectStoreNames.contains(OBJECT_STORE_NAME)) {
db.deleteObjectStore(OBJECT_STORE_NAME);
}
}
const objStore = db.createObjectStore(OBJECT_STORE_NAME, {
autoIncrement: true,
keyPath: 'id'
});
objStore.createIndex(INDEXED_PROP, INDEXED_PROP, {
unique: false
});
}
}
/*
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 serializableProperties = ['method', 'referrer', 'referrerPolicy', 'mode', 'credentials', 'cache', 'redirect', 'integrity', 'keepalive'];
/**
* A class to make it easier to serialize and de-serialize requests so they
* can be stored in IndexedDB.
*
* @private
*/
class StorableRequest {
/**
* Accepts an object of request data that can be used to construct a
* `Request` but can also be stored in IndexedDB.
*
* @param {Object} requestData An object of request data that includes the
* `url` plus any relevant properties of
* [requestInit]{@link https://fetch.spec.whatwg.org/#requestinit}.
* @private
*/
constructor(requestData) {
{
assert_js.assert.isType(requestData, 'object', {
moduleName: 'workbox-background-sync',
className: 'StorableRequest',
funcName: 'constructor',
paramName: 'requestData'
});
assert_js.assert.isType(requestData.url, 'string', {
moduleName: 'workbox-background-sync',
className: 'StorableRequest',
funcName: 'constructor',
paramName: 'requestData.url'
});
} // If the request's mode is `navigate`, convert it to `same-origin` since
// navigation requests can't be constructed via script.
if (requestData['mode'] === 'navigate') {
requestData['mode'] = 'same-origin';
}
this._requestData = requestData;
}
/**
* Converts a Request object to a plain object that can be structured
* cloned or JSON-stringified.
*
* @param {Request} request
* @return {Promise<StorableRequest>}
*
* @private
*/
static async fromRequest(request) {
const requestData = {
url: request.url,
headers: {}
}; // Set the body if present.
if (request.method !== 'GET') {
// Use ArrayBuffer to support non-text request bodies.
// NOTE: we can't use Blobs becuse Safari doesn't support storing
// Blobs in IndexedDB in some cases:
// https://github.com/dfahlander/Dexie.js/issues/618#issuecomment-398348457
requestData.body = await request.clone().arrayBuffer();
} // Convert the headers from an iterable to an object.
for (const [key, value] of request.headers.entries()) {
requestData.headers[key] = value;
} // Add all other serializable request properties
for (const prop of serializableProperties) {
if (request[prop] !== undefined) {
requestData[prop] = request[prop];
}
}
return new StorableRequest(requestData);
}
/**
* Returns a deep clone of the instances `_requestData` object.
*
* @return {Object}
*
* @private
*/
toObject() {
const requestData = Object.assign({}, this._requestData);
requestData.headers = Object.assign({}, this._requestData.headers);
if (requestData.body) {
requestData.body = requestData.body.slice(0);
}
return requestData;
}
/**
* Converts this instance to a Request.
*
* @return {Request}
*
* @private
*/
toRequest() {
return new Request(this._requestData.url, this._requestData);
}
/**
* Creates and returns a deep clone of the instance.
*
* @return {StorableRequest}
*
* @private
*/
clone() {
return new StorableRequest(this.toObject());
}
}
/*
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 TAG_PREFIX = 'workbox-background-sync';
const MAX_RETENTION_TIME = 60 * 24 * 7; // 7 days in minutes
const queueNames = new Set();
/**
* Converts a QueueStore entry into the format exposed by Queue. This entails
* converting the request data into a real request and omitting the `id` and
* `queueName` properties.
*
* @param {Object} queueStoreEntry
* @return {Object}
* @private
*/
const convertEntry = queueStoreEntry => {
const queueEntry = {
request: new StorableRequest(queueStoreEntry.requestData).toRequest(),
timestamp: queueStoreEntry.timestamp
};
if (queueStoreEntry.metadata) {
queueEntry.metadata = queueStoreEntry.metadata;
}
return queueEntry;
};
/**
* A class to manage storing failed requests in IndexedDB and retrying them
* later. All parts of the storing and replaying process are observable via
* callbacks.
*
* @memberof module:workbox-background-sync
*/
class Queue {
/**
* Creates an instance of Queue with the given options
*
* @param {string} name The unique name for this queue. This name must be
* unique as it's used to register sync events and store requests
* in IndexedDB specific to this instance. An error will be thrown if
* a duplicate name is detected.
* @param {Object} [options]
* @param {Function} [options.onSync] A function that gets invoked whenever
* the 'sync' event fires. The function is invoked with an object
* containing the `queue` property (referencing this instance), and you
* can use the callback to customize the replay behavior of the queue.
* When not set the `replayRequests()` method is called.
* Note: if the replay fails after a sync event, make sure you throw an
* error, so the browser knows to retry the sync event later.
* @param {number} [options.maxRetentionTime=7 days] The amount of time (in
* minutes) a request may be retried. After this amount of time has
* passed, the request will be deleted from the queue.
*/
constructor(name, {
onSync,
maxRetentionTime
} = {}) {
this._syncInProgress = false;
this._requestsAddedDuringSync = false; // Ensure the store name is not already being used
if (queueNames.has(name)) {
throw new WorkboxError_js.WorkboxError('duplicate-queue-name', {
name
});
} else {
queueNames.add(name);
}
this._name = name;
this._onSync = onSync || this.replayRequests;
this._maxRetentionTime = maxRetentionTime || MAX_RETENTION_TIME;
this._queueStore = new QueueStore(this._name);
this._addSyncListener();
}
/**
* @return {string}
*/
get name() {
return this._name;
}
/**
* Stores the passed request in IndexedDB (with its timestamp and any
* metadata) at the end of the queue.
*
* @param {Object} entry
* @param {Request} entry.request The request to store in the queue.
* @param {Object} [entry.metadata] Any metadata you want associated with the
* stored request. When requests are replayed you'll have access to this
* metadata object in case you need to modify the request beforehand.
* @param {number} [entry.timestamp] The timestamp (Epoch time in
* milliseconds) when the request was first added to the queue. This is
* used along with `maxRetentionTime` to remove outdated requests. In
* general you don't need to set this value, as it's automatically set
* for you (defaulting to `Date.now()`), but you can update it if you
* don't want particular requests to expire.
*/
async pushRequest(entry) {
{
assert_js.assert.isType(entry, 'object', {
moduleName: 'workbox-background-sync',
className: 'Queue',
funcName: 'pushRequest',
paramName: 'entry'
});
assert_js.assert.isInstance(entry.request, Request, {
moduleName: 'workbox-background-sync',
className: 'Queue',
funcName: 'pushRequest',
paramName: 'entry.request'
});
}
await this._addRequest(entry, 'push');
}
/**
* Stores the passed request in IndexedDB (with its timestamp and any
* metadata) at the beginning of the queue.
*
* @param {Object} entry
* @param {Request} entry.request The request to store in the queue.
* @param {Object} [entry.metadata] Any metadata you want associated with the
* stored request. When requests are replayed you'll have access to this
* metadata object in case you need to modify the request beforehand.
* @param {number} [entry.timestamp] The timestamp (Epoch time in
* milliseconds) when the request was first added to the queue. This is
* used along with `maxRetentionTime` to remove outdated requests. In
* general you don't need to set this value, as it's automatically set
* for you (defaulting to `Date.now()`), but you can update it if you
* don't want particular requests to expire.
*/
async unshiftRequest(entry) {
{
assert_js.assert.isType(entry, 'object', {
moduleName: 'workbox-background-sync',
className: 'Queue',
funcName: 'unshiftRequest',
paramName: 'entry'
});
assert_js.assert.isInstance(entry.request, Request, {
moduleName: 'workbox-background-sync',
className: 'Queue',
funcName: 'unshiftRequest',
paramName: 'entry.request'
});
}
await this._addRequest(entry, 'unshift');
}
/**
* Removes and returns the last request in the queue (along with its
* timestamp and any metadata). The returned object takes the form:
* `{request, timestamp, metadata}`.
*
* @return {Promise<Object>}
*/
async popRequest() {
return this._removeRequest('pop');
}
/**
* Removes and returns the first request in the queue (along with its
* timestamp and any metadata). The returned object takes the form:
* `{request, timestamp, metadata}`.
*
* @return {Promise<Object>}
*/
async shiftRequest() {
return this._removeRequest('shift');
}
/**
* Returns all the entries that have not expired (per `maxRetentionTime`).
* Any expired entries are removed from the queue.
*
* @return {Promise<Array<Object>>}
*/
async getAll() {
const allEntries = await this._queueStore.getAll();
const now = Date.now();
const unexpiredEntries = [];
for (const entry of allEntries) {
// Ignore requests older than maxRetentionTime. Call this function
// recursively until an unexpired request is found.
const maxRetentionTimeInMs = this._maxRetentionTime * 60 * 1000;
if (now - entry.timestamp > maxRetentionTimeInMs) {
await this._queueStore.deleteEntry(entry.id);
} else {
unexpiredEntries.push(convertEntry(entry));
}
}
return unexpiredEntries;
}
/**
* Adds the entry to the QueueStore and registers for a sync event.
*
* @param {Object} entry
* @param {Request} entry.request
* @param {Object} [entry.metadata]
* @param {number} [entry.timestamp=Date.now()]
* @param {string} operation ('push' or 'unshift')
* @private
*/
async _addRequest({
request,
metadata,
timestamp = Date.now()
}, operation) {
const storableRequest = await StorableRequest.fromRequest(request.clone());
const entry = {
requestData: storableRequest.toObject(),
timestamp
}; // Only include metadata if it's present.
if (metadata) {
entry.metadata = metadata;
}
await this._queueStore[`${operation}Entry`](entry);
{
logger_js.logger.log(`Request for '${getFriendlyURL_js.getFriendlyURL(request.url)}' has ` + `been added to background sync queue '${this._name}'.`);
} // Don't register for a sync if we're in the middle of a sync. Instead,
// we wait until the sync is complete and call register if
// `this._requestsAddedDuringSync` is true.
if (this._syncInProgress) {
this._requestsAddedDuringSync = true;
} else {
await this.registerSync();
}
}
/**
* Removes and returns the first or last (depending on `operation`) entry
* from the QueueStore that's not older than the `maxRetentionTime`.
*
* @param {string} operation ('pop' or 'shift')
* @return {Object|undefined}
* @private
*/
async _removeRequest(operation) {
const now = Date.now();
const entry = await this._queueStore[`${operation}Entry`]();
if (entry) {
// Ignore requests older than maxRetentionTime. Call this function
// recursively until an unexpired request is found.
const maxRetentionTimeInMs = this._maxRetentionTime * 60 * 1000;
if (now - entry.timestamp > maxRetentionTimeInMs) {
return this._removeRequest(operation);
}
return convertEntry(entry);
} else {
return undefined;
}
}
/**
* Loops through each request in the queue and attempts to re-fetch it.
* If any request fails to re-fetch, it's put back in the same position in
* the queue (which registers a retry for the next sync event).
*/
async replayRequests() {
let entry;
while (entry = await this.shiftRequest()) {
try {
await fetch(entry.request.clone());
if ("dev" !== 'production') {
logger_js.logger.log(`Request for '${getFriendlyURL_js.getFriendlyURL(entry.request.url)}'` + `has been replayed in queue '${this._name}'`);
}
} catch (error) {
await this.unshiftRequest(entry);
{
logger_js.logger.log(`Request for '${getFriendlyURL_js.getFriendlyURL(entry.request.url)}'` + `failed to replay, putting it back in queue '${this._name}'`);
}
throw new WorkboxError_js.WorkboxError('queue-replay-failed', {
name: this._name
});
}
}
{
logger_js.logger.log(`All requests in queue '${this.name}' have successfully ` + `replayed; the queue is now empty!`);
}
}
/**
* Registers a sync event with a tag unique to this instance.
*/
async registerSync() {
if ('sync' in self.registration) {
try {
await self.registration.sync.register(`${TAG_PREFIX}:${this._name}`);
} catch (err) {
// This means the registration failed for some reason, possibly due to
// the user disabling it.
{
logger_js.logger.warn(`Unable to register sync event for '${this._name}'.`, err);
}
}
}
}
/**
* In sync-supporting browsers, this adds a listener for the sync event.
* In non-sync-supporting browsers, this will retry the queue on service
* worker startup.
*
* @private
*/
_addSyncListener() {
if ('sync' in self.registration) {
self.addEventListener('sync', event => {
if (event.tag === `${TAG_PREFIX}:${this._name}`) {
{
logger_js.logger.log(`Background sync for tag '${event.tag}'` + `has been received`);
}
const syncComplete = async () => {
this._syncInProgress = true;
let syncError;
try {
await this._onSync({
queue: this
});
} catch (error) {
syncError = error; // Rethrow the error. Note: the logic in the finally clause
// will run before this gets rethrown.
throw syncError;
} finally {
// New items may have been added to the queue during the sync,
// so we need to register for a new sync if that's happened...
// Unless there was an error during the sync, in which
// case the browser will automatically retry later, as long
// as `event.lastChance` is not true.
if (this._requestsAddedDuringSync && !(syncError && !event.lastChance)) {
await this.registerSync();
}
this._syncInProgress = false;
this._requestsAddedDuringSync = false;
}
};
event.waitUntil(syncComplete());
}
});
} else {
{
logger_js.logger.log(`Background sync replaying without background sync event`);
} // If the browser doesn't support background sync, retry
// every time the service worker starts up as a fallback.
this._onSync({
queue: this
});
}
}
/**
* Returns the set of queue names. This is primarily used to reset the list
* of queue names in tests.
*
* @return {Set}
*
* @private
*/
static get _queueNames() {
return queueNames;
}
}
/*
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.
*/
/**
* A class implementing the `fetchDidFail` lifecycle callback. This makes it
* easier to add failed requests to a background sync Queue.
*
* @memberof module:workbox-background-sync
*/
class BackgroundSyncPlugin {
/**
* @param {string} name See the [Queue]{@link module:workbox-background-sync.Queue}
* documentation for parameter details.
* @param {Object} [options] See the
* [Queue]{@link module:workbox-background-sync.Queue} documentation for
* parameter details.
*/
constructor(name, options) {
/**
* @param {Object} options
* @param {Request} options.request
* @private
*/
this.fetchDidFail = async ({
request
}) => {
await this._queue.pushRequest({
request
});
};
this._queue = new Queue(name, options);
}
}
exports.BackgroundSyncPlugin = BackgroundSyncPlugin;
exports.Queue = Queue;
return exports;
}({}, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private));
//# sourceMappingURL=workbox-background-sync.dev.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-background-sync.dev.js","sources":["../_version.js","../lib/QueueStore.js","../lib/StorableRequest.js","../Queue.js","../BackgroundSyncPlugin.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:background-sync:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { DBWrapper } from 'workbox-core/_private/DBWrapper.js';\nimport '../_version.js';\nconst DB_VERSION = 3;\nconst DB_NAME = 'workbox-background-sync';\nconst OBJECT_STORE_NAME = 'requests';\nconst INDEXED_PROP = 'queueName';\n/**\n * A class to manage storing requests from a Queue in IndexedDB,\n * indexed by their queue name for easier access.\n *\n * @private\n */\nexport class QueueStore {\n /**\n * Associates this instance with a Queue instance, so entries added can be\n * identified by their queue name.\n *\n * @param {string} queueName\n * @private\n */\n constructor(queueName) {\n this._queueName = queueName;\n this._db = new DBWrapper(DB_NAME, DB_VERSION, {\n onupgradeneeded: this._upgradeDb,\n });\n }\n /**\n * Append an entry last in the queue.\n *\n * @param {Object} entry\n * @param {Object} entry.requestData\n * @param {number} [entry.timestamp]\n * @param {Object} [entry.metadata]\n * @private\n */\n async pushEntry(entry) {\n if (process.env.NODE_ENV !== 'production') {\n assert.isType(entry, 'object', {\n moduleName: 'workbox-background-sync',\n className: 'QueueStore',\n funcName: 'pushEntry',\n paramName: 'entry',\n });\n assert.isType(entry.requestData, 'object', {\n moduleName: 'workbox-background-sync',\n className: 'QueueStore',\n funcName: 'pushEntry',\n paramName: 'entry.requestData',\n });\n }\n // Don't specify an ID since one is automatically generated.\n delete entry.id;\n entry.queueName = this._queueName;\n await this._db.add(OBJECT_STORE_NAME, entry);\n }\n /**\n * Prepend an entry first in the queue.\n *\n * @param {Object} entry\n * @param {Object} entry.requestData\n * @param {number} [entry.timestamp]\n * @param {Object} [entry.metadata]\n * @private\n */\n async unshiftEntry(entry) {\n if (process.env.NODE_ENV !== 'production') {\n assert.isType(entry, 'object', {\n moduleName: 'workbox-background-sync',\n className: 'QueueStore',\n funcName: 'unshiftEntry',\n paramName: 'entry',\n });\n assert.isType(entry.requestData, 'object', {\n moduleName: 'workbox-background-sync',\n className: 'QueueStore',\n funcName: 'unshiftEntry',\n paramName: 'entry.requestData',\n });\n }\n const [firstEntry] = await this._db.getAllMatching(OBJECT_STORE_NAME, {\n count: 1,\n });\n if (firstEntry) {\n // Pick an ID one less than the lowest ID in the object store.\n entry.id = firstEntry.id - 1;\n }\n else {\n // Otherwise let the auto-incrementor assign the ID.\n delete entry.id;\n }\n entry.queueName = this._queueName;\n await this._db.add(OBJECT_STORE_NAME, entry);\n }\n /**\n * Removes and returns the last entry in the queue matching the `queueName`.\n *\n * @return {Promise<Object>}\n * @private\n */\n async popEntry() {\n return this._removeEntry({ direction: 'prev' });\n }\n /**\n * Removes and returns the first entry in the queue matching the `queueName`.\n *\n * @return {Promise<Object>}\n * @private\n */\n async shiftEntry() {\n return this._removeEntry({ direction: 'next' });\n }\n /**\n * Returns all entries in the store matching the `queueName`.\n *\n * @param {Object} options See {@link module:workbox-background-sync.Queue~getAll}\n * @return {Promise<Array<Object>>}\n * @private\n */\n async getAll() {\n return await this._db.getAllMatching(OBJECT_STORE_NAME, {\n index: INDEXED_PROP,\n query: IDBKeyRange.only(this._queueName),\n });\n }\n /**\n * Deletes the entry for the given ID.\n *\n * WARNING: this method does not ensure the deleted enry belongs to this\n * queue (i.e. matches the `queueName`). But this limitation is acceptable\n * as this class is not publicly exposed. An additional check would make\n * this method slower than iLine truncated
@@ -0,0 +1,2 @@
this.workbox=this.workbox||{},this.workbox.backgroundSync=function(t,e,s,i,n){"use strict";try{self["workbox:background-sync:5.1.4"]&&_()}catch(t){}class a{constructor(t){this.t=t,this.s=new n.DBWrapper("workbox-background-sync",3,{onupgradeneeded:this.i})}async pushEntry(t){delete t.id,t.queueName=this.t,await this.s.add("requests",t)}async unshiftEntry(t){const[e]=await this.s.getAllMatching("requests",{count:1});e?t.id=e.id-1:delete t.id,t.queueName=this.t,await this.s.add("requests",t)}async popEntry(){return this.h({direction:"prev"})}async shiftEntry(){return this.h({direction:"next"})}async getAll(){return await this.s.getAllMatching("requests",{index:"queueName",query:IDBKeyRange.only(this.t)})}async deleteEntry(t){await this.s.delete("requests",t)}async h({direction:t}){const[e]=await this.s.getAllMatching("requests",{direction:t,index:"queueName",query:IDBKeyRange.only(this.t),count:1});if(e)return await this.deleteEntry(e.id),e}i(t){const e=t.target.result;t.oldVersion>0&&t.oldVersion<3&&e.objectStoreNames.contains("requests")&&e.deleteObjectStore("requests");e.createObjectStore("requests",{autoIncrement:!0,keyPath:"id"}).createIndex("queueName","queueName",{unique:!1})}}const r=["method","referrer","referrerPolicy","mode","credentials","cache","redirect","integrity","keepalive"];class c{constructor(t){"navigate"===t.mode&&(t.mode="same-origin"),this.u=t}static async fromRequest(t){const e={url:t.url,headers:{}};"GET"!==t.method&&(e.body=await t.clone().arrayBuffer());for(const[s,i]of t.headers.entries())e.headers[s]=i;for(const s of r)void 0!==t[s]&&(e[s]=t[s]);return new c(e)}toObject(){const t=Object.assign({},this.u);return t.headers=Object.assign({},this.u.headers),t.body&&(t.body=t.body.slice(0)),t}toRequest(){return new Request(this.u.url,this.u)}clone(){return new c(this.toObject())}}const h=new Set,u=t=>{const e={request:new c(t.requestData).toRequest(),timestamp:t.timestamp};return t.metadata&&(e.metadata=t.metadata),e};class o{constructor(t,{onSync:s,maxRetentionTime:i}={}){if(this.o=!1,this.q=!1,h.has(t))throw new e.WorkboxError("duplicate-queue-name",{name:t});h.add(t),this.l=t,this.m=s||this.replayRequests,this.p=i||10080,this.g=new a(this.l),this.R()}get name(){return this.l}async pushRequest(t){await this.k(t,"push")}async unshiftRequest(t){await this.k(t,"unshift")}async popRequest(){return this.D("pop")}async shiftRequest(){return this.D("shift")}async getAll(){const t=await this.g.getAll(),e=Date.now(),s=[];for(const i of t){const t=60*this.p*1e3;e-i.timestamp>t?await this.g.deleteEntry(i.id):s.push(u(i))}return s}async k({request:t,metadata:e,timestamp:s=Date.now()},i){const n={requestData:(await c.fromRequest(t.clone())).toObject(),timestamp:s};e&&(n.metadata=e),await this.g[i+"Entry"](n),this.o?this.q=!0:await this.registerSync()}async D(t){const e=Date.now(),s=await this.g[t+"Entry"]();if(s){const i=60*this.p*1e3;return e-s.timestamp>i?this.D(t):u(s)}}async replayRequests(){let t;for(;t=await this.shiftRequest();)try{await fetch(t.request.clone())}catch(s){throw await this.unshiftRequest(t),new e.WorkboxError("queue-replay-failed",{name:this.l})}}async registerSync(){if("sync"in self.registration)try{await self.registration.sync.register("workbox-background-sync:"+this.l)}catch(t){}}R(){"sync"in self.registration?self.addEventListener("sync",t=>{if(t.tag==="workbox-background-sync:"+this.l){const e=async()=>{let e;this.o=!0;try{await this.m({queue:this})}catch(t){throw e=t,e}finally{!this.q||e&&!t.lastChance||await this.registerSync(),this.o=!1,this.q=!1}};t.waitUntil(e())}}):this.m({queue:this})}static get _(){return h}}return t.BackgroundSyncPlugin=class{constructor(t,e){this.fetchDidFail=async({request:t})=>{await this.v.pushRequest({request:t})},this.v=new o(t,e)}},t.Queue=o,t}({},workbox.core._private,workbox.core._private,workbox.core._private,workbox.core._private);
//# sourceMappingURL=workbox-background-sync.prod.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-background-sync.prod.js","sources":["../_version.js","../lib/QueueStore.js","../lib/StorableRequest.js","../Queue.js","../BackgroundSyncPlugin.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:background-sync:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { DBWrapper } from 'workbox-core/_private/DBWrapper.js';\nimport '../_version.js';\nconst DB_VERSION = 3;\nconst DB_NAME = 'workbox-background-sync';\nconst OBJECT_STORE_NAME = 'requests';\nconst INDEXED_PROP = 'queueName';\n/**\n * A class to manage storing requests from a Queue in IndexedDB,\n * indexed by their queue name for easier access.\n *\n * @private\n */\nexport class QueueStore {\n /**\n * Associates this instance with a Queue instance, so entries added can be\n * identified by their queue name.\n *\n * @param {string} queueName\n * @private\n */\n constructor(queueName) {\n this._queueName = queueName;\n this._db = new DBWrapper(DB_NAME, DB_VERSION, {\n onupgradeneeded: this._upgradeDb,\n });\n }\n /**\n * Append an entry last in the queue.\n *\n * @param {Object} entry\n * @param {Object} entry.requestData\n * @param {number} [entry.timestamp]\n * @param {Object} [entry.metadata]\n * @private\n */\n async pushEntry(entry) {\n if (process.env.NODE_ENV !== 'production') {\n assert.isType(entry, 'object', {\n moduleName: 'workbox-background-sync',\n className: 'QueueStore',\n funcName: 'pushEntry',\n paramName: 'entry',\n });\n assert.isType(entry.requestData, 'object', {\n moduleName: 'workbox-background-sync',\n className: 'QueueStore',\n funcName: 'pushEntry',\n paramName: 'entry.requestData',\n });\n }\n // Don't specify an ID since one is automatically generated.\n delete entry.id;\n entry.queueName = this._queueName;\n await this._db.add(OBJECT_STORE_NAME, entry);\n }\n /**\n * Prepend an entry first in the queue.\n *\n * @param {Object} entry\n * @param {Object} entry.requestData\n * @param {number} [entry.timestamp]\n * @param {Object} [entry.metadata]\n * @private\n */\n async unshiftEntry(entry) {\n if (process.env.NODE_ENV !== 'production') {\n assert.isType(entry, 'object', {\n moduleName: 'workbox-background-sync',\n className: 'QueueStore',\n funcName: 'unshiftEntry',\n paramName: 'entry',\n });\n assert.isType(entry.requestData, 'object', {\n moduleName: 'workbox-background-sync',\n className: 'QueueStore',\n funcName: 'unshiftEntry',\n paramName: 'entry.requestData',\n });\n }\n const [firstEntry] = await this._db.getAllMatching(OBJECT_STORE_NAME, {\n count: 1,\n });\n if (firstEntry) {\n // Pick an ID one less than the lowest ID in the object store.\n entry.id = firstEntry.id - 1;\n }\n else {\n // Otherwise let the auto-incrementor assign the ID.\n delete entry.id;\n }\n entry.queueName = this._queueName;\n await this._db.add(OBJECT_STORE_NAME, entry);\n }\n /**\n * Removes and returns the last entry in the queue matching the `queueName`.\n *\n * @return {Promise<Object>}\n * @private\n */\n async popEntry() {\n return this._removeEntry({ direction: 'prev' });\n }\n /**\n * Removes and returns the first entry in the queue matching the `queueName`.\n *\n * @return {Promise<Object>}\n * @private\n */\n async shiftEntry() {\n return this._removeEntry({ direction: 'next' });\n }\n /**\n * Returns all entries in the store matching the `queueName`.\n *\n * @param {Object} options See {@link module:workbox-background-sync.Queue~getAll}\n * @return {Promise<Array<Object>>}\n * @private\n */\n async getAll() {\n return await this._db.getAllMatching(OBJECT_STORE_NAME, {\n index: INDEXED_PROP,\n query: IDBKeyRange.only(this._queueName),\n });\n }\n /**\n * Deletes the entry for the given ID.\n *\n * WARNING: this method does not ensure the deleted enry belongs to this\n * queue (i.e. matches the `queueName`). But this limitation is acceptable\n * as this class is not publicly exposed. An additional check would make\n * this method slower than Line truncated
@@ -0,0 +1,288 @@
this.workbox = this.workbox || {};
this.workbox.broadcastUpdate = (function (exports, assert_js, timeout_js, resultingClientExists_js, logger_js, WorkboxError_js, dontWaitFor_js) {
'use strict';
try {
self['workbox:broadcast-update:5.1.4'] && _();
} catch (e) {}
/*
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.
*/
/**
* Given two `Response's`, compares several header values to see if they are
* the same or not.
*
* @param {Response} firstResponse
* @param {Response} secondResponse
* @param {Array<string>} headersToCheck
* @return {boolean}
*
* @memberof module:workbox-broadcast-update
*/
const responsesAreSame = (firstResponse, secondResponse, headersToCheck) => {
{
if (!(firstResponse instanceof Response && secondResponse instanceof Response)) {
throw new WorkboxError_js.WorkboxError('invalid-responses-are-same-args');
}
}
const atLeastOneHeaderAvailable = headersToCheck.some(header => {
return firstResponse.headers.has(header) && secondResponse.headers.has(header);
});
if (!atLeastOneHeaderAvailable) {
{
logger_js.logger.warn(`Unable to determine where the response has been updated ` + `because none of the headers that would be checked are present.`);
logger_js.logger.debug(`Attempting to compare the following: `, firstResponse, secondResponse, headersToCheck);
} // Just return true, indicating the that responses are the same, since we
// can't determine otherwise.
return true;
}
return headersToCheck.every(header => {
const headerStateComparison = firstResponse.headers.has(header) === secondResponse.headers.has(header);
const headerValueComparison = firstResponse.headers.get(header) === secondResponse.headers.get(header);
return headerStateComparison && headerValueComparison;
});
};
/*
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 CACHE_UPDATED_MESSAGE_TYPE = 'CACHE_UPDATED';
const CACHE_UPDATED_MESSAGE_META = 'workbox-broadcast-update';
const DEFAULT_HEADERS_TO_CHECK = ['content-length', 'etag', 'last-modified'];
/*
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 once this Safari bug fix has been released.
// https://bugs.webkit.org/show_bug.cgi?id=201169
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
/**
* Generates the default payload used in update messages. By default the
* payload includes the `cacheName` and `updatedURL` fields.
*
* @return Object
* @private
*/
function defaultPayloadGenerator(data) {
return {
cacheName: data.cacheName,
updatedURL: data.request.url
};
}
/**
* Uses the `postMessage()` API to inform any open windows/tabs when a cached
* response has been updated.
*
* For efficiency's sake, the underlying response bodies are not compared;
* only specific response headers are checked.
*
* @memberof module:workbox-broadcast-update
*/
class BroadcastCacheUpdate {
/**
* Construct a BroadcastCacheUpdate instance with a specific `channelName` to
* broadcast messages on
*
* @param {Object} options
* @param {Array<string>} [options.headersToCheck=['content-length', 'etag', 'last-modified']]
* A list of headers that will be used to determine whether the responses
* differ.
* @param {string} [options.generatePayload] A function whose return value
* will be used as the `payload` field in any cache update messages sent
* to the window clients.
*/
constructor({
headersToCheck,
generatePayload
} = {}) {
this._headersToCheck = headersToCheck || DEFAULT_HEADERS_TO_CHECK;
this._generatePayload = generatePayload || defaultPayloadGenerator;
}
/**
* Compares two [Responses](https://developer.mozilla.org/en-US/docs/Web/API/Response)
* and sends a message (via `postMessage()`) to all window clients if the
* responses differ (note: neither of the Responses can be
* {@link http://stackoverflow.com/questions/39109789|opaque}).
*
* The message that's posted has the following format (where `payload` can
* be customized via the `generatePayload` option the instance is created
* with):
*
* ```
* {
* type: 'CACHE_UPDATED',
* meta: 'workbox-broadcast-update',
* payload: {
* cacheName: 'the-cache-name',
* updatedURL: 'https://example.com/'
* }
* }
* ```
*
* @param {Object} options
* @param {Response} [options.oldResponse] Cached response to compare.
* @param {Response} options.newResponse Possibly updated response to compare.
* @param {Request} options.request The request.
* @param {string} options.cacheName Name of the cache the responses belong
* to. This is included in the broadcast message.
* @param {Event} [options.event] event An optional event that triggered
* this possible cache update.
* @return {Promise} Resolves once the update is sent.
*/
async notifyIfUpdated(options) {
{
assert_js.assert.isType(options.cacheName, 'string', {
moduleName: 'workbox-broadcast-update',
className: 'BroadcastCacheUpdate',
funcName: 'notifyIfUpdated',
paramName: 'cacheName'
});
assert_js.assert.isInstance(options.newResponse, Response, {
moduleName: 'workbox-broadcast-update',
className: 'BroadcastCacheUpdate',
funcName: 'notifyIfUpdated',
paramName: 'newResponse'
});
assert_js.assert.isInstance(options.request, Request, {
moduleName: 'workbox-broadcast-update',
className: 'BroadcastCacheUpdate',
funcName: 'notifyIfUpdated',
paramName: 'request'
});
} // Without two responses there is nothing to compare.
if (!options.oldResponse) {
return;
}
if (!responsesAreSame(options.oldResponse, options.newResponse, this._headersToCheck)) {
{
logger_js.logger.log(`Newer response found (and cached) for:`, options.request.url);
}
const messageData = {
type: CACHE_UPDATED_MESSAGE_TYPE,
meta: CACHE_UPDATED_MESSAGE_META,
payload: this._generatePayload(options)
}; // For navigation requests, wait until the new window client exists
// before sending the message
if (options.request.mode === 'navigate') {
let resultingClientId;
if (options.event instanceof FetchEvent) {
resultingClientId = options.event.resultingClientId;
}
const resultingWin = await resultingClientExists_js.resultingClientExists(resultingClientId); // Safari does not currently implement postMessage buffering and
// there's no good way to feature detect that, so to increase the
// chances of the message being delivered in Safari, we add a timeout.
// We also do this if `resultingClientExists()` didn't return a client,
// which means it timed out, so it's worth waiting a bit longer.
if (!resultingWin || isSafari) {
// 3500 is chosen because (according to CrUX data) 80% of mobile
// websites hit the DOMContentLoaded event in less than 3.5 seconds.
// And presumably sites implementing service worker are on the
// higher end of the performance spectrum.
await timeout_js.timeout(3500);
}
}
const windows = await self.clients.matchAll({
type: 'window'
});
for (const win of windows) {
win.postMessage(messageData);
}
}
}
}
/*
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 plugin will automatically broadcast a message whenever a cached response
* is updated.
*
* @memberof module:workbox-broadcast-update
*/
class BroadcastUpdatePlugin {
/**
* Construct a BroadcastCacheUpdate instance with the passed options and
* calls its [`notifyIfUpdated()`]{@link module:workbox-broadcast-update.BroadcastCacheUpdate~notifyIfUpdated}
* method whenever the plugin's `cacheDidUpdate` callback is invoked.
*
* @param {Object} options
* @param {Array<string>} [options.headersToCheck=['content-length', 'etag', 'last-modified']]
* A list of headers that will be used to determine whether the responses
* differ.
* @param {string} [options.generatePayload] A function whose return value
* will be used as the `payload` field in any cache update messages sent
* to the window clients.
*/
constructor(options) {
/**
* A "lifecycle" callback that will be triggered automatically by the
* `workbox-sw` and `workbox-runtime-caching` handlers when an entry is
* added to a cache.
*
* @private
* @param {Object} options The input object to this function.
* @param {string} options.cacheName Name of the cache being updated.
* @param {Response} [options.oldResponse] The previous cached value, if any.
* @param {Response} options.newResponse The new value in the cache.
* @param {Request} options.request The request that triggered the update.
* @param {Request} [options.event] The event that triggered the update.
*/
this.cacheDidUpdate = async options => {
dontWaitFor_js.dontWaitFor(this._broadcastUpdate.notifyIfUpdated(options));
};
this._broadcastUpdate = new BroadcastCacheUpdate(options);
}
}
exports.BroadcastCacheUpdate = BroadcastCacheUpdate;
exports.BroadcastUpdatePlugin = BroadcastUpdatePlugin;
exports.responsesAreSame = responsesAreSame;
return exports;
}({}, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private));
//# sourceMappingURL=workbox-broadcast-update.dev.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-broadcast-update.dev.js","sources":["../_version.js","../responsesAreSame.js","../utils/constants.js","../BroadcastCacheUpdate.js","../BroadcastUpdatePlugin.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:broadcast-update:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport './_version.js';\n/**\n * Given two `Response's`, compares several header values to see if they are\n * the same or not.\n *\n * @param {Response} firstResponse\n * @param {Response} secondResponse\n * @param {Array<string>} headersToCheck\n * @return {boolean}\n *\n * @memberof module:workbox-broadcast-update\n */\nconst responsesAreSame = (firstResponse, secondResponse, headersToCheck) => {\n if (process.env.NODE_ENV !== 'production') {\n if (!(firstResponse instanceof Response &&\n secondResponse instanceof Response)) {\n throw new WorkboxError('invalid-responses-are-same-args');\n }\n }\n const atLeastOneHeaderAvailable = headersToCheck.some((header) => {\n return firstResponse.headers.has(header) &&\n secondResponse.headers.has(header);\n });\n if (!atLeastOneHeaderAvailable) {\n if (process.env.NODE_ENV !== 'production') {\n logger.warn(`Unable to determine where the response has been updated ` +\n `because none of the headers that would be checked are present.`);\n logger.debug(`Attempting to compare the following: `, firstResponse, secondResponse, headersToCheck);\n }\n // Just return true, indicating the that responses are the same, since we\n // can't determine otherwise.\n return true;\n }\n return headersToCheck.every((header) => {\n const headerStateComparison = firstResponse.headers.has(header) ===\n secondResponse.headers.has(header);\n const headerValueComparison = firstResponse.headers.get(header) ===\n secondResponse.headers.get(header);\n return headerStateComparison && headerValueComparison;\n });\n};\nexport { responsesAreSame };\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\nexport const CACHE_UPDATED_MESSAGE_TYPE = 'CACHE_UPDATED';\nexport const CACHE_UPDATED_MESSAGE_META = 'workbox-broadcast-update';\nexport const DEFAULT_HEADERS_TO_CHECK = [\n 'content-length',\n 'etag',\n 'last-modified',\n];\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { timeout } from 'workbox-core/_private/timeout.js';\nimport { resultingClientExists } from 'workbox-core/_private/resultingClientExists.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { responsesAreSame } from './responsesAreSame.js';\nimport { CACHE_UPDATED_MESSAGE_TYPE, CACHE_UPDATED_MESSAGE_META, DEFAULT_HEADERS_TO_CHECK } from './utils/constants.js';\nimport './_version.js';\n// UA-sniff Safari: https://stackoverflow.com/questions/7944460/detect-safari-browser\n// TODO(philipwalton): remove once this Safari bug fix has been released.\n// https://bugs.webkit.org/show_bug.cgi?id=201169\nconst isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n/**\n * Generates the default payload used in update messages. By default the\n * payload includes the `cacheName` and `updatedURL` fields.\n *\n * @return Object\n * @private\n */\nfunction defaultPayloadGenerator(data) {\n return {\n cacheName: data.cacheName,\n updatedURL: data.request.url,\n };\n}\n/**\n * Uses the `postMessage()` API to inform any open windows/tabs when a cached\n * response has been updated.\n *\n * For efficiency's sake, the underlying response bodies are not compared;\n * only specific response headers are checked.\n *\n * @memberof module:workbox-broadcast-update\n */\nclass BroadcastCacheUpdate {\n /**\n * Construct a BroadcastCacheUpdate instance with a specific `channelName` to\n * broadcast messages on\n *\n * @param {Object} options\n * @param {Array<string>} [options.headersToCheck=['content-length', 'etag', 'last-modified']]\n * A list of headers that will be used to determine whether the responses\n * differ.\n * @param {string} [options.generatePayload] A function whose return value\n * will be used as the `payload` field in any cache update messaLine truncated
@@ -0,0 +1,2 @@
this.workbox=this.workbox||{},this.workbox.broadcastUpdate=function(t,a,o,s){"use strict";try{self["workbox:broadcast-update:5.1.4"]&&_()}catch(t){}const e=(t,a,o)=>!o.some(o=>t.headers.has(o)&&a.headers.has(o))||o.every(o=>{const s=t.headers.has(o)===a.headers.has(o),e=t.headers.get(o)===a.headers.get(o);return s&&e}),n=["content-length","etag","last-modified"],i=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);function c(t){return{cacheName:t.cacheName,updatedURL:t.request.url}}class r{constructor({headersToCheck:t,generatePayload:a}={}){this.t=t||n,this.o=a||c}async notifyIfUpdated(t){if(t.oldResponse&&!e(t.oldResponse,t.newResponse,this.t)){const s={type:"CACHE_UPDATED",meta:"workbox-broadcast-update",payload:this.o(t)};if("navigate"===t.request.mode){let s;t.event instanceof FetchEvent&&(s=t.event.resultingClientId);await o.resultingClientExists(s)&&!i||await a.timeout(3500)}const e=await self.clients.matchAll({type:"window"});for(const t of e)t.postMessage(s)}}}return t.BroadcastCacheUpdate=r,t.BroadcastUpdatePlugin=class{constructor(t){this.cacheDidUpdate=async t=>{s.dontWaitFor(this.s.notifyIfUpdated(t))},this.s=new r(t)}},t.responsesAreSame=e,t}({},workbox.core._private,workbox.core._private,workbox.core._private);
//# sourceMappingURL=workbox-broadcast-update.prod.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-broadcast-update.prod.js","sources":["../_version.js","../responsesAreSame.js","../utils/constants.js","../BroadcastCacheUpdate.js","../BroadcastUpdatePlugin.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:broadcast-update:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport './_version.js';\n/**\n * Given two `Response's`, compares several header values to see if they are\n * the same or not.\n *\n * @param {Response} firstResponse\n * @param {Response} secondResponse\n * @param {Array<string>} headersToCheck\n * @return {boolean}\n *\n * @memberof module:workbox-broadcast-update\n */\nconst responsesAreSame = (firstResponse, secondResponse, headersToCheck) => {\n if (process.env.NODE_ENV !== 'production') {\n if (!(firstResponse instanceof Response &&\n secondResponse instanceof Response)) {\n throw new WorkboxError('invalid-responses-are-same-args');\n }\n }\n const atLeastOneHeaderAvailable = headersToCheck.some((header) => {\n return firstResponse.headers.has(header) &&\n secondResponse.headers.has(header);\n });\n if (!atLeastOneHeaderAvailable) {\n if (process.env.NODE_ENV !== 'production') {\n logger.warn(`Unable to determine where the response has been updated ` +\n `because none of the headers that would be checked are present.`);\n logger.debug(`Attempting to compare the following: `, firstResponse, secondResponse, headersToCheck);\n }\n // Just return true, indicating the that responses are the same, since we\n // can't determine otherwise.\n return true;\n }\n return headersToCheck.every((header) => {\n const headerStateComparison = firstResponse.headers.has(header) ===\n secondResponse.headers.has(header);\n const headerValueComparison = firstResponse.headers.get(header) ===\n secondResponse.headers.get(header);\n return headerStateComparison && headerValueComparison;\n });\n};\nexport { responsesAreSame };\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\nexport const CACHE_UPDATED_MESSAGE_TYPE = 'CACHE_UPDATED';\nexport const CACHE_UPDATED_MESSAGE_META = 'workbox-broadcast-update';\nexport const DEFAULT_HEADERS_TO_CHECK = [\n 'content-length',\n 'etag',\n 'last-modified',\n];\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { timeout } from 'workbox-core/_private/timeout.js';\nimport { resultingClientExists } from 'workbox-core/_private/resultingClientExists.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { responsesAreSame } from './responsesAreSame.js';\nimport { CACHE_UPDATED_MESSAGE_TYPE, CACHE_UPDATED_MESSAGE_META, DEFAULT_HEADERS_TO_CHECK } from './utils/constants.js';\nimport './_version.js';\n// UA-sniff Safari: https://stackoverflow.com/questions/7944460/detect-safari-browser\n// TODO(philipwalton): remove once this Safari bug fix has been released.\n// https://bugs.webkit.org/show_bug.cgi?id=201169\nconst isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n/**\n * Generates the default payload used in update messages. By default the\n * payload includes the `cacheName` and `updatedURL` fields.\n *\n * @return Object\n * @private\n */\nfunction defaultPayloadGenerator(data) {\n return {\n cacheName: data.cacheName,\n updatedURL: data.request.url,\n };\n}\n/**\n * Uses the `postMessage()` API to inform any open windows/tabs when a cached\n * response has been updated.\n *\n * For efficiency's sake, the underlying response bodies are not compared;\n * only specific response headers are checked.\n *\n * @memberof module:workbox-broadcast-update\n */\nclass BroadcastCacheUpdate {\n /**\n * Construct a BroadcastCacheUpdate instance with a specific `channelName` to\n * broadcast messages on\n *\n * @param {Object} options\n * @param {Array<string>} [options.headersToCheck=['content-length', 'etag', 'last-modified']]\n * A list of headers that will be used to determine whether the responses\n * differ.\n * @param {string} [options.generatePayload] A function whose return value\n * will be used as the `payload` field in any cache update messLine truncated
@@ -0,0 +1,191 @@
this.workbox = this.workbox || {};
this.workbox.cacheableResponse = (function (exports, assert_js, WorkboxError_js, getFriendlyURL_js, logger_js) {
'use strict';
try {
self['workbox:cacheable-response:5.1.4'] && _();
} catch (e) {}
/*
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 class allows you to set up rules determining what
* status codes and/or headers need to be present in order for a
* [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
* to be considered cacheable.
*
* @memberof module:workbox-cacheable-response
*/
class CacheableResponse {
/**
* To construct a new CacheableResponse instance you must provide at least
* one of the `config` properties.
*
* If both `statuses` and `headers` are specified, then both conditions must
* be met for the `Response` to be considered cacheable.
*
* @param {Object} config
* @param {Array<number>} [config.statuses] One or more status codes that a
* `Response` can have and be considered cacheable.
* @param {Object<string,string>} [config.headers] A mapping of header names
* and expected values that a `Response` can have and be considered cacheable.
* If multiple headers are provided, only one needs to be present.
*/
constructor(config = {}) {
{
if (!(config.statuses || config.headers)) {
throw new WorkboxError_js.WorkboxError('statuses-or-headers-required', {
moduleName: 'workbox-cacheable-response',
className: 'CacheableResponse',
funcName: 'constructor'
});
}
if (config.statuses) {
assert_js.assert.isArray(config.statuses, {
moduleName: 'workbox-cacheable-response',
className: 'CacheableResponse',
funcName: 'constructor',
paramName: 'config.statuses'
});
}
if (config.headers) {
assert_js.assert.isType(config.headers, 'object', {
moduleName: 'workbox-cacheable-response',
className: 'CacheableResponse',
funcName: 'constructor',
paramName: 'config.headers'
});
}
}
this._statuses = config.statuses;
this._headers = config.headers;
}
/**
* Checks a response to see whether it's cacheable or not, based on this
* object's configuration.
*
* @param {Response} response The response whose cacheability is being
* checked.
* @return {boolean} `true` if the `Response` is cacheable, and `false`
* otherwise.
*/
isResponseCacheable(response) {
{
assert_js.assert.isInstance(response, Response, {
moduleName: 'workbox-cacheable-response',
className: 'CacheableResponse',
funcName: 'isResponseCacheable',
paramName: 'response'
});
}
let cacheable = true;
if (this._statuses) {
cacheable = this._statuses.includes(response.status);
}
if (this._headers && cacheable) {
cacheable = Object.keys(this._headers).some(headerName => {
return response.headers.get(headerName) === this._headers[headerName];
});
}
{
if (!cacheable) {
logger_js.logger.groupCollapsed(`The request for ` + `'${getFriendlyURL_js.getFriendlyURL(response.url)}' returned a response that does ` + `not meet the criteria for being cached.`);
logger_js.logger.groupCollapsed(`View cacheability criteria here.`);
logger_js.logger.log(`Cacheable statuses: ` + JSON.stringify(this._statuses));
logger_js.logger.log(`Cacheable headers: ` + JSON.stringify(this._headers, null, 2));
logger_js.logger.groupEnd();
const logFriendlyHeaders = {};
response.headers.forEach((value, key) => {
logFriendlyHeaders[key] = value;
});
logger_js.logger.groupCollapsed(`View response status and headers here.`);
logger_js.logger.log(`Response status: ` + response.status);
logger_js.logger.log(`Response headers: ` + JSON.stringify(logFriendlyHeaders, null, 2));
logger_js.logger.groupEnd();
logger_js.logger.groupCollapsed(`View full response details here.`);
logger_js.logger.log(response.headers);
logger_js.logger.log(response);
logger_js.logger.groupEnd();
logger_js.logger.groupEnd();
}
}
return cacheable;
}
}
/*
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.
*/
/**
* A class implementing the `cacheWillUpdate` lifecycle callback. This makes it
* easier to add in cacheability checks to requests made via Workbox's built-in
* strategies.
*
* @memberof module:workbox-cacheable-response
*/
class CacheableResponsePlugin {
/**
* To construct a new CacheableResponsePlugin instance you must provide at
* least one of the `config` properties.
*
* If both `statuses` and `headers` are specified, then both conditions must
* be met for the `Response` to be considered cacheable.
*
* @param {Object} config
* @param {Array<number>} [config.statuses] One or more status codes that a
* `Response` can have and be considered cacheable.
* @param {Object<string,string>} [config.headers] A mapping of header names
* and expected values that a `Response` can have and be considered cacheable.
* If multiple headers are provided, only one needs to be present.
*/
constructor(config) {
/**
* @param {Object} options
* @param {Response} options.response
* @return {Response|null}
* @private
*/
this.cacheWillUpdate = async ({
response
}) => {
if (this._cacheableResponse.isResponseCacheable(response)) {
return response;
}
return null;
};
this._cacheableResponse = new CacheableResponse(config);
}
}
exports.CacheableResponse = CacheableResponse;
exports.CacheableResponsePlugin = CacheableResponsePlugin;
return exports;
}({}, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private));
//# sourceMappingURL=workbox-cacheable-response.dev.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-cacheable-response.dev.js","sources":["../_version.js","../CacheableResponse.js","../CacheableResponsePlugin.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:cacheable-response:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport { getFriendlyURL } from 'workbox-core/_private/getFriendlyURL.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport './_version.js';\n/**\n * This class allows you to set up rules determining what\n * status codes and/or headers need to be present in order for a\n * [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)\n * to be considered cacheable.\n *\n * @memberof module:workbox-cacheable-response\n */\nclass CacheableResponse {\n /**\n * To construct a new CacheableResponse instance you must provide at least\n * one of the `config` properties.\n *\n * If both `statuses` and `headers` are specified, then both conditions must\n * be met for the `Response` to be considered cacheable.\n *\n * @param {Object} config\n * @param {Array<number>} [config.statuses] One or more status codes that a\n * `Response` can have and be considered cacheable.\n * @param {Object<string,string>} [config.headers] A mapping of header names\n * and expected values that a `Response` can have and be considered cacheable.\n * If multiple headers are provided, only one needs to be present.\n */\n constructor(config = {}) {\n if (process.env.NODE_ENV !== 'production') {\n if (!(config.statuses || config.headers)) {\n throw new WorkboxError('statuses-or-headers-required', {\n moduleName: 'workbox-cacheable-response',\n className: 'CacheableResponse',\n funcName: 'constructor',\n });\n }\n if (config.statuses) {\n assert.isArray(config.statuses, {\n moduleName: 'workbox-cacheable-response',\n className: 'CacheableResponse',\n funcName: 'constructor',\n paramName: 'config.statuses',\n });\n }\n if (config.headers) {\n assert.isType(config.headers, 'object', {\n moduleName: 'workbox-cacheable-response',\n className: 'CacheableResponse',\n funcName: 'constructor',\n paramName: 'config.headers',\n });\n }\n }\n this._statuses = config.statuses;\n this._headers = config.headers;\n }\n /**\n * Checks a response to see whether it's cacheable or not, based on this\n * object's configuration.\n *\n * @param {Response} response The response whose cacheability is being\n * checked.\n * @return {boolean} `true` if the `Response` is cacheable, and `false`\n * otherwise.\n */\n isResponseCacheable(response) {\n if (process.env.NODE_ENV !== 'production') {\n assert.isInstance(response, Response, {\n moduleName: 'workbox-cacheable-response',\n className: 'CacheableResponse',\n funcName: 'isResponseCacheable',\n paramName: 'response',\n });\n }\n let cacheable = true;\n if (this._statuses) {\n cacheable = this._statuses.includes(response.status);\n }\n if (this._headers && cacheable) {\n cacheable = Object.keys(this._headers).some((headerName) => {\n return response.headers.get(headerName) === this._headers[headerName];\n });\n }\n if (process.env.NODE_ENV !== 'production') {\n if (!cacheable) {\n logger.groupCollapsed(`The request for ` +\n `'${getFriendlyURL(response.url)}' returned a response that does ` +\n `not meet the criteria for being cached.`);\n logger.groupCollapsed(`View cacheability criteria here.`);\n logger.log(`Cacheable statuses: ` +\n JSON.stringify(this._statuses));\n logger.log(`Cacheable headers: ` +\n JSON.stringify(this._headers, null, 2));\n logger.groupEnd();\n const logFriendlyHeaders = {};\n response.headers.forEach((value, key) => {\n logFriendlyHeaders[key] = value;\n });\n logger.groupCollapsed(`View response status and headers here.`);\n logger.log(`Response status: ` + responsLine truncated
@@ -0,0 +1,2 @@
this.workbox=this.workbox||{},this.workbox.cacheableResponse=function(s){"use strict";try{self["workbox:cacheable-response:5.1.4"]&&_()}catch(s){}class t{constructor(s={}){this.s=s.statuses,this.t=s.headers}isResponseCacheable(s){let t=!0;return this.s&&(t=this.s.includes(s.status)),this.t&&t&&(t=Object.keys(this.t).some(t=>s.headers.get(t)===this.t[t])),t}}return s.CacheableResponse=t,s.CacheableResponsePlugin=class{constructor(s){this.cacheWillUpdate=async({response:s})=>this.i.isResponseCacheable(s)?s:null,this.i=new t(s)}},s}({});
//# sourceMappingURL=workbox-cacheable-response.prod.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-cacheable-response.prod.js","sources":["../_version.js","../CacheableResponse.js","../CacheableResponsePlugin.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:cacheable-response:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport { getFriendlyURL } from 'workbox-core/_private/getFriendlyURL.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport './_version.js';\n/**\n * This class allows you to set up rules determining what\n * status codes and/or headers need to be present in order for a\n * [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)\n * to be considered cacheable.\n *\n * @memberof module:workbox-cacheable-response\n */\nclass CacheableResponse {\n /**\n * To construct a new CacheableResponse instance you must provide at least\n * one of the `config` properties.\n *\n * If both `statuses` and `headers` are specified, then both conditions must\n * be met for the `Response` to be considered cacheable.\n *\n * @param {Object} config\n * @param {Array<number>} [config.statuses] One or more status codes that a\n * `Response` can have and be considered cacheable.\n * @param {Object<string,string>} [config.headers] A mapping of header names\n * and expected values that a `Response` can have and be considered cacheable.\n * If multiple headers are provided, only one needs to be present.\n */\n constructor(config = {}) {\n if (process.env.NODE_ENV !== 'production') {\n if (!(config.statuses || config.headers)) {\n throw new WorkboxError('statuses-or-headers-required', {\n moduleName: 'workbox-cacheable-response',\n className: 'CacheableResponse',\n funcName: 'constructor',\n });\n }\n if (config.statuses) {\n assert.isArray(config.statuses, {\n moduleName: 'workbox-cacheable-response',\n className: 'CacheableResponse',\n funcName: 'constructor',\n paramName: 'config.statuses',\n });\n }\n if (config.headers) {\n assert.isType(config.headers, 'object', {\n moduleName: 'workbox-cacheable-response',\n className: 'CacheableResponse',\n funcName: 'constructor',\n paramName: 'config.headers',\n });\n }\n }\n this._statuses = config.statuses;\n this._headers = config.headers;\n }\n /**\n * Checks a response to see whether it's cacheable or not, based on this\n * object's configuration.\n *\n * @param {Response} response The response whose cacheability is being\n * checked.\n * @return {boolean} `true` if the `Response` is cacheable, and `false`\n * otherwise.\n */\n isResponseCacheable(response) {\n if (process.env.NODE_ENV !== 'production') {\n assert.isInstance(response, Response, {\n moduleName: 'workbox-cacheable-response',\n className: 'CacheableResponse',\n funcName: 'isResponseCacheable',\n paramName: 'response',\n });\n }\n let cacheable = true;\n if (this._statuses) {\n cacheable = this._statuses.includes(response.status);\n }\n if (this._headers && cacheable) {\n cacheable = Object.keys(this._headers).some((headerName) => {\n return response.headers.get(headerName) === this._headers[headerName];\n });\n }\n if (process.env.NODE_ENV !== 'production') {\n if (!cacheable) {\n logger.groupCollapsed(`The request for ` +\n `'${getFriendlyURL(response.url)}' returned a response that does ` +\n `not meet the criteria for being cached.`);\n logger.groupCollapsed(`View cacheability criteria here.`);\n logger.log(`Cacheable statuses: ` +\n JSON.stringify(this._statuses));\n logger.log(`Cacheable headers: ` +\n JSON.stringify(this._headers, null, 2));\n logger.groupEnd();\n const logFriendlyHeaders = {};\n response.headers.forEach((value, key) => {\n logFriendlyHeaders[key] = value;\n });\n logger.groupCollapsed(`View response status and headers here.`);\n logger.log(`Response status: ` + responLine truncated
File diff suppressed because it is too large. Load diff
@@ -0,0 +1 @@
{"version":3,"file":"workbox-core.dev.js","sources":["../_version.js","../_private/logger.js","../models/messages/messages.js","../models/messages/messageGenerator.js","../_private/WorkboxError.js","../_private/assert.js","../models/quotaErrorCallbacks.js","../registerQuotaErrorCallback.js","../_private/cacheNames.js","../_private/executeQuotaErrorCallbacks.js","../_private/getFriendlyURL.js","../utils/pluginUtils.js","../_private/cacheWrapper.js","../_private/canConstructReadableStream.js","../_private/canConstructResponseFromBodyStream.js","../_private/dontWaitFor.js","../_private/DBWrapper.js","../_private/Deferred.js","../_private/deleteDatabase.js","../_private/fetchWrapper.js","../_private/timeout.js","../_private/resultingClientExists.js","../_private.js","../cacheNames.js","../copyResponse.js","../clientsClaim.js","../setCacheNameDetails.js","../skipWaiting.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:core:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\n Copyright 2019 Google LLC\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\nconst logger = (process.env.NODE_ENV === 'production' ? null : (() => {\n // Don't overwrite this value if it's already set.\n // See https://github.com/GoogleChrome/workbox/pull/2284#issuecomment-560470923\n if (!('__WB_DISABLE_DEV_LOGS' in self)) {\n self.__WB_DISABLE_DEV_LOGS = false;\n }\n let inGroup = false;\n const methodToColorMap = {\n debug: `#7f8c8d`,\n log: `#2ecc71`,\n warn: `#f39c12`,\n error: `#c0392b`,\n groupCollapsed: `#3498db`,\n groupEnd: null,\n };\n const print = function (method, args) {\n if (self.__WB_DISABLE_DEV_LOGS) {\n return;\n }\n if (method === 'groupCollapsed') {\n // Safari doesn't print all console.groupCollapsed() arguments:\n // https://bugs.webkit.org/show_bug.cgi?id=182754\n if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {\n console[method](...args);\n return;\n }\n }\n const styles = [\n `background: ${methodToColorMap[method]}`,\n `border-radius: 0.5em`,\n `color: white`,\n `font-weight: bold`,\n `padding: 2px 0.5em`,\n ];\n // When in a group, the workbox prefix is not displayed.\n const logPrefix = inGroup ? [] : ['%cworkbox', styles.join(';')];\n console[method](...logPrefix, ...args);\n if (method === 'groupCollapsed') {\n inGroup = true;\n }\n if (method === 'groupEnd') {\n inGroup = false;\n }\n };\n const api = {};\n const loggerMethods = Object.keys(methodToColorMap);\n for (const key of loggerMethods) {\n const method = key;\n api[method] = (...args) => {\n print(method, args);\n };\n }\n return api;\n})());\nexport { logger };\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../../_version.js';\nexport const messages = {\n 'invalid-value': ({ paramName, validValueDescription, value }) => {\n if (!paramName || !validValueDescription) {\n throw new Error(`Unexpected input to 'invalid-value' error.`);\n }\n return `The '${paramName}' parameter was given a value with an ` +\n `unexpected value. ${validValueDescription} Received a value of ` +\n `${JSON.stringify(value)}.`;\n },\n 'not-an-array': ({ moduleName, className, funcName, paramName }) => {\n if (!moduleName || !className || !funcName || !paramName) {\n throw new Error(`Unexpected input to 'not-an-array' error.`);\n }\n return `The parameter '${paramName}' passed into ` +\n `'${moduleName}.${className}.${funcName}()' must be an array.`;\n },\n 'incorrect-type': ({ expectedType, paramName, moduleName, className, funcName }) => {\n if (!expectedType || !paramName || !moduleName || !funcName) {\n throw new Error(`Unexpected input to 'incorrect-type' error.`);\n }\n return `The parameter '${paramName}' passed into ` +\n `'${moduleName}.${className ? (className + '.') : ''}` +\n `${funcName}()' must be of type ${expectedType}.`;\n },\n 'incorrect-class': ({ expectedClass, paramName, moduleName, className, funcName, isReturnValueProblem }) => {\n if (!expectedClass || !moduleName || !funcName) {\n throw new Error(`Unexpected input to 'incorrect-class' error.`);\n }\n if (isReturnValueProblem) {\n return `The return value from ` +\n `'${moduleName}.${classNaLine truncated
@@ -0,0 +1,2 @@
this.workbox=this.workbox||{},this.workbox.core=function(e){"use strict";try{self["workbox:core:5.1.4"]&&_()}catch(e){}const t=(e,...t)=>{let n=e;return t.length>0&&(n+=" :: "+JSON.stringify(t)),n};class n extends Error{constructor(e,n){super(t(e,n)),this.name=e,this.details=n}}const s=new Set;const r={googleAnalytics:"googleAnalytics",precache:"precache-v2",prefix:"workbox",runtime:"runtime",suffix:"undefined"!=typeof registration?registration.scope:""},i=e=>[r.prefix,e,r.suffix].filter(e=>e&&e.length>0).join("-"),o={updateDetails:e=>{(e=>{for(const t of Object.keys(r))e(t)})(t=>{"string"==typeof e[t]&&(r[t]=e[t])})},getGoogleAnalyticsName:e=>e||i(r.googleAnalytics),getPrecacheName:e=>e||i(r.precache),getPrefix:()=>r.prefix,getRuntimeName:e=>e||i(r.runtime),getSuffix:()=>r.suffix};async function a(){for(const e of s)await e()}const c=e=>new URL(String(e),location.href).href.replace(new RegExp("^"+location.origin),""),u=(e,t)=>e.filter(e=>t in e),l=async({request:e,mode:t,plugins:n=[]})=>{const s=u(n,"cacheKeyWillBeUsed");let r=e;for(const e of s)r=await e.cacheKeyWillBeUsed.call(e,{mode:t,request:r}),"string"==typeof r&&(r=new Request(r));return r},f=async({cacheName:e,request:t,event:n,matchOptions:s,plugins:r=[]})=>{const i=await self.caches.open(e),o=await l({plugins:r,request:t,mode:"read"});let a=await i.match(o,s);for(const t of r)if("cachedResponseWillBeUsed"in t){const r=t.cachedResponseWillBeUsed;a=await r.call(t,{cacheName:e,event:n,matchOptions:s,cachedResponse:a,request:o})}return a},h={put:async({cacheName:e,request:t,response:s,event:r,plugins:i=[],matchOptions:o})=>{const h=await l({plugins:i,request:t,mode:"write"});if(!s)throw new n("cache-put-with-no-response",{url:c(h.url)});const w=await(async({request:e,response:t,event:n,plugins:s=[]})=>{let r=t,i=!1;for(const t of s)if("cacheWillUpdate"in t){i=!0;const s=t.cacheWillUpdate;if(r=await s.call(t,{request:e,response:r,event:n}),!r)break}return i||(r=r&&200===r.status?r:void 0),r||null})({event:r,plugins:i,response:s,request:h});if(!w)return;const p=await self.caches.open(e),d=u(i,"cacheDidUpdate"),g=d.length>0?await f({cacheName:e,matchOptions:o,request:h}):null;try{await p.put(h,w)}catch(e){throw"QuotaExceededError"===e.name&&await a(),e}for(const t of d)await t.cacheDidUpdate.call(t,{cacheName:e,event:r,oldResponse:g,newResponse:w,request:h})},match:f};let w,p;function d(){if(void 0===p){const e=new Response("");if("body"in e)try{new Response(e.body),p=!0}catch(e){p=!1}p=!1}return p}class g{constructor(e,t,{onupgradeneeded:n,onversionchange:s}={}){this.t=null,this.s=e,this.i=t,this.o=n,this.u=s||(()=>this.close())}get db(){return this.t}async open(){if(!this.t)return this.t=await new Promise((e,t)=>{let n=!1;setTimeout(()=>{n=!0,t(new Error("The open request was blocked and timed out"))},this.OPEN_TIMEOUT);const s=indexedDB.open(this.s,this.i);s.onerror=()=>t(s.error),s.onupgradeneeded=e=>{n?(s.transaction.abort(),s.result.close()):"function"==typeof this.o&&this.o(e)},s.onsuccess=()=>{const t=s.result;n?t.close():(t.onversionchange=this.u.bind(this),e(t))}}),this}async getKey(e,t){return(await this.getAllKeys(e,t,1))[0]}async getAll(e,t,n){return await this.getAllMatching(e,{query:t,count:n})}async getAllKeys(e,t,n){return(await this.getAllMatching(e,{query:t,count:n,includeKeys:!0})).map(e=>e.key)}async getAllMatching(e,{index:t,query:n=null,direction:s="next",count:r,includeKeys:i=!1}={}){return await this.transaction([e],"readonly",(o,a)=>{const c=o.objectStore(e),u=t?c.index(t):c,l=[],f=u.openCursor(n,s);f.onsuccess=()=>{const e=f.result;e?(l.push(i?e:e.value),r&&l.length>=r?a(l):e.continue()):a(l)}})}async transaction(e,t,n){return await this.open(),await new Promise((s,r)=>{const i=this.t.transaction(e,t);i.onabort=()=>r(i.error),i.oncomplete=()=>s(),n(i,e=>s(e))})}async l(e,t,n,...s){return await this.transaction([t],n,(n,r)=>{const i=n.objectStore(t),o=i[e].apply(i,s);o.onsuccess=()=>r(o.result)})}close(){this.t&&(this.t.close(),this.t=null)}}g.prototype.OPEN_TIMEOUT=2e3;const y={readonly:["get","count","getKey","getAll","getAllKeys"],readwrite:["add","put","clear","delete"]};for(const[e,t]of Object.entries(y))for(const n of t)n in IDBObjectStore.prototype&&(g.prototype[n]=async function(t,...s){return await this.l(n,t,e,...s)});const m={fetch:async({request:e,fetchOptions:t,event:s,plugins:r=[]})=>{if("string"==typeof e&&(e=new Request(e)),s instanceof FetchEvent&&s.preloadResponse){const e=await s.preloadResponse;if(e)return e}const i=u(r,"fetchDidFail"),o=i.length>0?e.clone():null;try{for(const t of r)if("requestWillFetch"in t){const n=t.requestWillFetch,r=e.clone();e=await n.call(t,{request:r,event:s})}}catch(e){throw new n("plugin-error-request-will-fetch",{thrownError:e})}const a=e.clone();try{let n;n="navigate"===e.mode?await fetch(e):await fetch(e,t);for(const e of r)"fetchDidSucceed"in e&&(n=await e.fetchDidSucceed.call(e,{event:s,request:a,response:n}));return n}catch(e){for(const t of i)await t.fetchDidFail.call(t,{Line truncated
//# sourceMappingURL=workbox-core.prod.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-core.prod.js","sources":["../_version.js","../_private/logger.js","../models/messages/messageGenerator.js","../_private/WorkboxError.js","../_private/assert.js","../models/quotaErrorCallbacks.js","../_private/cacheNames.js","../_private/executeQuotaErrorCallbacks.js","../_private/getFriendlyURL.js","../utils/pluginUtils.js","../_private/cacheWrapper.js","../_private/canConstructReadableStream.js","../_private/canConstructResponseFromBodyStream.js","../_private/DBWrapper.js","../_private/deleteDatabase.js","../_private/fetchWrapper.js","../_private/timeout.js","../_private/dontWaitFor.js","../_private/Deferred.js","../_private/resultingClientExists.js","../cacheNames.js","../clientsClaim.js","../copyResponse.js","../registerQuotaErrorCallback.js","../setCacheNameDetails.js","../skipWaiting.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:core:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\n Copyright 2019 Google LLC\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\nconst logger = (process.env.NODE_ENV === 'production' ? null : (() => {\n // Don't overwrite this value if it's already set.\n // See https://github.com/GoogleChrome/workbox/pull/2284#issuecomment-560470923\n if (!('__WB_DISABLE_DEV_LOGS' in self)) {\n self.__WB_DISABLE_DEV_LOGS = false;\n }\n let inGroup = false;\n const methodToColorMap = {\n debug: `#7f8c8d`,\n log: `#2ecc71`,\n warn: `#f39c12`,\n error: `#c0392b`,\n groupCollapsed: `#3498db`,\n groupEnd: null,\n };\n const print = function (method, args) {\n if (self.__WB_DISABLE_DEV_LOGS) {\n return;\n }\n if (method === 'groupCollapsed') {\n // Safari doesn't print all console.groupCollapsed() arguments:\n // https://bugs.webkit.org/show_bug.cgi?id=182754\n if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {\n console[method](...args);\n return;\n }\n }\n const styles = [\n `background: ${methodToColorMap[method]}`,\n `border-radius: 0.5em`,\n `color: white`,\n `font-weight: bold`,\n `padding: 2px 0.5em`,\n ];\n // When in a group, the workbox prefix is not displayed.\n const logPrefix = inGroup ? [] : ['%cworkbox', styles.join(';')];\n console[method](...logPrefix, ...args);\n if (method === 'groupCollapsed') {\n inGroup = true;\n }\n if (method === 'groupEnd') {\n inGroup = false;\n }\n };\n const api = {};\n const loggerMethods = Object.keys(methodToColorMap);\n for (const key of loggerMethods) {\n const method = key;\n api[method] = (...args) => {\n print(method, args);\n };\n }\n return api;\n})());\nexport { logger };\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { messages } from './messages.js';\nimport '../../_version.js';\nconst fallback = (code, ...args) => {\n let msg = code;\n if (args.length > 0) {\n msg += ` :: ${JSON.stringify(args)}`;\n }\n return msg;\n};\nconst generatorFunction = (code, details = {}) => {\n const message = messages[code];\n if (!message) {\n throw new Error(`Unable to find message for code '${code}'.`);\n }\n return message(details);\n};\nexport const messageGenerator = (process.env.NODE_ENV === 'production') ?\n fallback : generatorFunction;\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { messageGenerator } from '../models/messages/messageGenerator.js';\nimport '../_version.js';\n/**\n * Workbox errors should be thrown with this class.\n * This allows use to ensure the type easily in tests,\n * helps developers identify errors from workbox\n * easily and allows use to optimise error\n * messages correctly.\n *\n * @private\n */\nclass WorkboxError extends Error {\n /**\n *\n * @param {string} errorCode The error code that\n * identifies this particular error.\n * @param {Object=} details Any relevant arguments\n * that will help developers identify issues should\n * be added as a key on the context object.\n */\n constructor(errorCode, details) {\n const message = messageGenerator(errorCode, details);\n super(message);\n this.name = errorCode;\n this.details = details;\n }\n}\nexport { WorkboxError };\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by aLine truncated
@@ -0,0 +1,649 @@
this.workbox = this.workbox || {};
this.workbox.expiration = (function (exports, assert_js, dontWaitFor_js, logger_js, WorkboxError_js, DBWrapper_js, deleteDatabase_js, cacheNames_js, getFriendlyURL_js, registerQuotaErrorCallback_js) {
'use strict';
try {
self['workbox:expiration:5.1.4'] && _();
} catch (e) {}
/*
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 DB_NAME = 'workbox-expiration';
const OBJECT_STORE_NAME = 'cache-entries';
const normalizeURL = unNormalizedUrl => {
const url = new URL(unNormalizedUrl, location.href);
url.hash = '';
return url.href;
};
/**
* Returns the timestamp model.
*
* @private
*/
class CacheTimestampsModel {
/**
*
* @param {string} cacheName
*
* @private
*/
constructor(cacheName) {
this._cacheName = cacheName;
this._db = new DBWrapper_js.DBWrapper(DB_NAME, 1, {
onupgradeneeded: event => this._handleUpgrade(event)
});
}
/**
* Should perform an upgrade of indexedDB.
*
* @param {Event} event
*
* @private
*/
_handleUpgrade(event) {
const db = event.target.result; // TODO(philipwalton): EdgeHTML doesn't support arrays as a keyPath, so we
// have to use the `id` keyPath here and create our own values (a
// concatenation of `url + cacheName`) instead of simply using
// `keyPath: ['url', 'cacheName']`, which is supported in other browsers.
const objStore = db.createObjectStore(OBJECT_STORE_NAME, {
keyPath: 'id'
}); // TODO(philipwalton): once we don't have to support EdgeHTML, we can
// create a single index with the keyPath `['cacheName', 'timestamp']`
// instead of doing both these indexes.
objStore.createIndex('cacheName', 'cacheName', {
unique: false
});
objStore.createIndex('timestamp', 'timestamp', {
unique: false
}); // Previous versions of `workbox-expiration` used `this._cacheName`
// as the IDBDatabase name.
deleteDatabase_js.deleteDatabase(this._cacheName);
}
/**
* @param {string} url
* @param {number} timestamp
*
* @private
*/
async setTimestamp(url, timestamp) {
url = normalizeURL(url);
const entry = {
url,
timestamp,
cacheName: this._cacheName,
// Creating an ID from the URL and cache name won't be necessary once
// Edge switches to Chromium and all browsers we support work with
// array keyPaths.
id: this._getId(url)
};
await this._db.put(OBJECT_STORE_NAME, entry);
}
/**
* Returns the timestamp stored for a given URL.
*
* @param {string} url
* @return {number}
*
* @private
*/
async getTimestamp(url) {
const entry = await this._db.get(OBJECT_STORE_NAME, this._getId(url));
return entry.timestamp;
}
/**
* Iterates through all the entries in the object store (from newest to
* oldest) and removes entries once either `maxCount` is reached or the
* entry's timestamp is less than `minTimestamp`.
*
* @param {number} minTimestamp
* @param {number} maxCount
* @return {Array<string>}
*
* @private
*/
async expireEntries(minTimestamp, maxCount) {
const entriesToDelete = await this._db.transaction(OBJECT_STORE_NAME, 'readwrite', (txn, done) => {
const store = txn.objectStore(OBJECT_STORE_NAME);
const request = store.index('timestamp').openCursor(null, 'prev');
const entriesToDelete = [];
let entriesNotDeletedCount = 0;
request.onsuccess = () => {
const cursor = request.result;
if (cursor) {
const result = cursor.value; // TODO(philipwalton): once we can use a multi-key index, we
// won't have to check `cacheName` here.
if (result.cacheName === this._cacheName) {
// Delete an entry if it's older than the max age or
// if we already have the max number allowed.
if (minTimestamp && result.timestamp < minTimestamp || maxCount && entriesNotDeletedCount >= maxCount) {
// TODO(philipwalton): we should be able to delete the
// entry right here, but doing so causes an iteration
// bug in Safari stable (fixed in TP). Instead we can
// store the keys of the entries to delete, and then
// delete the separate transactions.
// https://github.com/GoogleChrome/workbox/issues/1978
// cursor.delete();
// We only need to return the URL, not the whole entry.
entriesToDelete.push(cursor.value);
} else {
entriesNotDeletedCount++;
}
}
cursor.continue();
} else {
done(entriesToDelete);
}
};
}); // TODO(philipwalton): once the Safari bug in the following issue is fixed,
// we should be able to remove this loop and do the entry deletion in the
// cursor loop above:
// https://github.com/GoogleChrome/workbox/issues/1978
const urlsDeleted = [];
for (const entry of entriesToDelete) {
await this._db.delete(OBJECT_STORE_NAME, entry.id);
urlsDeleted.push(entry.url);
}
return urlsDeleted;
}
/**
* Takes a URL and returns an ID that will be unique in the object store.
*
* @param {string} url
* @return {string}
*
* @private
*/
_getId(url) {
// Creating an ID from the URL and cache name won't be necessary once
// Edge switches to Chromium and all browsers we support work with
// array keyPaths.
return this._cacheName + '|' + normalizeURL(url);
}
}
/*
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.
*/
/**
* The `CacheExpiration` class allows you define an expiration and / or
* limit on the number of responses stored in a
* [`Cache`](https://developer.mozilla.org/en-US/docs/Web/API/Cache).
*
* @memberof module:workbox-expiration
*/
class CacheExpiration {
/**
* To construct a new CacheExpiration instance you must provide at least
* one of the `config` properties.
*
* @param {string} cacheName Name of the cache to apply restrictions to.
* @param {Object} config
* @param {number} [config.maxEntries] The maximum number of entries to cache.
* Entries used the least will be removed as the maximum is reached.
* @param {number} [config.maxAgeSeconds] The maximum age of an entry before
* it's treated as stale and removed.
*/
constructor(cacheName, config = {}) {
this._isRunning = false;
this._rerunRequested = false;
{
assert_js.assert.isType(cacheName, 'string', {
moduleName: 'workbox-expiration',
className: 'CacheExpiration',
funcName: 'constructor',
paramName: 'cacheName'
});
if (!(config.maxEntries || config.maxAgeSeconds)) {
throw new WorkboxError_js.WorkboxError('max-entries-or-age-required', {
moduleName: 'workbox-expiration',
className: 'CacheExpiration',
funcName: 'constructor'
});
}
if (config.maxEntries) {
assert_js.assert.isType(config.maxEntries, 'number', {
moduleName: 'workbox-expiration',
className: 'CacheExpiration',
funcName: 'constructor',
paramName: 'config.maxEntries'
}); // TODO: Assert is positive
}
if (config.maxAgeSeconds) {
assert_js.assert.isType(config.maxAgeSeconds, 'number', {
moduleName: 'workbox-expiration',
className: 'CacheExpiration',
funcName: 'constructor',
paramName: 'config.maxAgeSeconds'
}); // TODO: Assert is positive
}
}
this._maxEntries = config.maxEntries;
this._maxAgeSeconds = config.maxAgeSeconds;
this._cacheName = cacheName;
this._timestampModel = new CacheTimestampsModel(cacheName);
}
/**
* Expires entries for the given cache and given criteria.
*/
async expireEntries() {
if (this._isRunning) {
this._rerunRequested = true;
return;
}
this._isRunning = true;
const minTimestamp = this._maxAgeSeconds ? Date.now() - this._maxAgeSeconds * 1000 : 0;
const urlsExpired = await this._timestampModel.expireEntries(minTimestamp, this._maxEntries); // Delete URLs from the cache
const cache = await self.caches.open(this._cacheName);
for (const url of urlsExpired) {
await cache.delete(url);
}
{
if (urlsExpired.length > 0) {
logger_js.logger.groupCollapsed(`Expired ${urlsExpired.length} ` + `${urlsExpired.length === 1 ? 'entry' : 'entries'} and removed ` + `${urlsExpired.length === 1 ? 'it' : 'them'} from the ` + `'${this._cacheName}' cache.`);
logger_js.logger.log(`Expired the following ${urlsExpired.length === 1 ? 'URL' : 'URLs'}:`);
urlsExpired.forEach(url => logger_js.logger.log(` ${url}`));
logger_js.logger.groupEnd();
} else {
logger_js.logger.debug(`Cache expiration ran and found no entries to remove.`);
}
}
this._isRunning = false;
if (this._rerunRequested) {
this._rerunRequested = false;
dontWaitFor_js.dontWaitFor(this.expireEntries());
}
}
/**
* Update the timestamp for the given URL. This ensures the when
* removing entries based on maximum entries, most recently used
* is accurate or when expiring, the timestamp is up-to-date.
*
* @param {string} url
*/
async updateTimestamp(url) {
{
assert_js.assert.isType(url, 'string', {
moduleName: 'workbox-expiration',
className: 'CacheExpiration',
funcName: 'updateTimestamp',
paramName: 'url'
});
}
await this._timestampModel.setTimestamp(url, Date.now());
}
/**
* Can be used to check if a URL has expired or not before it's used.
*
* This requires a look up from IndexedDB, so can be slow.
*
* Note: This method will not remove the cached entry, call
* `expireEntries()` to remove indexedDB and Cache entries.
*
* @param {string} url
* @return {boolean}
*/
async isURLExpired(url) {
if (!this._maxAgeSeconds) {
{
throw new WorkboxError_js.WorkboxError(`expired-test-without-max-age`, {
methodName: 'isURLExpired',
paramName: 'maxAgeSeconds'
});
}
} else {
const timestamp = await this._timestampModel.getTimestamp(url);
const expireOlderThan = Date.now() - this._maxAgeSeconds * 1000;
return timestamp < expireOlderThan;
}
}
/**
* Removes the IndexedDB object store used to keep track of cache expiration
* metadata.
*/
async delete() {
// Make sure we don't attempt another rerun if we're called in the middle of
// a cache expiration.
this._rerunRequested = false;
await this._timestampModel.expireEntries(Infinity); // Expires all.
}
}
/*
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 plugin can be used in the Workbox APIs to regularly enforce a
* limit on the age and / or the number of cached requests.
*
* Whenever a cached request is used or updated, this plugin will look
* at the used Cache and remove any old or extra requests.
*
* When using `maxAgeSeconds`, requests may be used *once* after expiring
* because the expiration clean up will not have occurred until *after* the
* cached request has been used. If the request has a "Date" header, then
* a light weight expiration check is performed and the request will not be
* used immediately.
*
* When using `maxEntries`, the entry least-recently requested will be removed
* from the cache first.
*
* @memberof module:workbox-expiration
*/
class ExpirationPlugin {
/**
* @param {Object} config
* @param {number} [config.maxEntries] The maximum number of entries to cache.
* Entries used the least will be removed as the maximum is reached.
* @param {number} [config.maxAgeSeconds] The maximum age of an entry before
* it's treated as stale and removed.
* @param {boolean} [config.purgeOnQuotaError] Whether to opt this cache in to
* automatic deletion if the available storage quota has been exceeded.
*/
constructor(config = {}) {
/**
* A "lifecycle" callback that will be triggered automatically by the
* `workbox-strategies` handlers when a `Response` is about to be returned
* from a [Cache](https://developer.mozilla.org/en-US/docs/Web/API/Cache) to
* the handler. It allows the `Response` to be inspected for freshness and
* prevents it from being used if the `Response`'s `Date` header value is
* older than the configured `maxAgeSeconds`.
*
* @param {Object} options
* @param {string} options.cacheName Name of the cache the response is in.
* @param {Response} options.cachedResponse The `Response` object that's been
* read from a cache and whose freshness should be checked.
* @return {Response} Either the `cachedResponse`, if it's
* fresh, or `null` if the `Response` is older than `maxAgeSeconds`.
*
* @private
*/
this.cachedResponseWillBeUsed = async ({
event,
request,
cacheName,
cachedResponse
}) => {
if (!cachedResponse) {
return null;
}
const isFresh = this._isResponseDateFresh(cachedResponse); // Expire entries to ensure that even if the expiration date has
// expired, it'll only be used once.
const cacheExpiration = this._getCacheExpiration(cacheName);
dontWaitFor_js.dontWaitFor(cacheExpiration.expireEntries()); // Update the metadata for the request URL to the current timestamp,
// but don't `await` it as we don't want to block the response.
const updateTimestampDone = cacheExpiration.updateTimestamp(request.url);
if (event) {
try {
event.waitUntil(updateTimestampDone);
} catch (error) {
{
// The event may not be a fetch event; only log the URL if it is.
if ('request' in event) {
logger_js.logger.warn(`Unable to ensure service worker stays alive when ` + `updating cache entry for ` + `'${getFriendlyURL_js.getFriendlyURL(event.request.url)}'.`);
}
}
}
}
return isFresh ? cachedResponse : null;
};
/**
* A "lifecycle" callback that will be triggered automatically by the
* `workbox-strategies` handlers when an entry is added to a cache.
*
* @param {Object} options
* @param {string} options.cacheName Name of the cache that was updated.
* @param {string} options.request The Request for the cached entry.
*
* @private
*/
this.cacheDidUpdate = async ({
cacheName,
request
}) => {
{
assert_js.assert.isType(cacheName, 'string', {
moduleName: 'workbox-expiration',
className: 'Plugin',
funcName: 'cacheDidUpdate',
paramName: 'cacheName'
});
assert_js.assert.isInstance(request, Request, {
moduleName: 'workbox-expiration',
className: 'Plugin',
funcName: 'cacheDidUpdate',
paramName: 'request'
});
}
const cacheExpiration = this._getCacheExpiration(cacheName);
await cacheExpiration.updateTimestamp(request.url);
await cacheExpiration.expireEntries();
};
{
if (!(config.maxEntries || config.maxAgeSeconds)) {
throw new WorkboxError_js.WorkboxError('max-entries-or-age-required', {
moduleName: 'workbox-expiration',
className: 'Plugin',
funcName: 'constructor'
});
}
if (config.maxEntries) {
assert_js.assert.isType(config.maxEntries, 'number', {
moduleName: 'workbox-expiration',
className: 'Plugin',
funcName: 'constructor',
paramName: 'config.maxEntries'
});
}
if (config.maxAgeSeconds) {
assert_js.assert.isType(config.maxAgeSeconds, 'number', {
moduleName: 'workbox-expiration',
className: 'Plugin',
funcName: 'constructor',
paramName: 'config.maxAgeSeconds'
});
}
}
this._config = config;
this._maxAgeSeconds = config.maxAgeSeconds;
this._cacheExpirations = new Map();
if (config.purgeOnQuotaError) {
registerQuotaErrorCallback_js.registerQuotaErrorCallback(() => this.deleteCacheAndMetadata());
}
}
/**
* A simple helper method to return a CacheExpiration instance for a given
* cache name.
*
* @param {string} cacheName
* @return {CacheExpiration}
*
* @private
*/
_getCacheExpiration(cacheName) {
if (cacheName === cacheNames_js.cacheNames.getRuntimeName()) {
throw new WorkboxError_js.WorkboxError('expire-custom-caches-only');
}
let cacheExpiration = this._cacheExpirations.get(cacheName);
if (!cacheExpiration) {
cacheExpiration = new CacheExpiration(cacheName, this._config);
this._cacheExpirations.set(cacheName, cacheExpiration);
}
return cacheExpiration;
}
/**
* @param {Response} cachedResponse
* @return {boolean}
*
* @private
*/
_isResponseDateFresh(cachedResponse) {
if (!this._maxAgeSeconds) {
// We aren't expiring by age, so return true, it's fresh
return true;
} // Check if the 'date' header will suffice a quick expiration check.
// See https://github.com/GoogleChromeLabs/sw-toolbox/issues/164 for
// discussion.
const dateHeaderTimestamp = this._getDateHeaderTimestamp(cachedResponse);
if (dateHeaderTimestamp === null) {
// Unable to parse date, so assume it's fresh.
return true;
} // If we have a valid headerTime, then our response is fresh iff the
// headerTime plus maxAgeSeconds is greater than the current time.
const now = Date.now();
return dateHeaderTimestamp >= now - this._maxAgeSeconds * 1000;
}
/**
* This method will extract the data header and parse it into a useful
* value.
*
* @param {Response} cachedResponse
* @return {number|null}
*
* @private
*/
_getDateHeaderTimestamp(cachedResponse) {
if (!cachedResponse.headers.has('date')) {
return null;
}
const dateHeader = cachedResponse.headers.get('date');
const parsedDate = new Date(dateHeader);
const headerTime = parsedDate.getTime(); // If the Date header was invalid for some reason, parsedDate.getTime()
// will return NaN.
if (isNaN(headerTime)) {
return null;
}
return headerTime;
}
/**
* This is a helper method that performs two operations:
*
* - Deletes *all* the underlying Cache instances associated with this plugin
* instance, by calling caches.delete() on your behalf.
* - Deletes the metadata from IndexedDB used to keep track of expiration
* details for each Cache instance.
*
* When using cache expiration, calling this method is preferable to calling
* `caches.delete()` directly, since this will ensure that the IndexedDB
* metadata is also cleanly removed and open IndexedDB instances are deleted.
*
* Note that if you're *not* using cache expiration for a given cache, calling
* `caches.delete()` and passing in the cache's name should be sufficient.
* There is no Workbox-specific method needed for cleanup in that case.
*/
async deleteCacheAndMetadata() {
// Do this one at a time instead of all at once via `Promise.all()` to
// reduce the chance of inconsistency if a promise rejects.
for (const [cacheName, cacheExpiration] of this._cacheExpirations) {
await self.caches.delete(cacheName);
await cacheExpiration.delete();
} // Reset this._cacheExpirations to its initial state.
this._cacheExpirations = new Map();
}
}
exports.CacheExpiration = CacheExpiration;
exports.ExpirationPlugin = ExpirationPlugin;
return exports;
}({}, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core));
//# sourceMappingURL=workbox-expiration.dev.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-expiration.dev.js","sources":["../_version.js","../models/CacheTimestampsModel.js","../CacheExpiration.js","../ExpirationPlugin.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:expiration:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { DBWrapper } from 'workbox-core/_private/DBWrapper.js';\nimport { deleteDatabase } from 'workbox-core/_private/deleteDatabase.js';\nimport '../_version.js';\nconst DB_NAME = 'workbox-expiration';\nconst OBJECT_STORE_NAME = 'cache-entries';\nconst normalizeURL = (unNormalizedUrl) => {\n const url = new URL(unNormalizedUrl, location.href);\n url.hash = '';\n return url.href;\n};\n/**\n * Returns the timestamp model.\n *\n * @private\n */\nclass CacheTimestampsModel {\n /**\n *\n * @param {string} cacheName\n *\n * @private\n */\n constructor(cacheName) {\n this._cacheName = cacheName;\n this._db = new DBWrapper(DB_NAME, 1, {\n onupgradeneeded: (event) => this._handleUpgrade(event),\n });\n }\n /**\n * Should perform an upgrade of indexedDB.\n *\n * @param {Event} event\n *\n * @private\n */\n _handleUpgrade(event) {\n const db = event.target.result;\n // TODO(philipwalton): EdgeHTML doesn't support arrays as a keyPath, so we\n // have to use the `id` keyPath here and create our own values (a\n // concatenation of `url + cacheName`) instead of simply using\n // `keyPath: ['url', 'cacheName']`, which is supported in other browsers.\n const objStore = db.createObjectStore(OBJECT_STORE_NAME, { keyPath: 'id' });\n // TODO(philipwalton): once we don't have to support EdgeHTML, we can\n // create a single index with the keyPath `['cacheName', 'timestamp']`\n // instead of doing both these indexes.\n objStore.createIndex('cacheName', 'cacheName', { unique: false });\n objStore.createIndex('timestamp', 'timestamp', { unique: false });\n // Previous versions of `workbox-expiration` used `this._cacheName`\n // as the IDBDatabase name.\n deleteDatabase(this._cacheName);\n }\n /**\n * @param {string} url\n * @param {number} timestamp\n *\n * @private\n */\n async setTimestamp(url, timestamp) {\n url = normalizeURL(url);\n const entry = {\n url,\n timestamp,\n cacheName: this._cacheName,\n // Creating an ID from the URL and cache name won't be necessary once\n // Edge switches to Chromium and all browsers we support work with\n // array keyPaths.\n id: this._getId(url),\n };\n await this._db.put(OBJECT_STORE_NAME, entry);\n }\n /**\n * Returns the timestamp stored for a given URL.\n *\n * @param {string} url\n * @return {number}\n *\n * @private\n */\n async getTimestamp(url) {\n const entry = await this._db.get(OBJECT_STORE_NAME, this._getId(url));\n return entry.timestamp;\n }\n /**\n * Iterates through all the entries in the object store (from newest to\n * oldest) and removes entries once either `maxCount` is reached or the\n * entry's timestamp is less than `minTimestamp`.\n *\n * @param {number} minTimestamp\n * @param {number} maxCount\n * @return {Array<string>}\n *\n * @private\n */\n async expireEntries(minTimestamp, maxCount) {\n const entriesToDelete = await this._db.transaction(OBJECT_STORE_NAME, 'readwrite', (txn, done) => {\n const store = txn.objectStore(OBJECT_STORE_NAME);\n const request = store.index('timestamp').openCursor(null, 'prev');\n const entriesToDelete = [];\n let entriesNotDeletedCount = 0;\n request.onsuccess = () => {\n const cursor = request.result;\n if (cursor) {\n const result = cursor.value;\n // TODO(philipwalton): once we can use a multi-key index, we\n // won't have to check `cacheName` here.\n if (result.cacheName === this._cacheName) {\n // Delete an entry if it's older than the max age or\n // if we already have the max number allowed.\n if ((minTimestamp && result.timestamp < minTimestamp) ||\n (maxCount && entriesNotDeletedCount >= maxCount)) {\n // TODO(philipwalton): we should be able to delete the\n // entry right here, but doing so causes an iteration\n // bug in Safari stable (fixed in TP). Instead we can\n //Line truncated
@@ -0,0 +1,2 @@
this.workbox=this.workbox||{},this.workbox.expiration=function(t,e,s,i,a,n,h){"use strict";try{self["workbox:expiration:5.1.4"]&&_()}catch(t){}const r=t=>{const e=new URL(t,location.href);return e.hash="",e.href};class c{constructor(t){this.t=t,this.s=new i.DBWrapper("workbox-expiration",1,{onupgradeneeded:t=>this.i(t)})}i(t){const e=t.target.result.createObjectStore("cache-entries",{keyPath:"id"});e.createIndex("cacheName","cacheName",{unique:!1}),e.createIndex("timestamp","timestamp",{unique:!1}),a.deleteDatabase(this.t)}async setTimestamp(t,e){const s={url:t=r(t),timestamp:e,cacheName:this.t,id:this.h(t)};await this.s.put("cache-entries",s)}async getTimestamp(t){return(await this.s.get("cache-entries",this.h(t))).timestamp}async expireEntries(t,e){const s=await this.s.transaction("cache-entries","readwrite",(s,i)=>{const a=s.objectStore("cache-entries").index("timestamp").openCursor(null,"prev"),n=[];let h=0;a.onsuccess=()=>{const s=a.result;if(s){const i=s.value;i.cacheName===this.t&&(t&&i.timestamp<t||e&&h>=e?n.push(s.value):h++),s.continue()}else i(n)}}),i=[];for(const t of s)await this.s.delete("cache-entries",t.id),i.push(t.url);return i}h(t){return this.t+"|"+r(t)}}class o{constructor(t,e={}){this.o=!1,this.u=!1,this.l=e.maxEntries,this.m=e.maxAgeSeconds,this.t=t,this.p=new c(t)}async expireEntries(){if(this.o)return void(this.u=!0);this.o=!0;const t=this.m?Date.now()-1e3*this.m:0,s=await this.p.expireEntries(t,this.l),i=await self.caches.open(this.t);for(const t of s)await i.delete(t);this.o=!1,this.u&&(this.u=!1,e.dontWaitFor(this.expireEntries()))}async updateTimestamp(t){await this.p.setTimestamp(t,Date.now())}async isURLExpired(t){if(this.m){return await this.p.getTimestamp(t)<Date.now()-1e3*this.m}return!1}async delete(){this.u=!1,await this.p.expireEntries(1/0)}}return t.CacheExpiration=o,t.ExpirationPlugin=class{constructor(t={}){this.cachedResponseWillBeUsed=async({event:t,request:s,cacheName:i,cachedResponse:a})=>{if(!a)return null;const n=this.k(a),h=this.D(i);e.dontWaitFor(h.expireEntries());const r=h.updateTimestamp(s.url);if(t)try{t.waitUntil(r)}catch(t){}return n?a:null},this.cacheDidUpdate=async({cacheName:t,request:e})=>{const s=this.D(t);await s.updateTimestamp(e.url),await s.expireEntries()},this.N=t,this.m=t.maxAgeSeconds,this.g=new Map,t.purgeOnQuotaError&&h.registerQuotaErrorCallback(()=>this.deleteCacheAndMetadata())}D(t){if(t===n.cacheNames.getRuntimeName())throw new s.WorkboxError("expire-custom-caches-only");let e=this.g.get(t);return e||(e=new o(t,this.N),this.g.set(t,e)),e}k(t){if(!this.m)return!0;const e=this._(t);if(null===e)return!0;return e>=Date.now()-1e3*this.m}_(t){if(!t.headers.has("date"))return null;const e=t.headers.get("date"),s=new Date(e).getTime();return isNaN(s)?null:s}async deleteCacheAndMetadata(){for(const[t,e]of this.g)await self.caches.delete(t),await e.delete();this.g=new Map}},t}({},workbox.core._private,workbox.core._private,workbox.core._private,workbox.core._private,workbox.core._private,workbox.core);
//# sourceMappingURL=workbox-expiration.prod.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-expiration.prod.js","sources":["../_version.js","../models/CacheTimestampsModel.js","../CacheExpiration.js","../ExpirationPlugin.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:expiration:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { DBWrapper } from 'workbox-core/_private/DBWrapper.js';\nimport { deleteDatabase } from 'workbox-core/_private/deleteDatabase.js';\nimport '../_version.js';\nconst DB_NAME = 'workbox-expiration';\nconst OBJECT_STORE_NAME = 'cache-entries';\nconst normalizeURL = (unNormalizedUrl) => {\n const url = new URL(unNormalizedUrl, location.href);\n url.hash = '';\n return url.href;\n};\n/**\n * Returns the timestamp model.\n *\n * @private\n */\nclass CacheTimestampsModel {\n /**\n *\n * @param {string} cacheName\n *\n * @private\n */\n constructor(cacheName) {\n this._cacheName = cacheName;\n this._db = new DBWrapper(DB_NAME, 1, {\n onupgradeneeded: (event) => this._handleUpgrade(event),\n });\n }\n /**\n * Should perform an upgrade of indexedDB.\n *\n * @param {Event} event\n *\n * @private\n */\n _handleUpgrade(event) {\n const db = event.target.result;\n // TODO(philipwalton): EdgeHTML doesn't support arrays as a keyPath, so we\n // have to use the `id` keyPath here and create our own values (a\n // concatenation of `url + cacheName`) instead of simply using\n // `keyPath: ['url', 'cacheName']`, which is supported in other browsers.\n const objStore = db.createObjectStore(OBJECT_STORE_NAME, { keyPath: 'id' });\n // TODO(philipwalton): once we don't have to support EdgeHTML, we can\n // create a single index with the keyPath `['cacheName', 'timestamp']`\n // instead of doing both these indexes.\n objStore.createIndex('cacheName', 'cacheName', { unique: false });\n objStore.createIndex('timestamp', 'timestamp', { unique: false });\n // Previous versions of `workbox-expiration` used `this._cacheName`\n // as the IDBDatabase name.\n deleteDatabase(this._cacheName);\n }\n /**\n * @param {string} url\n * @param {number} timestamp\n *\n * @private\n */\n async setTimestamp(url, timestamp) {\n url = normalizeURL(url);\n const entry = {\n url,\n timestamp,\n cacheName: this._cacheName,\n // Creating an ID from the URL and cache name won't be necessary once\n // Edge switches to Chromium and all browsers we support work with\n // array keyPaths.\n id: this._getId(url),\n };\n await this._db.put(OBJECT_STORE_NAME, entry);\n }\n /**\n * Returns the timestamp stored for a given URL.\n *\n * @param {string} url\n * @return {number}\n *\n * @private\n */\n async getTimestamp(url) {\n const entry = await this._db.get(OBJECT_STORE_NAME, this._getId(url));\n return entry.timestamp;\n }\n /**\n * Iterates through all the entries in the object store (from newest to\n * oldest) and removes entries once either `maxCount` is reached or the\n * entry's timestamp is less than `minTimestamp`.\n *\n * @param {number} minTimestamp\n * @param {number} maxCount\n * @return {Array<string>}\n *\n * @private\n */\n async expireEntries(minTimestamp, maxCount) {\n const entriesToDelete = await this._db.transaction(OBJECT_STORE_NAME, 'readwrite', (txn, done) => {\n const store = txn.objectStore(OBJECT_STORE_NAME);\n const request = store.index('timestamp').openCursor(null, 'prev');\n const entriesToDelete = [];\n let entriesNotDeletedCount = 0;\n request.onsuccess = () => {\n const cursor = request.result;\n if (cursor) {\n const result = cursor.value;\n // TODO(philipwalton): once we can use a multi-key index, we\n // won't have to check `cacheName` here.\n if (result.cacheName === this._cacheName) {\n // Delete an entry if it's older than the max age or\n // if we already have the max number allowed.\n if ((minTimestamp && result.timestamp < minTimestamp) ||\n (maxCount && entriesNotDeletedCount >= maxCount)) {\n // TODO(philipwalton): we should be able to delete the\n // entry right here, but doing so causes an iteration\n // bug in Safari stable (fixed in TP). Instead we can\n /Line truncated
@@ -0,0 +1,102 @@
this.workbox = this.workbox || {};
this.workbox.navigationPreload = (function (exports, logger_js) {
'use strict';
try {
self['workbox:navigation-preload:5.1.4'] && _();
} catch (e) {}
/*
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.
*/
/**
* @return {boolean} Whether or not the current browser supports enabling
* navigation preload.
*
* @memberof module:workbox-navigation-preload
*/
function isSupported() {
return Boolean(self.registration && self.registration.navigationPreload);
}
/*
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.
*/
/**
* If the browser supports Navigation Preload, then this will disable it.
*
* @memberof module:workbox-navigation-preload
*/
function disable() {
if (isSupported()) {
self.addEventListener('activate', event => {
event.waitUntil(self.registration.navigationPreload.disable().then(() => {
{
logger_js.logger.log(`Navigation preload is disabled.`);
}
}));
});
} else {
{
logger_js.logger.log(`Navigation preload is not supported in this browser.`);
}
}
}
/*
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.
*/
/**
* If the browser supports Navigation Preload, then this will enable it.
*
* @param {string} [headerValue] Optionally, allows developers to
* [override](https://developers.google.com/web/updates/2017/02/navigation-preload#changing_the_header)
* the value of the `Service-Worker-Navigation-Preload` header which will be
* sent to the server when making the navigation request.
*
* @memberof module:workbox-navigation-preload
*/
function enable(headerValue) {
if (isSupported()) {
self.addEventListener('activate', event => {
event.waitUntil(self.registration.navigationPreload.enable().then(() => {
// Defaults to Service-Worker-Navigation-Preload: true if not set.
if (headerValue) {
self.registration.navigationPreload.setHeaderValue(headerValue);
}
{
logger_js.logger.log(`Navigation preload is enabled.`);
}
}));
});
} else {
{
logger_js.logger.log(`Navigation preload is not supported in this browser.`);
}
}
}
exports.disable = disable;
exports.enable = enable;
exports.isSupported = isSupported;
return exports;
}({}, workbox.core._private));
//# sourceMappingURL=workbox-navigation-preload.dev.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-navigation-preload.dev.js","sources":["../_version.js","../isSupported.js","../disable.js","../enable.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:navigation-preload:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport './_version.js';\n/**\n * @return {boolean} Whether or not the current browser supports enabling\n * navigation preload.\n *\n * @memberof module:workbox-navigation-preload\n */\nfunction isSupported() {\n return Boolean(self.registration && self.registration.navigationPreload);\n}\nexport { isSupported };\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { isSupported } from './isSupported.js';\nimport './_version.js';\n/**\n * If the browser supports Navigation Preload, then this will disable it.\n *\n * @memberof module:workbox-navigation-preload\n */\nfunction disable() {\n if (isSupported()) {\n self.addEventListener('activate', (event) => {\n event.waitUntil(self.registration.navigationPreload.disable().then(() => {\n if (process.env.NODE_ENV !== 'production') {\n logger.log(`Navigation preload is disabled.`);\n }\n }));\n });\n }\n else {\n if (process.env.NODE_ENV !== 'production') {\n logger.log(`Navigation preload is not supported in this browser.`);\n }\n }\n}\nexport { disable };\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { isSupported } from './isSupported.js';\nimport './_version.js';\n/**\n * If the browser supports Navigation Preload, then this will enable it.\n *\n * @param {string} [headerValue] Optionally, allows developers to\n * [override](https://developers.google.com/web/updates/2017/02/navigation-preload#changing_the_header)\n * the value of the `Service-Worker-Navigation-Preload` header which will be\n * sent to the server when making the navigation request.\n *\n * @memberof module:workbox-navigation-preload\n */\nfunction enable(headerValue) {\n if (isSupported()) {\n self.addEventListener('activate', (event) => {\n event.waitUntil(self.registration.navigationPreload.enable().then(() => {\n // Defaults to Service-Worker-Navigation-Preload: true if not set.\n if (headerValue) {\n self.registration.navigationPreload.setHeaderValue(headerValue);\n }\n if (process.env.NODE_ENV !== 'production') {\n logger.log(`Navigation preload is enabled.`);\n }\n }));\n });\n }\n else {\n if (process.env.NODE_ENV !== 'production') {\n logger.log(`Navigation preload is not supported in this browser.`);\n }\n }\n}\nexport { enable };\n"],"names":["self","_","e","isSupported","Boolean","registration","navigationPreload","disable","addEventListener","event","waitUntil","then","logger","log","enable","headerValue","setHeaderValue"],"mappings":";;;;IAEA,IAAI;IACAA,EAAAA,IAAI,CAAC,kCAAD,CAAJ,IAA4CC,CAAC,EAA7C;IACH,CAFD,CAGA,OAAOC,CAAP,EAAU;;ICLV;;;;;;;AAOA,IACA;;;;;;;IAMA,SAASC,WAAT,GAAuB;IACnB,SAAOC,OAAO,CAACJ,IAAI,CAACK,YAAL,IAAqBL,IAAI,CAACK,YAAL,CAAkBC,iBAAxC,CAAd;IACH;;IChBD;;;;;;;AAOA,IAGA;;;;;;IAKA,SAASC,OAAT,GAAmB;IACf,MAAIJ,WAAW,EAAf,EAAmB;IACfH,IAAAA,IAAI,CAACQ,gBAAL,CAAsB,UAAtB,EAAmCC,KAAD,IAAW;IACzCA,MAAAA,KAAK,CAACC,SAAN,CAAgBV,IAAI,CAACK,YAAL,CAAkBC,iBAAlB,CAAoCC,OAApC,GAA8CI,IAA9C,CAAmD,MAAM;IACrE,QAA2C;IACvCC,UAAAA,gBAAM,CAACC,GAAP,CAAY,iCAAZ;IACH;IACJ,OAJe,CAAhB;IAKH,KAND;IAOH,GARD,MASK;IACD,IAA2C;IACvCD,MAAAA,gBAAM,CAACC,GAAP,CAAY,sDAAZ;IACH;IACJ;IACJ;;IC9BD;;;;;;;AAOA,IAGA;;;;;;;;;;;IAUA,SAASC,MAAT,CAAgBC,WAAhB,EAA6B;IACzB,MAAIZ,WAAW,EAAf,EAAmB;IACfH,IAAAA,IAAI,CAACQ,gBAAL,CAAsB,UAAtB,EAAmCC,KAAD,IAAW;IACzCA,MAAAA,KAAK,CAACC,SAAN,CAAgBV,IAAI,CAACK,YAAL,CAAkBC,iBAAlB,CAAoCQ,MAApC,GAA6CH,IAA7C,CAAkD,MAAM;IACpE;IACA,YAAII,WAAJ,EAAiB;IACbf,UAAAA,IAAI,CAACK,YAAL,CAAkBC,iBAAlB,CAAoCU,cAApC,CAAmDD,WAAnD;IACH;;IACD,QAA2C;IACvCH,UAAAA,gBAAM,CAACC,GAAP,CAAY,gCAAZ;IACH;IACJ,OARe,CAAhB;IASH,KAVD;IAWH,GAZD,MAaK;IACD,IAA2C;IACvCD,MAAAA,gBAAM,CAACC,GAAP,CAAY,sDAAZ;IACH;IACJ;IACJ;;;;;;;;;;;;"}
@@ -0,0 +1,2 @@
this.workbox=this.workbox||{},this.workbox.navigationPreload=function(t){"use strict";try{self["workbox:navigation-preload:5.1.4"]&&_()}catch(t){}function e(){return Boolean(self.registration&&self.registration.navigationPreload)}return t.disable=function(){e()&&self.addEventListener("activate",t=>{t.waitUntil(self.registration.navigationPreload.disable().then(()=>{}))})},t.enable=function(t){e()&&self.addEventListener("activate",e=>{e.waitUntil(self.registration.navigationPreload.enable().then(()=>{t&&self.registration.navigationPreload.setHeaderValue(t)}))})},t.isSupported=e,t}({});
//# sourceMappingURL=workbox-navigation-preload.prod.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-navigation-preload.prod.js","sources":["../_version.js","../isSupported.js","../disable.js","../enable.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:navigation-preload:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport './_version.js';\n/**\n * @return {boolean} Whether or not the current browser supports enabling\n * navigation preload.\n *\n * @memberof module:workbox-navigation-preload\n */\nfunction isSupported() {\n return Boolean(self.registration && self.registration.navigationPreload);\n}\nexport { isSupported };\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { isSupported } from './isSupported.js';\nimport './_version.js';\n/**\n * If the browser supports Navigation Preload, then this will disable it.\n *\n * @memberof module:workbox-navigation-preload\n */\nfunction disable() {\n if (isSupported()) {\n self.addEventListener('activate', (event) => {\n event.waitUntil(self.registration.navigationPreload.disable().then(() => {\n if (process.env.NODE_ENV !== 'production') {\n logger.log(`Navigation preload is disabled.`);\n }\n }));\n });\n }\n else {\n if (process.env.NODE_ENV !== 'production') {\n logger.log(`Navigation preload is not supported in this browser.`);\n }\n }\n}\nexport { disable };\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { isSupported } from './isSupported.js';\nimport './_version.js';\n/**\n * If the browser supports Navigation Preload, then this will enable it.\n *\n * @param {string} [headerValue] Optionally, allows developers to\n * [override](https://developers.google.com/web/updates/2017/02/navigation-preload#changing_the_header)\n * the value of the `Service-Worker-Navigation-Preload` header which will be\n * sent to the server when making the navigation request.\n *\n * @memberof module:workbox-navigation-preload\n */\nfunction enable(headerValue) {\n if (isSupported()) {\n self.addEventListener('activate', (event) => {\n event.waitUntil(self.registration.navigationPreload.enable().then(() => {\n // Defaults to Service-Worker-Navigation-Preload: true if not set.\n if (headerValue) {\n self.registration.navigationPreload.setHeaderValue(headerValue);\n }\n if (process.env.NODE_ENV !== 'production') {\n logger.log(`Navigation preload is enabled.`);\n }\n }));\n });\n }\n else {\n if (process.env.NODE_ENV !== 'production') {\n logger.log(`Navigation preload is not supported in this browser.`);\n }\n }\n}\nexport { enable };\n"],"names":["self","_","e","isSupported","Boolean","registration","navigationPreload","addEventListener","event","waitUntil","disable","then","headerValue","enable","setHeaderValue"],"mappings":"sFAEA,IACIA,KAAK,qCAAuCC,IAEhD,MAAOC,ICSP,SAASC,WACEC,QAAQJ,KAAKK,cAAgBL,KAAKK,aAAaC,oCCA1D,WACQH,KACAH,KAAKO,iBAAiB,WAAaC,IAC/BA,EAAMC,UAAUT,KAAKK,aAAaC,kBAAkBI,UAAUC,KAAK,qBCE/E,SAAgBC,GACRT,KACAH,KAAKO,iBAAiB,WAAaC,IAC/BA,EAAMC,UAAUT,KAAKK,aAAaC,kBAAkBO,SAASF,KAAK,KAE1DC,GACAZ,KAAKK,aAAaC,kBAAkBQ,eAAeF"}
@@ -0,0 +1,235 @@
this.workbox = this.workbox || {};
this.workbox.googleAnalytics = (function (exports, BackgroundSyncPlugin_js, cacheNames_js, getFriendlyURL_js, logger_js, Route_js, Router_js, NetworkFirst_js, NetworkOnly_js) {
'use strict';
try {
self['workbox:google-analytics:5.1.4'] && _();
} catch (e) {}
/*
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 QUEUE_NAME = 'workbox-google-analytics';
const MAX_RETENTION_TIME = 60 * 48; // Two days in minutes
const GOOGLE_ANALYTICS_HOST = 'www.google-analytics.com';
const GTM_HOST = 'www.googletagmanager.com';
const ANALYTICS_JS_PATH = '/analytics.js';
const GTAG_JS_PATH = '/gtag/js';
const GTM_JS_PATH = '/gtm.js';
// endpoints. Most of the time the default path (/collect) is used, but
// occasionally an experimental endpoint is used when testing new features,
// (e.g. /r/collect or /j/collect)
const COLLECT_PATHS_REGEX = /^\/(\w+\/)?collect/;
/*
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.
*/
/**
* Creates the requestWillDequeue callback to be used with the background
* sync plugin. The callback takes the failed request and adds the
* `qt` param based on the current time, as well as applies any other
* user-defined hit modifications.
*
* @param {Object} config See {@link module:workbox-google-analytics.initialize}.
* @return {Function} The requestWillDequeue callback function.
*
* @private
*/
const createOnSyncCallback = config => {
return async ({
queue
}) => {
let entry;
while (entry = await queue.shiftRequest()) {
const {
request,
timestamp
} = entry;
const url = new URL(request.url);
try {
// Measurement protocol requests can set their payload parameters in
// either the URL query string (for GET requests) or the POST body.
const params = request.method === 'POST' ? new URLSearchParams(await request.clone().text()) : url.searchParams; // Calculate the qt param, accounting for the fact that an existing
// qt param may be present and should be updated rather than replaced.
const originalHitTime = timestamp - (Number(params.get('qt')) || 0);
const queueTime = Date.now() - originalHitTime; // Set the qt param prior to applying hitFilter or parameterOverrides.
params.set('qt', String(queueTime)); // Apply `parameterOverrides`, if set.
if (config.parameterOverrides) {
for (const param of Object.keys(config.parameterOverrides)) {
const value = config.parameterOverrides[param];
params.set(param, value);
}
} // Apply `hitFilter`, if set.
if (typeof config.hitFilter === 'function') {
config.hitFilter.call(null, params);
} // Retry the fetch. Ignore URL search params from the URL as they're
// now in the post body.
await fetch(new Request(url.origin + url.pathname, {
body: params.toString(),
method: 'POST',
mode: 'cors',
credentials: 'omit',
headers: {
'Content-Type': 'text/plain'
}
}));
if ("dev" !== 'production') {
logger_js.logger.log(`Request for '${getFriendlyURL_js.getFriendlyURL(url.href)}'` + `has been replayed`);
}
} catch (err) {
await queue.unshiftRequest(entry);
{
logger_js.logger.log(`Request for '${getFriendlyURL_js.getFriendlyURL(url.href)}'` + `failed to replay, putting it back in the queue.`);
}
throw err;
}
}
{
logger_js.logger.log(`All Google Analytics request successfully replayed; ` + `the queue is now empty!`);
}
};
};
/**
* Creates GET and POST routes to catch failed Measurement Protocol hits.
*
* @param {BackgroundSyncPlugin} bgSyncPlugin
* @return {Array<Route>} The created routes.
*
* @private
*/
const createCollectRoutes = bgSyncPlugin => {
const match = ({
url
}) => url.hostname === GOOGLE_ANALYTICS_HOST && COLLECT_PATHS_REGEX.test(url.pathname);
const handler = new NetworkOnly_js.NetworkOnly({
plugins: [bgSyncPlugin]
});
return [new Route_js.Route(match, handler, 'GET'), new Route_js.Route(match, handler, 'POST')];
};
/**
* Creates a route with a network first strategy for the analytics.js script.
*
* @param {string} cacheName
* @return {Route} The created route.
*
* @private
*/
const createAnalyticsJsRoute = cacheName => {
const match = ({
url
}) => url.hostname === GOOGLE_ANALYTICS_HOST && url.pathname === ANALYTICS_JS_PATH;
const handler = new NetworkFirst_js.NetworkFirst({
cacheName
});
return new Route_js.Route(match, handler, 'GET');
};
/**
* Creates a route with a network first strategy for the gtag.js script.
*
* @param {string} cacheName
* @return {Route} The created route.
*
* @private
*/
const createGtagJsRoute = cacheName => {
const match = ({
url
}) => url.hostname === GTM_HOST && url.pathname === GTAG_JS_PATH;
const handler = new NetworkFirst_js.NetworkFirst({
cacheName
});
return new Route_js.Route(match, handler, 'GET');
};
/**
* Creates a route with a network first strategy for the gtm.js script.
*
* @param {string} cacheName
* @return {Route} The created route.
*
* @private
*/
const createGtmJsRoute = cacheName => {
const match = ({
url
}) => url.hostname === GTM_HOST && url.pathname === GTM_JS_PATH;
const handler = new NetworkFirst_js.NetworkFirst({
cacheName
});
return new Route_js.Route(match, handler, 'GET');
};
/**
* @param {Object=} [options]
* @param {Object} [options.cacheName] The cache name to store and retrieve
* analytics.js. Defaults to the cache names provided by `workbox-core`.
* @param {Object} [options.parameterOverrides]
* [Measurement Protocol parameters](https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters),
* expressed as key/value pairs, to be added to replayed Google Analytics
* requests. This can be used to, e.g., set a custom dimension indicating
* that the request was replayed.
* @param {Function} [options.hitFilter] A function that allows you to modify
* the hit parameters prior to replaying
* the hit. The function is invoked with the original hit's URLSearchParams
* object as its only argument.
*
* @memberof module:workbox-google-analytics
*/
const initialize = (options = {}) => {
const cacheName = cacheNames_js.cacheNames.getGoogleAnalyticsName(options.cacheName);
const bgSyncPlugin = new BackgroundSyncPlugin_js.BackgroundSyncPlugin(QUEUE_NAME, {
maxRetentionTime: MAX_RETENTION_TIME,
onSync: createOnSyncCallback(options)
});
const routes = [createGtmJsRoute(cacheName), createAnalyticsJsRoute(cacheName), createGtagJsRoute(cacheName), ...createCollectRoutes(bgSyncPlugin)];
const router = new Router_js.Router();
for (const route of routes) {
router.registerRoute(route);
}
router.addFetchListener();
};
exports.initialize = initialize;
return exports;
}({}, workbox.backgroundSync, workbox.core._private, workbox.core._private, workbox.core._private, workbox.routing, workbox.routing, workbox.strategies, workbox.strategies));
//# sourceMappingURL=workbox-offline-ga.dev.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-offline-ga.dev.js","sources":["../_version.js","../utils/constants.js","../initialize.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:google-analytics:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\nexport const QUEUE_NAME = 'workbox-google-analytics';\nexport const MAX_RETENTION_TIME = 60 * 48; // Two days in minutes\nexport const GOOGLE_ANALYTICS_HOST = 'www.google-analytics.com';\nexport const GTM_HOST = 'www.googletagmanager.com';\nexport const ANALYTICS_JS_PATH = '/analytics.js';\nexport const GTAG_JS_PATH = '/gtag/js';\nexport const GTM_JS_PATH = '/gtm.js';\nexport const COLLECT_DEFAULT_PATH = '/collect';\n// This RegExp matches all known Measurement Protocol single-hit collect\n// endpoints. Most of the time the default path (/collect) is used, but\n// occasionally an experimental endpoint is used when testing new features,\n// (e.g. /r/collect or /j/collect)\nexport const COLLECT_PATHS_REGEX = /^\\/(\\w+\\/)?collect/;\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { BackgroundSyncPlugin } from 'workbox-background-sync/BackgroundSyncPlugin.js';\nimport { cacheNames } from 'workbox-core/_private/cacheNames.js';\nimport { getFriendlyURL } from 'workbox-core/_private/getFriendlyURL.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { Route } from 'workbox-routing/Route.js';\nimport { Router } from 'workbox-routing/Router.js';\nimport { NetworkFirst } from 'workbox-strategies/NetworkFirst.js';\nimport { NetworkOnly } from 'workbox-strategies/NetworkOnly.js';\nimport { QUEUE_NAME, MAX_RETENTION_TIME, GOOGLE_ANALYTICS_HOST, GTM_HOST, ANALYTICS_JS_PATH, GTAG_JS_PATH, GTM_JS_PATH, COLLECT_PATHS_REGEX, } from './utils/constants.js';\nimport './_version.js';\n/**\n * Creates the requestWillDequeue callback to be used with the background\n * sync plugin. The callback takes the failed request and adds the\n * `qt` param based on the current time, as well as applies any other\n * user-defined hit modifications.\n *\n * @param {Object} config See {@link module:workbox-google-analytics.initialize}.\n * @return {Function} The requestWillDequeue callback function.\n *\n * @private\n */\nconst createOnSyncCallback = (config) => {\n return async ({ queue }) => {\n let entry;\n while (entry = await queue.shiftRequest()) {\n const { request, timestamp } = entry;\n const url = new URL(request.url);\n try {\n // Measurement protocol requests can set their payload parameters in\n // either the URL query string (for GET requests) or the POST body.\n const params = request.method === 'POST' ?\n new URLSearchParams(await request.clone().text()) :\n url.searchParams;\n // Calculate the qt param, accounting for the fact that an existing\n // qt param may be present and should be updated rather than replaced.\n const originalHitTime = timestamp - (Number(params.get('qt')) || 0);\n const queueTime = Date.now() - originalHitTime;\n // Set the qt param prior to applying hitFilter or parameterOverrides.\n params.set('qt', String(queueTime));\n // Apply `parameterOverrides`, if set.\n if (config.parameterOverrides) {\n for (const param of Object.keys(config.parameterOverrides)) {\n const value = config.parameterOverrides[param];\n params.set(param, value);\n }\n }\n // Apply `hitFilter`, if set.\n if (typeof config.hitFilter === 'function') {\n config.hitFilter.call(null, params);\n }\n // Retry the fetch. Ignore URL search params from the URL as they're\n // now in the post body.\n await fetch(new Request(url.origin + url.pathname, {\n body: params.toString(),\n method: 'POST',\n mode: 'cors',\n credentials: 'omit',\n headers: { 'Content-Type': 'text/plain' },\n }));\n if (process.env.NODE_ENV !== 'production') {\n logger.log(`Request for '${getFriendlyURL(url.href)}'` +\n `has been replayed`);\n }\n }\n catch (err) {\n await queue.unshiftRequest(entry);\n if (process.env.NODE_ENV !== 'production') {\n Line truncated
@@ -0,0 +1,2 @@
this.workbox=this.workbox||{},this.workbox.googleAnalytics=function(t,o,e,n,a,c,r,w,s){"use strict";try{self["workbox:google-analytics:5.1.4"]&&_()}catch(t){}const i=/^\/(\w+\/)?collect/,l=t=>{const o=({url:t})=>"www.google-analytics.com"===t.hostname&&i.test(t.pathname),e=new s.NetworkOnly({plugins:[t]});return[new c.Route(o,e,"GET"),new c.Route(o,e,"POST")]},g=t=>{const o=new w.NetworkFirst({cacheName:t});return new c.Route(({url:t})=>"www.google-analytics.com"===t.hostname&&"/analytics.js"===t.pathname,o,"GET")},m=t=>{const o=new w.NetworkFirst({cacheName:t});return new c.Route(({url:t})=>"www.googletagmanager.com"===t.hostname&&"/gtag/js"===t.pathname,o,"GET")},u=t=>{const o=new w.NetworkFirst({cacheName:t});return new c.Route(({url:t})=>"www.googletagmanager.com"===t.hostname&&"/gtm.js"===t.pathname,o,"GET")};return t.initialize=(t={})=>{const n=e.cacheNames.getGoogleAnalyticsName(t.cacheName),a=new o.BackgroundSyncPlugin("workbox-google-analytics",{maxRetentionTime:2880,onSync:(c=t,async({queue:t})=>{let o;for(;o=await t.shiftRequest();){const{request:e,timestamp:n}=o,a=new URL(e.url);try{const t="POST"===e.method?new URLSearchParams(await e.clone().text()):a.searchParams,o=n-(Number(t.get("qt"))||0),r=Date.now()-o;if(t.set("qt",String(r)),c.parameterOverrides)for(const o of Object.keys(c.parameterOverrides)){const e=c.parameterOverrides[o];t.set(o,e)}"function"==typeof c.hitFilter&&c.hitFilter.call(null,t),await fetch(new Request(a.origin+a.pathname,{body:t.toString(),method:"POST",mode:"cors",credentials:"omit",headers:{"Content-Type":"text/plain"}}))}catch(e){throw await t.unshiftRequest(o),e}}})});var c;const w=[u(n),g(n),m(n),...l(a)],s=new r.Router;for(const t of w)s.registerRoute(t);s.addFetchListener()},t}({},workbox.backgroundSync,workbox.core._private,workbox.core._private,workbox.core._private,workbox.routing,workbox.routing,workbox.strategies,workbox.strategies);
//# sourceMappingURL=workbox-offline-ga.prod.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-offline-ga.prod.js","sources":["../_version.js","../utils/constants.js","../initialize.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:google-analytics:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\nexport const QUEUE_NAME = 'workbox-google-analytics';\nexport const MAX_RETENTION_TIME = 60 * 48; // Two days in minutes\nexport const GOOGLE_ANALYTICS_HOST = 'www.google-analytics.com';\nexport const GTM_HOST = 'www.googletagmanager.com';\nexport const ANALYTICS_JS_PATH = '/analytics.js';\nexport const GTAG_JS_PATH = '/gtag/js';\nexport const GTM_JS_PATH = '/gtm.js';\nexport const COLLECT_DEFAULT_PATH = '/collect';\n// This RegExp matches all known Measurement Protocol single-hit collect\n// endpoints. Most of the time the default path (/collect) is used, but\n// occasionally an experimental endpoint is used when testing new features,\n// (e.g. /r/collect or /j/collect)\nexport const COLLECT_PATHS_REGEX = /^\\/(\\w+\\/)?collect/;\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { BackgroundSyncPlugin } from 'workbox-background-sync/BackgroundSyncPlugin.js';\nimport { cacheNames } from 'workbox-core/_private/cacheNames.js';\nimport { getFriendlyURL } from 'workbox-core/_private/getFriendlyURL.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { Route } from 'workbox-routing/Route.js';\nimport { Router } from 'workbox-routing/Router.js';\nimport { NetworkFirst } from 'workbox-strategies/NetworkFirst.js';\nimport { NetworkOnly } from 'workbox-strategies/NetworkOnly.js';\nimport { QUEUE_NAME, MAX_RETENTION_TIME, GOOGLE_ANALYTICS_HOST, GTM_HOST, ANALYTICS_JS_PATH, GTAG_JS_PATH, GTM_JS_PATH, COLLECT_PATHS_REGEX, } from './utils/constants.js';\nimport './_version.js';\n/**\n * Creates the requestWillDequeue callback to be used with the background\n * sync plugin. The callback takes the failed request and adds the\n * `qt` param based on the current time, as well as applies any other\n * user-defined hit modifications.\n *\n * @param {Object} config See {@link module:workbox-google-analytics.initialize}.\n * @return {Function} The requestWillDequeue callback function.\n *\n * @private\n */\nconst createOnSyncCallback = (config) => {\n return async ({ queue }) => {\n let entry;\n while (entry = await queue.shiftRequest()) {\n const { request, timestamp } = entry;\n const url = new URL(request.url);\n try {\n // Measurement protocol requests can set their payload parameters in\n // either the URL query string (for GET requests) or the POST body.\n const params = request.method === 'POST' ?\n new URLSearchParams(await request.clone().text()) :\n url.searchParams;\n // Calculate the qt param, accounting for the fact that an existing\n // qt param may be present and should be updated rather than replaced.\n const originalHitTime = timestamp - (Number(params.get('qt')) || 0);\n const queueTime = Date.now() - originalHitTime;\n // Set the qt param prior to applying hitFilter or parameterOverrides.\n params.set('qt', String(queueTime));\n // Apply `parameterOverrides`, if set.\n if (config.parameterOverrides) {\n for (const param of Object.keys(config.parameterOverrides)) {\n const value = config.parameterOverrides[param];\n params.set(param, value);\n }\n }\n // Apply `hitFilter`, if set.\n if (typeof config.hitFilter === 'function') {\n config.hitFilter.call(null, params);\n }\n // Retry the fetch. Ignore URL search params from the URL as they're\n // now in the post body.\n await fetch(new Request(url.origin + url.pathname, {\n body: params.toString(),\n method: 'POST',\n mode: 'cors',\n credentials: 'omit',\n headers: { 'Content-Type': 'text/plain' },\n }));\n if (process.env.NODE_ENV !== 'production') {\n logger.log(`Request for '${getFriendlyURL(url.href)}'` +\n `has been replayed`);\n }\n }\n catch (err) {\n await queue.unshiftRequest(entry);\n if (process.env.NODE_ENV !== 'production') {\n Line truncated
File diff suppressed because it is too large. Load diff
@@ -0,0 +1 @@
{"version":3,"file":"workbox-precaching.dev.js","sources":["../_version.js","../utils/precachePlugins.js","../addPlugins.js","../utils/createCacheKey.js","../utils/printCleanupDetails.js","../utils/printInstallDetails.js","../PrecacheController.js","../utils/getOrCreatePrecacheController.js","../utils/removeIgnoredSearchParams.js","../utils/generateURLVariations.js","../utils/getCacheKeyForURL.js","../utils/addFetchListener.js","../addRoute.js","../utils/deleteOutdatedCaches.js","../cleanupOutdatedCaches.js","../createHandler.js","../createHandlerBoundToURL.js","../getCacheKeyForURL.js","../matchPrecache.js","../precache.js","../precacheAndRoute.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:precaching:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\nconst plugins = [];\nexport const precachePlugins = {\n /*\n * @return {Array}\n * @private\n */\n get() {\n return plugins;\n },\n /*\n * @param {Array} newPlugins\n * @private\n */\n add(newPlugins) {\n plugins.push(...newPlugins);\n },\n};\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { precachePlugins } from './utils/precachePlugins.js';\nimport './_version.js';\n/**\n * Adds plugins to precaching.\n *\n * @param {Array<Object>} newPlugins\n *\n * @memberof module:workbox-precaching\n */\nfunction addPlugins(newPlugins) {\n precachePlugins.add(newPlugins);\n}\nexport { addPlugins };\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport '../_version.js';\n// Name of the search parameter used to store revision info.\nconst REVISION_SEARCH_PARAM = '__WB_REVISION__';\n/**\n * Converts a manifest entry into a versioned URL suitable for precaching.\n *\n * @param {Object|string} entry\n * @return {string} A URL with versioning info.\n *\n * @private\n * @memberof module:workbox-precaching\n */\nexport function createCacheKey(entry) {\n if (!entry) {\n throw new WorkboxError('add-to-cache-list-unexpected-type', { entry });\n }\n // If a precache manifest entry is a string, it's assumed to be a versioned\n // URL, like '/app.abcd1234.js'. Return as-is.\n if (typeof entry === 'string') {\n const urlObject = new URL(entry, location.href);\n return {\n cacheKey: urlObject.href,\n url: urlObject.href,\n };\n }\n const { revision, url } = entry;\n if (!url) {\n throw new WorkboxError('add-to-cache-list-unexpected-type', { entry });\n }\n // If there's just a URL and no revision, then it's also assumed to be a\n // versioned URL.\n if (!revision) {\n const urlObject = new URL(url, location.href);\n return {\n cacheKey: urlObject.href,\n url: urlObject.href,\n };\n }\n // Otherwise, construct a properly versioned URL using the custom Workbox\n // search parameter along with the revision info.\n const cacheKeyURL = new URL(url, location.href);\n const originalURL = new URL(url, location.href);\n cacheKeyURL.searchParams.set(REVISION_SEARCH_PARAM, revision);\n return {\n cacheKey: cacheKeyURL.href,\n url: originalURL.href,\n };\n}\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { logger } from 'workbox-core/_private/logger.js';\nimport '../_version.js';\n/**\n * @param {string} groupTitle\n * @param {Array<string>} deletedURLs\n *\n * @private\n */\nconst logGroup = (groupTitle, deletedURLs) => {\n logger.groupCollapsed(groupTitle);\n for (const url of deletedURLs) {\n logger.log(url);\n }\n logger.groupEnd();\n};\n/**\n * @param {Array<string>} deletedURLs\n *\n * @private\n * @memberof module:workbox-precaching\n */\nexport function printCleanupDetails(deletedURLs) {\n const deletionCount = deletedURLs.length;\n if (deletionCount > 0) {\n logger.groupCollapsed(`During precaching cleanup, ` +\n `${deletionCount} cached ` +\n `request${deletionCount === 1 ? ' was' : 's were'} deleted.`);\n logGroup('Deleted Cache Requests', deletedURLs);\n logger.groupEnd();\n }\n}\n","/*\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 LICENSE file or at\n https://opensouLine truncated
@@ -0,0 +1,2 @@
this.workbox=this.workbox||{},this.workbox.precaching=function(t,e,n,i,s,c){"use strict";try{self["workbox:precaching:5.1.4"]&&_()}catch(t){}const r=[],o={get:()=>r,add(t){r.push(...t)}};function a(t){if(!t)throw new s.WorkboxError("add-to-cache-list-unexpected-type",{entry:t});if("string"==typeof t){const e=new URL(t,location.href);return{cacheKey:e.href,url:e.href}}const{revision:e,url:n}=t;if(!n)throw new s.WorkboxError("add-to-cache-list-unexpected-type",{entry:t});if(!e){const t=new URL(n,location.href);return{cacheKey:t.href,url:t.href}}const i=new URL(n,location.href),c=new URL(n,location.href);return i.searchParams.set("__WB_REVISION__",e),{cacheKey:i.href,url:c.href}}class h{constructor(t){this.t=e.cacheNames.getPrecacheName(t),this.i=new Map,this.s=new Map,this.o=new Map}addToCacheList(t){const e=[];for(const n of t){"string"==typeof n?e.push(n):n&&void 0===n.revision&&e.push(n.url);const{cacheKey:t,url:i}=a(n),c="string"!=typeof n&&n.revision?"reload":"default";if(this.i.has(i)&&this.i.get(i)!==t)throw new s.WorkboxError("add-to-cache-list-conflicting-entries",{firstEntry:this.i.get(i),secondEntry:t});if("string"!=typeof n&&n.integrity){if(this.o.has(t)&&this.o.get(t)!==n.integrity)throw new s.WorkboxError("add-to-cache-list-conflicting-integrities",{url:i});this.o.set(t,n.integrity)}if(this.i.set(i,t),this.s.set(i,c),e.length>0){const t=`Workbox is precaching URLs without revision info: ${e.join(", ")}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(t)}}}async install({event:t,plugins:e}={}){const n=[],i=[],s=await self.caches.open(this.t),c=await s.keys(),r=new Set(c.map(t=>t.url));for(const[t,e]of this.i)r.has(e)?i.push(t):n.push({cacheKey:e,url:t});const o=n.map(({cacheKey:n,url:i})=>{const s=this.o.get(n),c=this.s.get(i);return this.h({cacheKey:n,cacheMode:c,event:t,integrity:s,plugins:e,url:i})});await Promise.all(o);return{updatedURLs:n.map(t=>t.url),notUpdatedURLs:i}}async activate(){const t=await self.caches.open(this.t),e=await t.keys(),n=new Set(this.i.values()),i=[];for(const s of e)n.has(s.url)||(await t.delete(s),i.push(s.url));return{deletedURLs:i}}async h({cacheKey:t,url:e,cacheMode:r,event:o,plugins:a,integrity:h}){const u=new Request(e,{integrity:h,cache:r,credentials:"same-origin"});let l,f=await i.fetchWrapper.fetch({event:o,plugins:a,request:u});for(const t of a||[])"cacheWillUpdate"in t&&(l=t);if(!(l?await l.cacheWillUpdate({event:o,request:u,response:f}):f.status<400))throw new s.WorkboxError("bad-precaching-response",{url:e,status:f.status});f.redirected&&(f=await c.copyResponse(f)),await n.cacheWrapper.put({event:o,plugins:a,response:f,request:t===e?u:new Request(t),cacheName:this.t,matchOptions:{ignoreSearch:!0}})}getURLsToCacheKeys(){return this.i}getCachedURLs(){return[...this.i.keys()]}getCacheKeyForURL(t){const e=new URL(t,location.href);return this.i.get(e.href)}async matchPrecache(t){const e=t instanceof Request?t.url:t,n=this.getCacheKeyForURL(e);if(n){return(await self.caches.open(this.t)).match(n)}}createHandler(t=!0){return async({request:e})=>{try{const t=await this.matchPrecache(e);if(t)return t;throw new s.WorkboxError("missing-precache-entry",{cacheName:this.t,url:e instanceof Request?e.url:e})}catch(n){if(t)return fetch(e);throw n}}}createHandlerBoundToURL(t,e=!0){if(!this.getCacheKeyForURL(t))throw new s.WorkboxError("non-precached-url",{url:t});const n=this.createHandler(e),i=new Request(t);return()=>n({request:i})}}let u;const l=()=>(u||(u=new h),u);const f=(t,e)=>{const n=l().getURLsToCacheKeys();for(const i of function*(t,{ignoreURLParametersMatching:e,directoryIndex:n,cleanURLs:i,urlManipulation:s}={}){const c=new URL(t,location.href);c.hash="",yield c.href;const r=function(t,e=[]){for(const n of[...t.searchParams.keys()])e.some(t=>t.test(n))&&t.searchParams.delete(n);return t}(c,e);if(yield r.href,n&&r.pathname.endsWith("/")){const t=new URL(r.href);t.pathname+=n,yield t.href}if(i){const t=new URL(r.href);t.pathname+=".html",yield t.href}if(s){const t=s({url:c});for(const e of t)yield e.href}}(t,e)){const t=n.get(i);if(t)return t}};let w=!1;function d(t){w||((({ignoreURLParametersMatching:t=[/^utm_/],directoryIndex:n="index.html",cleanURLs:i=!0,urlManipulation:s}={})=>{const c=e.cacheNames.getPrecacheName();self.addEventListener("fetch",e=>{const r=f(e.request.url,{cleanURLs:i,directoryIndex:n,ignoreURLParametersMatching:t,urlManipulation:s});if(!r)return;let o=self.caches.open(c).then(t=>t.match(r)).then(t=>t||fetch(r));e.respondWith(o)})})(t),w=!0)}const y=t=>{const e=l(),n=o.get();t.waitUntil(e.install({event:t,plugins:n}).catch(t=>{throw t}))},p=t=>{const e=l();t.waitUntil(e.activate())};function g(t){l().addToCacheList(t),t.length>0&&(self.addEventListener("install",y),self.addEventListener("activate",p))}return t.PrecacheController=h,t.addPlugins=function(t){o.add(t)},t.addRoute=d,t.cleanupOutdatedCaches=function(){self.addEventListener("activate",t=>{const n=e.cacheNames.getPrecacheName();t.waitUntil((asynLine truncated
//# sourceMappingURL=workbox-precaching.prod.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-precaching.prod.js","sources":["../_version.js","../utils/precachePlugins.js","../utils/createCacheKey.js","../PrecacheController.js","../utils/getOrCreatePrecacheController.js","../utils/getCacheKeyForURL.js","../utils/generateURLVariations.js","../utils/removeIgnoredSearchParams.js","../addRoute.js","../utils/addFetchListener.js","../precache.js","../addPlugins.js","../cleanupOutdatedCaches.js","../utils/deleteOutdatedCaches.js","../createHandler.js","../createHandlerBoundToURL.js","../getCacheKeyForURL.js","../matchPrecache.js","../precacheAndRoute.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:precaching:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\nconst plugins = [];\nexport const precachePlugins = {\n /*\n * @return {Array}\n * @private\n */\n get() {\n return plugins;\n },\n /*\n * @param {Array} newPlugins\n * @private\n */\n add(newPlugins) {\n plugins.push(...newPlugins);\n },\n};\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport '../_version.js';\n// Name of the search parameter used to store revision info.\nconst REVISION_SEARCH_PARAM = '__WB_REVISION__';\n/**\n * Converts a manifest entry into a versioned URL suitable for precaching.\n *\n * @param {Object|string} entry\n * @return {string} A URL with versioning info.\n *\n * @private\n * @memberof module:workbox-precaching\n */\nexport function createCacheKey(entry) {\n if (!entry) {\n throw new WorkboxError('add-to-cache-list-unexpected-type', { entry });\n }\n // If a precache manifest entry is a string, it's assumed to be a versioned\n // URL, like '/app.abcd1234.js'. Return as-is.\n if (typeof entry === 'string') {\n const urlObject = new URL(entry, location.href);\n return {\n cacheKey: urlObject.href,\n url: urlObject.href,\n };\n }\n const { revision, url } = entry;\n if (!url) {\n throw new WorkboxError('add-to-cache-list-unexpected-type', { entry });\n }\n // If there's just a URL and no revision, then it's also assumed to be a\n // versioned URL.\n if (!revision) {\n const urlObject = new URL(url, location.href);\n return {\n cacheKey: urlObject.href,\n url: urlObject.href,\n };\n }\n // Otherwise, construct a properly versioned URL using the custom Workbox\n // search parameter along with the revision info.\n const cacheKeyURL = new URL(url, location.href);\n const originalURL = new URL(url, location.href);\n cacheKeyURL.searchParams.set(REVISION_SEARCH_PARAM, revision);\n return {\n cacheKey: cacheKeyURL.href,\n url: originalURL.href,\n };\n}\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { cacheNames } from 'workbox-core/_private/cacheNames.js';\nimport { cacheWrapper } from 'workbox-core/_private/cacheWrapper.js';\nimport { fetchWrapper } from 'workbox-core/_private/fetchWrapper.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport { copyResponse } from 'workbox-core/copyResponse.js';\nimport { createCacheKey } from './utils/createCacheKey.js';\nimport { printCleanupDetails } from './utils/printCleanupDetails.js';\nimport { printInstallDetails } from './utils/printInstallDetails.js';\nimport './_version.js';\n/**\n * Performs efficient precaching of assets.\n *\n * @memberof module:workbox-precaching\n */\nclass PrecacheController {\n /**\n * Create a new PrecacheController.\n *\n * @param {string} [cacheName] An optional name for the cache, to override\n * the default precache name.\n */\n constructor(cacheName) {\n this._cacheName = cacheNames.getPrecacheName(cacheName);\n this._urlsToCacheKeys = new Map();\n this._urlsToCacheModes = new Map();\n this._cacheKeysToIntegrities = new Map();\n }\n /**\n * This method will add items to the precache list, removing duplicates\n * and ensuring the information is valid.\n *\n * @param {\n * Array<module:workbox-precaching.PrecacheController.PrecacheEntry|string>\n * } entries Array of entries to precache.\n */\n addToCacheList(entries) {\n if (process.env.NODE_ENV !== 'production') {\n Line truncated
@@ -0,0 +1,262 @@
this.workbox = this.workbox || {};
this.workbox.rangeRequests = (function (exports, WorkboxError_js, assert_js, logger_js) {
'use strict';
try {
self['workbox:range-requests:5.1.4'] && _();
} catch (e) {}
/*
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.
*/
/**
* @param {Blob} blob A source blob.
* @param {number} [start] The offset to use as the start of the
* slice.
* @param {number} [end] The offset to use as the end of the slice.
* @return {Object} An object with `start` and `end` properties, reflecting
* the effective boundaries to use given the size of the blob.
*
* @private
*/
function calculateEffectiveBoundaries(blob, start, end) {
{
assert_js.assert.isInstance(blob, Blob, {
moduleName: 'workbox-range-requests',
funcName: 'calculateEffectiveBoundaries',
paramName: 'blob'
});
}
const blobSize = blob.size;
if (end && end > blobSize || start && start < 0) {
throw new WorkboxError_js.WorkboxError('range-not-satisfiable', {
size: blobSize,
end,
start
});
}
let effectiveStart;
let effectiveEnd;
if (start !== undefined && end !== undefined) {
effectiveStart = start; // Range values are inclusive, so add 1 to the value.
effectiveEnd = end + 1;
} else if (start !== undefined && end === undefined) {
effectiveStart = start;
effectiveEnd = blobSize;
} else if (end !== undefined && start === undefined) {
effectiveStart = blobSize - end;
effectiveEnd = blobSize;
}
return {
start: effectiveStart,
end: effectiveEnd
};
}
/*
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.
*/
/**
* @param {string} rangeHeader A Range: header value.
* @return {Object} An object with `start` and `end` properties, reflecting
* the parsed value of the Range: header. If either the `start` or `end` are
* omitted, then `null` will be returned.
*
* @private
*/
function parseRangeHeader(rangeHeader) {
{
assert_js.assert.isType(rangeHeader, 'string', {
moduleName: 'workbox-range-requests',
funcName: 'parseRangeHeader',
paramName: 'rangeHeader'
});
}
const normalizedRangeHeader = rangeHeader.trim().toLowerCase();
if (!normalizedRangeHeader.startsWith('bytes=')) {
throw new WorkboxError_js.WorkboxError('unit-must-be-bytes', {
normalizedRangeHeader
});
} // Specifying multiple ranges separate by commas is valid syntax, but this
// library only attempts to handle a single, contiguous sequence of bytes.
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Range#Syntax
if (normalizedRangeHeader.includes(',')) {
throw new WorkboxError_js.WorkboxError('single-range-only', {
normalizedRangeHeader
});
}
const rangeParts = /(\d*)-(\d*)/.exec(normalizedRangeHeader); // We need either at least one of the start or end values.
if (!rangeParts || !(rangeParts[1] || rangeParts[2])) {
throw new WorkboxError_js.WorkboxError('invalid-range-values', {
normalizedRangeHeader
});
}
return {
start: rangeParts[1] === '' ? undefined : Number(rangeParts[1]),
end: rangeParts[2] === '' ? undefined : Number(rangeParts[2])
};
}
/*
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.
*/
/**
* Given a `Request` and `Response` objects as input, this will return a
* promise for a new `Response`.
*
* If the original `Response` already contains partial content (i.e. it has
* a status of 206), then this assumes it already fulfills the `Range:`
* requirements, and will return it as-is.
*
* @param {Request} request A request, which should contain a Range:
* header.
* @param {Response} originalResponse A response.
* @return {Promise<Response>} Either a `206 Partial Content` response, with
* the response body set to the slice of content specified by the request's
* `Range:` header, or a `416 Range Not Satisfiable` response if the
* conditions of the `Range:` header can't be met.
*
* @memberof module:workbox-range-requests
*/
async function createPartialResponse(request, originalResponse) {
try {
if ("dev" !== 'production') {
assert_js.assert.isInstance(request, Request, {
moduleName: 'workbox-range-requests',
funcName: 'createPartialResponse',
paramName: 'request'
});
assert_js.assert.isInstance(originalResponse, Response, {
moduleName: 'workbox-range-requests',
funcName: 'createPartialResponse',
paramName: 'originalResponse'
});
}
if (originalResponse.status === 206) {
// If we already have a 206, then just pass it through as-is;
// see https://github.com/GoogleChrome/workbox/issues/1720
return originalResponse;
}
const rangeHeader = request.headers.get('range');
if (!rangeHeader) {
throw new WorkboxError_js.WorkboxError('no-range-header');
}
const boundaries = parseRangeHeader(rangeHeader);
const originalBlob = await originalResponse.blob();
const effectiveBoundaries = calculateEffectiveBoundaries(originalBlob, boundaries.start, boundaries.end);
const slicedBlob = originalBlob.slice(effectiveBoundaries.start, effectiveBoundaries.end);
const slicedBlobSize = slicedBlob.size;
const slicedResponse = new Response(slicedBlob, {
// Status code 206 is for a Partial Content response.
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/206
status: 206,
statusText: 'Partial Content',
headers: originalResponse.headers
});
slicedResponse.headers.set('Content-Length', String(slicedBlobSize));
slicedResponse.headers.set('Content-Range', `bytes ${effectiveBoundaries.start}-${effectiveBoundaries.end - 1}/` + originalBlob.size);
return slicedResponse;
} catch (error) {
{
logger_js.logger.warn(`Unable to construct a partial response; returning a ` + `416 Range Not Satisfiable response instead.`);
logger_js.logger.groupCollapsed(`View details here.`);
logger_js.logger.log(error);
logger_js.logger.log(request);
logger_js.logger.log(originalResponse);
logger_js.logger.groupEnd();
}
return new Response('', {
status: 416,
statusText: 'Range Not Satisfiable'
});
}
}
/*
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.
*/
/**
* The range request plugin makes it easy for a request with a 'Range' header to
* be fulfilled by a cached response.
*
* It does this by intercepting the `cachedResponseWillBeUsed` plugin callback
* and returning the appropriate subset of the cached response body.
*
* @memberof module:workbox-range-requests
*/
class RangeRequestsPlugin {
constructor() {
/**
* @param {Object} options
* @param {Request} options.request The original request, which may or may not
* contain a Range: header.
* @param {Response} options.cachedResponse The complete cached response.
* @return {Promise<Response>} If request contains a 'Range' header, then a
* new response with status 206 whose body is a subset of `cachedResponse` is
* returned. Otherwise, `cachedResponse` is returned as-is.
*
* @private
*/
this.cachedResponseWillBeUsed = async ({
request,
cachedResponse
}) => {
// Only return a sliced response if there's something valid in the cache,
// and there's a Range: header in the request.
if (cachedResponse && request.headers.has('range')) {
return await createPartialResponse(request, cachedResponse);
} // If there was no Range: header, or if cachedResponse wasn't valid, just
// pass it through as-is.
return cachedResponse;
};
}
}
exports.RangeRequestsPlugin = RangeRequestsPlugin;
exports.createPartialResponse = createPartialResponse;
return exports;
}({}, workbox.core._private, workbox.core._private, workbox.core._private));
//# sourceMappingURL=workbox-range-requests.dev.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-range-requests.dev.js","sources":["../_version.js","../utils/calculateEffectiveBoundaries.js","../utils/parseRangeHeader.js","../createPartialResponse.js","../RangeRequestsPlugin.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:range-requests:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport { assert } from 'workbox-core/_private/assert.js';\nimport '../_version.js';\n/**\n * @param {Blob} blob A source blob.\n * @param {number} [start] The offset to use as the start of the\n * slice.\n * @param {number} [end] The offset to use as the end of the slice.\n * @return {Object} An object with `start` and `end` properties, reflecting\n * the effective boundaries to use given the size of the blob.\n *\n * @private\n */\nfunction calculateEffectiveBoundaries(blob, start, end) {\n if (process.env.NODE_ENV !== 'production') {\n assert.isInstance(blob, Blob, {\n moduleName: 'workbox-range-requests',\n funcName: 'calculateEffectiveBoundaries',\n paramName: 'blob',\n });\n }\n const blobSize = blob.size;\n if ((end && end > blobSize) || (start && start < 0)) {\n throw new WorkboxError('range-not-satisfiable', {\n size: blobSize,\n end,\n start,\n });\n }\n let effectiveStart;\n let effectiveEnd;\n if (start !== undefined && end !== undefined) {\n effectiveStart = start;\n // Range values are inclusive, so add 1 to the value.\n effectiveEnd = end + 1;\n }\n else if (start !== undefined && end === undefined) {\n effectiveStart = start;\n effectiveEnd = blobSize;\n }\n else if (end !== undefined && start === undefined) {\n effectiveStart = blobSize - end;\n effectiveEnd = blobSize;\n }\n return {\n start: effectiveStart,\n end: effectiveEnd,\n };\n}\nexport { calculateEffectiveBoundaries };\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport { assert } from 'workbox-core/_private/assert.js';\nimport '../_version.js';\n/**\n * @param {string} rangeHeader A Range: header value.\n * @return {Object} An object with `start` and `end` properties, reflecting\n * the parsed value of the Range: header. If either the `start` or `end` are\n * omitted, then `null` will be returned.\n *\n * @private\n */\nfunction parseRangeHeader(rangeHeader) {\n if (process.env.NODE_ENV !== 'production') {\n assert.isType(rangeHeader, 'string', {\n moduleName: 'workbox-range-requests',\n funcName: 'parseRangeHeader',\n paramName: 'rangeHeader',\n });\n }\n const normalizedRangeHeader = rangeHeader.trim().toLowerCase();\n if (!normalizedRangeHeader.startsWith('bytes=')) {\n throw new WorkboxError('unit-must-be-bytes', { normalizedRangeHeader });\n }\n // Specifying multiple ranges separate by commas is valid syntax, but this\n // library only attempts to handle a single, contiguous sequence of bytes.\n // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Range#Syntax\n if (normalizedRangeHeader.includes(',')) {\n throw new WorkboxError('single-range-only', { normalizedRangeHeader });\n }\n const rangeParts = /(\\d*)-(\\d*)/.exec(normalizedRangeHeader);\n // We need either at least one of the start or end values.\n if (!rangeParts || !(rangeParts[1] || rangeParts[2])) {\n throw new WorkboxError('invalid-range-values', { normalizedRangeHeader });\n }\n return {\n start: rangeParts[1] === '' ? undefined : Number(rangeParts[1]),\n end: rangeParts[2] === '' ? undefined : Number(rangeParts[2]),\n };\n}\nexport { parseRangeHeader };\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { calculateEffectiveBoundaries } from './utils/calculateEffectiveBoundaries.js';\nimport { parseRangeHeader } from './utils/parseRangeHeader.js';\nimport './_version.js';\n/**\n * Given a `Request` and `Response` objects as input, this will return a\n * promise for a new `Response`.\n *\n * If the original `Response` already contains partial content (i.e. it has\n * a status of 206), then Line truncated
@@ -0,0 +1,2 @@
this.workbox=this.workbox||{},this.workbox.rangeRequests=function(t,e,n){"use strict";try{self["workbox:range-requests:5.1.4"]&&_()}catch(t){}async function r(t,n){try{if(206===n.status)return n;const r=t.headers.get("range");if(!r)throw new e.WorkboxError("no-range-header");const s=function(t){const n=t.trim().toLowerCase();if(!n.startsWith("bytes="))throw new e.WorkboxError("unit-must-be-bytes",{normalizedRangeHeader:n});if(n.includes(","))throw new e.WorkboxError("single-range-only",{normalizedRangeHeader:n});const r=/(\d*)-(\d*)/.exec(n);if(!r||!r[1]&&!r[2])throw new e.WorkboxError("invalid-range-values",{normalizedRangeHeader:n});return{start:""===r[1]?void 0:Number(r[1]),end:""===r[2]?void 0:Number(r[2])}}(r),a=await n.blob(),o=function(t,n,r){const s=t.size;if(r&&r>s||n&&n<0)throw new e.WorkboxError("range-not-satisfiable",{size:s,end:r,start:n});let a,o;return void 0!==n&&void 0!==r?(a=n,o=r+1):void 0!==n&&void 0===r?(a=n,o=s):void 0!==r&&void 0===n&&(a=s-r,o=s),{start:a,end:o}}(a,s.start,s.end),i=a.slice(o.start,o.end),d=i.size,u=new Response(i,{status:206,statusText:"Partial Content",headers:n.headers});return u.headers.set("Content-Length",String(d)),u.headers.set("Content-Range",`bytes ${o.start}-${o.end-1}/`+a.size),u}catch(t){return new Response("",{status:416,statusText:"Range Not Satisfiable"})}}return t.RangeRequestsPlugin=class{constructor(){this.cachedResponseWillBeUsed=async({request:t,cachedResponse:e})=>e&&t.headers.has("range")?await r(t,e):e}},t.createPartialResponse=r,t}({},workbox.core._private,workbox.core._private);
//# sourceMappingURL=workbox-range-requests.prod.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-range-requests.prod.js","sources":["../_version.js","../createPartialResponse.js","../utils/parseRangeHeader.js","../utils/calculateEffectiveBoundaries.js","../RangeRequestsPlugin.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:range-requests:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { calculateEffectiveBoundaries } from './utils/calculateEffectiveBoundaries.js';\nimport { parseRangeHeader } from './utils/parseRangeHeader.js';\nimport './_version.js';\n/**\n * Given a `Request` and `Response` objects as input, this will return a\n * promise for a new `Response`.\n *\n * If the original `Response` already contains partial content (i.e. it has\n * a status of 206), then this assumes it already fulfills the `Range:`\n * requirements, and will return it as-is.\n *\n * @param {Request} request A request, which should contain a Range:\n * header.\n * @param {Response} originalResponse A response.\n * @return {Promise<Response>} Either a `206 Partial Content` response, with\n * the response body set to the slice of content specified by the request's\n * `Range:` header, or a `416 Range Not Satisfiable` response if the\n * conditions of the `Range:` header can't be met.\n *\n * @memberof module:workbox-range-requests\n */\nasync function createPartialResponse(request, originalResponse) {\n try {\n if (process.env.NODE_ENV !== 'production') {\n assert.isInstance(request, Request, {\n moduleName: 'workbox-range-requests',\n funcName: 'createPartialResponse',\n paramName: 'request',\n });\n assert.isInstance(originalResponse, Response, {\n moduleName: 'workbox-range-requests',\n funcName: 'createPartialResponse',\n paramName: 'originalResponse',\n });\n }\n if (originalResponse.status === 206) {\n // If we already have a 206, then just pass it through as-is;\n // see https://github.com/GoogleChrome/workbox/issues/1720\n return originalResponse;\n }\n const rangeHeader = request.headers.get('range');\n if (!rangeHeader) {\n throw new WorkboxError('no-range-header');\n }\n const boundaries = parseRangeHeader(rangeHeader);\n const originalBlob = await originalResponse.blob();\n const effectiveBoundaries = calculateEffectiveBoundaries(originalBlob, boundaries.start, boundaries.end);\n const slicedBlob = originalBlob.slice(effectiveBoundaries.start, effectiveBoundaries.end);\n const slicedBlobSize = slicedBlob.size;\n const slicedResponse = new Response(slicedBlob, {\n // Status code 206 is for a Partial Content response.\n // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/206\n status: 206,\n statusText: 'Partial Content',\n headers: originalResponse.headers,\n });\n slicedResponse.headers.set('Content-Length', String(slicedBlobSize));\n slicedResponse.headers.set('Content-Range', `bytes ${effectiveBoundaries.start}-${effectiveBoundaries.end - 1}/` +\n originalBlob.size);\n return slicedResponse;\n }\n catch (error) {\n if (process.env.NODE_ENV !== 'production') {\n logger.warn(`Unable to construct a partial response; returning a ` +\n `416 Range Not Satisfiable response instead.`);\n logger.groupCollapsed(`View details here.`);\n logger.log(error);\n logger.log(request);\n logger.log(originalResponse);\n logger.groupEnd();\n }\n return new Response('', {\n status: 416,\n statusText: 'Range Not Satisfiable',\n });\n }\n}\nexport { createPartialResponse };\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport { assert } from 'workbox-core/_private/assert.js';\nimport '../_version.js';\n/**\n * @param {string} rangeHeader A Range: header value.\n * @return {Object} An object with `start` and `end` properties, reflecting\n * the parsed value of the Range: header. If either the `start` or `end` are\n * omitted, then `null` will be returned.\n *\n * @private\n */\nfunction parseRangeHeader(rangeHeader) {\n if (process.env.NODE_ENV !== 'production') {\n assertLine truncated
@@ -0,0 +1,923 @@
this.workbox = this.workbox || {};
this.workbox.routing = (function (exports, assert_js, logger_js, WorkboxError_js, getFriendlyURL_js) {
'use strict';
try {
self['workbox:routing:5.1.4'] && _();
} catch (e) {}
/*
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.
*/
/**
* The default HTTP method, 'GET', used when there's no specific method
* configured for a route.
*
* @type {string}
*
* @private
*/
const defaultMethod = 'GET';
/**
* The list of valid HTTP methods associated with requests that could be routed.
*
* @type {Array<string>}
*
* @private
*/
const validMethods = ['DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT'];
/*
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.
*/
/**
* @param {function()|Object} handler Either a function, or an object with a
* 'handle' method.
* @return {Object} An object with a handle method.
*
* @private
*/
const normalizeHandler = handler => {
if (handler && typeof handler === 'object') {
{
assert_js.assert.hasMethod(handler, 'handle', {
moduleName: 'workbox-routing',
className: 'Route',
funcName: 'constructor',
paramName: 'handler'
});
}
return handler;
} else {
{
assert_js.assert.isType(handler, 'function', {
moduleName: 'workbox-routing',
className: 'Route',
funcName: 'constructor',
paramName: 'handler'
});
}
return {
handle: handler
};
}
};
/*
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.
*/
/**
* A `Route` consists of a pair of callback functions, "match" and "handler".
* The "match" callback determine if a route should be used to "handle" a
* request by returning a non-falsy value if it can. The "handler" callback
* is called when there is a match and should return a Promise that resolves
* to a `Response`.
*
* @memberof module:workbox-routing
*/
class Route {
/**
* Constructor for Route class.
*
* @param {module:workbox-routing~matchCallback} match
* A callback function that determines whether the route matches a given
* `fetch` event by returning a non-falsy value.
* @param {module:workbox-routing~handlerCallback} handler A callback
* function that returns a Promise resolving to a Response.
* @param {string} [method='GET'] The HTTP method to match the Route
* against.
*/
constructor(match, handler, method = defaultMethod) {
{
assert_js.assert.isType(match, 'function', {
moduleName: 'workbox-routing',
className: 'Route',
funcName: 'constructor',
paramName: 'match'
});
if (method) {
assert_js.assert.isOneOf(method, validMethods, {
paramName: 'method'
});
}
} // These values are referenced directly by Router so cannot be
// altered by minificaton.
this.handler = normalizeHandler(handler);
this.match = match;
this.method = method;
}
}
/*
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.
*/
/**
* NavigationRoute makes it easy to create a
* [Route]{@link module:workbox-routing.Route} that matches for browser
* [navigation requests]{@link https://developers.google.com/web/fundamentals/primers/service-workers/high-performance-loading#first_what_are_navigation_requests}.
*
* It will only match incoming Requests whose
* [`mode`]{@link https://fetch.spec.whatwg.org/#concept-request-mode}
* is set to `navigate`.
*
* You can optionally only apply this route to a subset of navigation requests
* by using one or both of the `denylist` and `allowlist` parameters.
*
* @memberof module:workbox-routing
* @extends module:workbox-routing.Route
*/
class NavigationRoute extends Route {
/**
* If both `denylist` and `allowlist` are provided, the `denylist` will
* take precedence and the request will not match this route.
*
* The regular expressions in `allowlist` and `denylist`
* are matched against the concatenated
* [`pathname`]{@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/pathname}
* and [`search`]{@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/search}
* portions of the requested URL.
*
* @param {module:workbox-routing~handlerCallback} handler A callback
* function that returns a Promise resulting in a Response.
* @param {Object} options
* @param {Array<RegExp>} [options.denylist] If any of these patterns match,
* the route will not handle the request (even if a allowlist RegExp matches).
* @param {Array<RegExp>} [options.allowlist=[/./]] If any of these patterns
* match the URL's pathname and search parameter, the route will handle the
* request (assuming the denylist doesn't match).
*/
constructor(handler, {
allowlist = [/./],
denylist = []
} = {}) {
{
assert_js.assert.isArrayOfClass(allowlist, RegExp, {
moduleName: 'workbox-routing',
className: 'NavigationRoute',
funcName: 'constructor',
paramName: 'options.allowlist'
});
assert_js.assert.isArrayOfClass(denylist, RegExp, {
moduleName: 'workbox-routing',
className: 'NavigationRoute',
funcName: 'constructor',
paramName: 'options.denylist'
});
}
super(options => this._match(options), handler);
this._allowlist = allowlist;
this._denylist = denylist;
}
/**
* Routes match handler.
*
* @param {Object} options
* @param {URL} options.url
* @param {Request} options.request
* @return {boolean}
*
* @private
*/
_match({
url,
request
}) {
if (request && request.mode !== 'navigate') {
return false;
}
const pathnameAndSearch = url.pathname + url.search;
for (const regExp of this._denylist) {
if (regExp.test(pathnameAndSearch)) {
{
logger_js.logger.log(`The navigation route ${pathnameAndSearch} is not ` + `being used, since the URL matches this denylist pattern: ` + `${regExp}`);
}
return false;
}
}
if (this._allowlist.some(regExp => regExp.test(pathnameAndSearch))) {
{
logger_js.logger.debug(`The navigation route ${pathnameAndSearch} ` + `is being used.`);
}
return true;
}
{
logger_js.logger.log(`The navigation route ${pathnameAndSearch} is not ` + `being used, since the URL being navigated to doesn't ` + `match the allowlist.`);
}
return false;
}
}
/*
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.
*/
/**
* RegExpRoute makes it easy to create a regular expression based
* [Route]{@link module:workbox-routing.Route}.
*
* For same-origin requests the RegExp only needs to match part of the URL. For
* requests against third-party servers, you must define a RegExp that matches
* the start of the URL.
*
* [See the module docs for info.]{@link https://developers.google.com/web/tools/workbox/modules/workbox-routing}
*
* @memberof module:workbox-routing
* @extends module:workbox-routing.Route
*/
class RegExpRoute extends Route {
/**
* If the regular expression contains
* [capture groups]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#grouping-back-references},
* the captured values will be passed to the
* [handler's]{@link module:workbox-routing~handlerCallback} `params`
* argument.
*
* @param {RegExp} regExp The regular expression to match against URLs.
* @param {module:workbox-routing~handlerCallback} handler A callback
* function that returns a Promise resulting in a Response.
* @param {string} [method='GET'] The HTTP method to match the Route
* against.
*/
constructor(regExp, handler, method) {
{
assert_js.assert.isInstance(regExp, RegExp, {
moduleName: 'workbox-routing',
className: 'RegExpRoute',
funcName: 'constructor',
paramName: 'pattern'
});
}
const match = ({
url
}) => {
const result = regExp.exec(url.href); // Return immediately if there's no match.
if (!result) {
return;
} // Require that the match start at the first character in the URL string
// if it's a cross-origin request.
// See https://github.com/GoogleChrome/workbox/issues/281 for the context
// behind this behavior.
if (url.origin !== location.origin && result.index !== 0) {
{
logger_js.logger.debug(`The regular expression '${regExp}' only partially matched ` + `against the cross-origin URL '${url}'. RegExpRoute's will only ` + `handle cross-origin requests if they match the entire URL.`);
}
return;
} // If the route matches, but there aren't any capture groups defined, then
// this will return [], which is truthy and therefore sufficient to
// indicate a match.
// If there are capture groups, then it will return their values.
return result.slice(1);
};
super(match, handler, method);
}
}
/*
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.
*/
/**
* The Router can be used to process a FetchEvent through one or more
* [Routes]{@link module:workbox-routing.Route} responding with a Request if
* a matching route exists.
*
* If no route matches a given a request, the Router will use a "default"
* handler if one is defined.
*
* Should the matching Route throw an error, the Router will use a "catch"
* handler if one is defined to gracefully deal with issues and respond with a
* Request.
*
* If a request matches multiple routes, the **earliest** registered route will
* be used to respond to the request.
*
* @memberof module:workbox-routing
*/
class Router {
/**
* Initializes a new Router.
*/
constructor() {
this._routes = new Map();
}
/**
* @return {Map<string, Array<module:workbox-routing.Route>>} routes A `Map` of HTTP
* method name ('GET', etc.) to an array of all the corresponding `Route`
* instances that are registered.
*/
get routes() {
return this._routes;
}
/**
* Adds a fetch event listener to respond to events when a route matches
* the event's request.
*/
addFetchListener() {
// See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705
self.addEventListener('fetch', event => {
const {
request
} = event;
const responsePromise = this.handleRequest({
request,
event
});
if (responsePromise) {
event.respondWith(responsePromise);
}
});
}
/**
* Adds a message event listener for URLs to cache from the window.
* This is useful to cache resources loaded on the page prior to when the
* service worker started controlling it.
*
* The format of the message data sent from the window should be as follows.
* Where the `urlsToCache` array may consist of URL strings or an array of
* URL string + `requestInit` object (the same as you'd pass to `fetch()`).
*
* ```
* {
* type: 'CACHE_URLS',
* payload: {
* urlsToCache: [
* './script1.js',
* './script2.js',
* ['./script3.js', {mode: 'no-cors'}],
* ],
* },
* }
* ```
*/
addCacheListener() {
// See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705
self.addEventListener('message', event => {
if (event.data && event.data.type === 'CACHE_URLS') {
const {
payload
} = event.data;
{
logger_js.logger.debug(`Caching URLs from the window`, payload.urlsToCache);
}
const requestPromises = Promise.all(payload.urlsToCache.map(entry => {
if (typeof entry === 'string') {
entry = [entry];
}
const request = new Request(...entry);
return this.handleRequest({
request
}); // TODO(philipwalton): TypeScript errors without this typecast for
// some reason (probably a bug). The real type here should work but
// doesn't: `Array<Promise<Response> | undefined>`.
})); // TypeScript
event.waitUntil(requestPromises); // If a MessageChannel was used, reply to the message on success.
if (event.ports && event.ports[0]) {
requestPromises.then(() => event.ports[0].postMessage(true));
}
}
});
}
/**
* Apply the routing rules to a FetchEvent object to get a Response from an
* appropriate Route's handler.
*
* @param {Object} options
* @param {Request} options.request The request to handle (this is usually
* from a fetch event, but it does not have to be).
* @param {FetchEvent} [options.event] The event that triggered the request,
* if applicable.
* @return {Promise<Response>|undefined} A promise is returned if a
* registered route can handle the request. If there is no matching
* route and there's no `defaultHandler`, `undefined` is returned.
*/
handleRequest({
request,
event
}) {
{
assert_js.assert.isInstance(request, Request, {
moduleName: 'workbox-routing',
className: 'Router',
funcName: 'handleRequest',
paramName: 'options.request'
});
}
const url = new URL(request.url, location.href);
if (!url.protocol.startsWith('http')) {
{
logger_js.logger.debug(`Workbox Router only supports URLs that start with 'http'.`);
}
return;
}
const {
params,
route
} = this.findMatchingRoute({
url,
request,
event
});
let handler = route && route.handler;
const debugMessages = [];
{
if (handler) {
debugMessages.push([`Found a route to handle this request:`, route]);
if (params) {
debugMessages.push([`Passing the following params to the route's handler:`, params]);
}
}
} // If we don't have a handler because there was no matching route, then
// fall back to defaultHandler if that's defined.
if (!handler && this._defaultHandler) {
{
debugMessages.push(`Failed to find a matching route. Falling ` + `back to the default handler.`);
}
handler = this._defaultHandler;
}
if (!handler) {
{
// No handler so Workbox will do nothing. If logs is set of debug
// i.e. verbose, we should print out this information.
logger_js.logger.debug(`No route found for: ${getFriendlyURL_js.getFriendlyURL(url)}`);
}
return;
}
{
// We have a handler, meaning Workbox is going to handle the route.
// print the routing details to the console.
logger_js.logger.groupCollapsed(`Router is responding to: ${getFriendlyURL_js.getFriendlyURL(url)}`);
debugMessages.forEach(msg => {
if (Array.isArray(msg)) {
logger_js.logger.log(...msg);
} else {
logger_js.logger.log(msg);
}
});
logger_js.logger.groupEnd();
} // Wrap in try and catch in case the handle method throws a synchronous
// error. It should still callback to the catch handler.
let responsePromise;
try {
responsePromise = handler.handle({
url,
request,
event,
params
});
} catch (err) {
responsePromise = Promise.reject(err);
}
if (responsePromise instanceof Promise && this._catchHandler) {
responsePromise = responsePromise.catch(err => {
{
// Still include URL here as it will be async from the console group
// and may not make sense without the URL
logger_js.logger.groupCollapsed(`Error thrown when responding to: ` + ` ${getFriendlyURL_js.getFriendlyURL(url)}. Falling back to Catch Handler.`);
logger_js.logger.error(`Error thrown by:`, route);
logger_js.logger.error(err);
logger_js.logger.groupEnd();
}
return this._catchHandler.handle({
url,
request,
event
});
});
}
return responsePromise;
}
/**
* Checks a request and URL (and optionally an event) against the list of
* registered routes, and if there's a match, returns the corresponding
* route along with any params generated by the match.
*
* @param {Object} options
* @param {URL} options.url
* @param {Request} options.request The request to match.
* @param {Event} [options.event] The corresponding event (unless N/A).
* @return {Object} An object with `route` and `params` properties.
* They are populated if a matching route was found or `undefined`
* otherwise.
*/
findMatchingRoute({
url,
request,
event
}) {
{
assert_js.assert.isInstance(url, URL, {
moduleName: 'workbox-routing',
className: 'Router',
funcName: 'findMatchingRoute',
paramName: 'options.url'
});
assert_js.assert.isInstance(request, Request, {
moduleName: 'workbox-routing',
className: 'Router',
funcName: 'findMatchingRoute',
paramName: 'options.request'
});
}
const routes = this._routes.get(request.method) || [];
for (const route of routes) {
let params;
const matchResult = route.match({
url,
request,
event
});
if (matchResult) {
// See https://github.com/GoogleChrome/workbox/issues/2079
params = matchResult;
if (Array.isArray(matchResult) && matchResult.length === 0) {
// Instead of passing an empty array in as params, use undefined.
params = undefined;
} else if (matchResult.constructor === Object && Object.keys(matchResult).length === 0) {
// Instead of passing an empty object in as params, use undefined.
params = undefined;
} else if (typeof matchResult === 'boolean') {
// For the boolean value true (rather than just something truth-y),
// don't set params.
// See https://github.com/GoogleChrome/workbox/pull/2134#issuecomment-513924353
params = undefined;
} // Return early if have a match.
return {
route,
params
};
}
} // If no match was found above, return and empty object.
return {};
}
/**
* Define a default `handler` that's called when no routes explicitly
* match the incoming request.
*
* Without a default handler, unmatched requests will go against the
* network as if there were no service worker present.
*
* @param {module:workbox-routing~handlerCallback} handler A callback
* function that returns a Promise resulting in a Response.
*/
setDefaultHandler(handler) {
this._defaultHandler = normalizeHandler(handler);
}
/**
* If a Route throws an error while handling a request, this `handler`
* will be called and given a chance to provide a response.
*
* @param {module:workbox-routing~handlerCallback} handler A callback
* function that returns a Promise resulting in a Response.
*/
setCatchHandler(handler) {
this._catchHandler = normalizeHandler(handler);
}
/**
* Registers a route with the router.
*
* @param {module:workbox-routing.Route} route The route to register.
*/
registerRoute(route) {
{
assert_js.assert.isType(route, 'object', {
moduleName: 'workbox-routing',
className: 'Router',
funcName: 'registerRoute',
paramName: 'route'
});
assert_js.assert.hasMethod(route, 'match', {
moduleName: 'workbox-routing',
className: 'Router',
funcName: 'registerRoute',
paramName: 'route'
});
assert_js.assert.isType(route.handler, 'object', {
moduleName: 'workbox-routing',
className: 'Router',
funcName: 'registerRoute',
paramName: 'route'
});
assert_js.assert.hasMethod(route.handler, 'handle', {
moduleName: 'workbox-routing',
className: 'Router',
funcName: 'registerRoute',
paramName: 'route.handler'
});
assert_js.assert.isType(route.method, 'string', {
moduleName: 'workbox-routing',
className: 'Router',
funcName: 'registerRoute',
paramName: 'route.method'
});
}
if (!this._routes.has(route.method)) {
this._routes.set(route.method, []);
} // Give precedence to all of the earlier routes by adding this additional
// route to the end of the array.
this._routes.get(route.method).push(route);
}
/**
* Unregisters a route with the router.
*
* @param {module:workbox-routing.Route} route The route to unregister.
*/
unregisterRoute(route) {
if (!this._routes.has(route.method)) {
throw new WorkboxError_js.WorkboxError('unregister-route-but-not-found-with-method', {
method: route.method
});
}
const routeIndex = this._routes.get(route.method).indexOf(route);
if (routeIndex > -1) {
this._routes.get(route.method).splice(routeIndex, 1);
} else {
throw new WorkboxError_js.WorkboxError('unregister-route-route-not-registered');
}
}
}
/*
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.
*/
let defaultRouter;
/**
* Creates a new, singleton Router instance if one does not exist. If one
* does already exist, that instance is returned.
*
* @private
* @return {Router}
*/
const getOrCreateDefaultRouter = () => {
if (!defaultRouter) {
defaultRouter = new Router(); // The helpers that use the default Router assume these listeners exist.
defaultRouter.addFetchListener();
defaultRouter.addCacheListener();
}
return defaultRouter;
};
/*
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.
*/
/**
* Easily register a RegExp, string, or function with a caching
* strategy to a singleton Router instance.
*
* This method will generate a Route for you if needed and
* call [registerRoute()]{@link module:workbox-routing.Router#registerRoute}.
*
* @param {RegExp|string|module:workbox-routing.Route~matchCallback|module:workbox-routing.Route} capture
* If the capture param is a `Route`, all other arguments will be ignored.
* @param {module:workbox-routing~handlerCallback} [handler] A callback
* function that returns a Promise resulting in a Response. This parameter
* is required if `capture` is not a `Route` object.
* @param {string} [method='GET'] The HTTP method to match the Route
* against.
* @return {module:workbox-routing.Route} The generated `Route`(Useful for
* unregistering).
*
* @memberof module:workbox-routing
*/
function registerRoute(capture, handler, method) {
let route;
if (typeof capture === 'string') {
const captureUrl = new URL(capture, location.href);
{
if (!(capture.startsWith('/') || capture.startsWith('http'))) {
throw new WorkboxError_js.WorkboxError('invalid-string', {
moduleName: 'workbox-routing',
funcName: 'registerRoute',
paramName: 'capture'
});
} // We want to check if Express-style wildcards are in the pathname only.
// TODO: Remove this log message in v4.
const valueToCheck = capture.startsWith('http') ? captureUrl.pathname : capture; // See https://github.com/pillarjs/path-to-regexp#parameters
const wildcards = '[*:?+]';
if (new RegExp(`${wildcards}`).exec(valueToCheck)) {
logger_js.logger.debug(`The '$capture' parameter contains an Express-style wildcard ` + `character (${wildcards}). Strings are now always interpreted as ` + `exact matches; use a RegExp for partial or wildcard matches.`);
}
}
const matchCallback = ({
url
}) => {
{
if (url.pathname === captureUrl.pathname && url.origin !== captureUrl.origin) {
logger_js.logger.debug(`${capture} only partially matches the cross-origin URL ` + `${url}. This route will only handle cross-origin requests ` + `if they match the entire URL.`);
}
}
return url.href === captureUrl.href;
}; // If `capture` is a string then `handler` and `method` must be present.
route = new Route(matchCallback, handler, method);
} else if (capture instanceof RegExp) {
// If `capture` is a `RegExp` then `handler` and `method` must be present.
route = new RegExpRoute(capture, handler, method);
} else if (typeof capture === 'function') {
// If `capture` is a function then `handler` and `method` must be present.
route = new Route(capture, handler, method);
} else if (capture instanceof Route) {
route = capture;
} else {
throw new WorkboxError_js.WorkboxError('unsupported-route-type', {
moduleName: 'workbox-routing',
funcName: 'registerRoute',
paramName: 'capture'
});
}
const defaultRouter = getOrCreateDefaultRouter();
defaultRouter.registerRoute(route);
return route;
}
/*
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.
*/
/**
* If a Route throws an error while handling a request, this `handler`
* will be called and given a chance to provide a response.
*
* @param {module:workbox-routing~handlerCallback} handler A callback
* function that returns a Promise resulting in a Response.
*
* @memberof module:workbox-routing
*/
function setCatchHandler(handler) {
const defaultRouter = getOrCreateDefaultRouter();
defaultRouter.setCatchHandler(handler);
}
/*
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.
*/
/**
* Define a default `handler` that's called when no routes explicitly
* match the incoming request.
*
* Without a default handler, unmatched requests will go against the
* network as if there were no service worker present.
*
* @param {module:workbox-routing~handlerCallback} handler A callback
* function that returns a Promise resulting in a Response.
*
* @memberof module:workbox-routing
*/
function setDefaultHandler(handler) {
const defaultRouter = getOrCreateDefaultRouter();
defaultRouter.setDefaultHandler(handler);
}
exports.NavigationRoute = NavigationRoute;
exports.RegExpRoute = RegExpRoute;
exports.Route = Route;
exports.Router = Router;
exports.registerRoute = registerRoute;
exports.setCatchHandler = setCatchHandler;
exports.setDefaultHandler = setDefaultHandler;
return exports;
}({}, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private));
//# sourceMappingURL=workbox-routing.dev.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-routing.dev.js","sources":["../_version.js","../utils/constants.js","../utils/normalizeHandler.js","../Route.js","../NavigationRoute.js","../RegExpRoute.js","../Router.js","../utils/getOrCreateDefaultRouter.js","../registerRoute.js","../setCatchHandler.js","../setDefaultHandler.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:routing:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * The default HTTP method, 'GET', used when there's no specific method\n * configured for a route.\n *\n * @type {string}\n *\n * @private\n */\nexport const defaultMethod = 'GET';\n/**\n * The list of valid HTTP methods associated with requests that could be routed.\n *\n * @type {Array<string>}\n *\n * @private\n */\nexport const validMethods = [\n 'DELETE',\n 'GET',\n 'HEAD',\n 'PATCH',\n 'POST',\n 'PUT',\n];\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport '../_version.js';\n/**\n * @param {function()|Object} handler Either a function, or an object with a\n * 'handle' method.\n * @return {Object} An object with a handle method.\n *\n * @private\n */\nexport const normalizeHandler = (handler) => {\n if (handler && typeof handler === 'object') {\n if (process.env.NODE_ENV !== 'production') {\n assert.hasMethod(handler, 'handle', {\n moduleName: 'workbox-routing',\n className: 'Route',\n funcName: 'constructor',\n paramName: 'handler',\n });\n }\n return handler;\n }\n else {\n if (process.env.NODE_ENV !== 'production') {\n assert.isType(handler, 'function', {\n moduleName: 'workbox-routing',\n className: 'Route',\n funcName: 'constructor',\n paramName: 'handler',\n });\n }\n return { handle: handler };\n }\n};\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { defaultMethod, validMethods } from './utils/constants.js';\nimport { normalizeHandler } from './utils/normalizeHandler.js';\nimport './_version.js';\n/**\n * A `Route` consists of a pair of callback functions, \"match\" and \"handler\".\n * The \"match\" callback determine if a route should be used to \"handle\" a\n * request by returning a non-falsy value if it can. The \"handler\" callback\n * is called when there is a match and should return a Promise that resolves\n * to a `Response`.\n *\n * @memberof module:workbox-routing\n */\nclass Route {\n /**\n * Constructor for Route class.\n *\n * @param {module:workbox-routing~matchCallback} match\n * A callback function that determines whether the route matches a given\n * `fetch` event by returning a non-falsy value.\n * @param {module:workbox-routing~handlerCallback} handler A callback\n * function that returns a Promise resolving to a Response.\n * @param {string} [method='GET'] The HTTP method to match the Route\n * against.\n */\n constructor(match, handler, method = defaultMethod) {\n if (process.env.NODE_ENV !== 'production') {\n assert.isType(match, 'function', {\n moduleName: 'workbox-routing',\n className: 'Route',\n funcName: 'constructor',\n paramName: 'match',\n });\n if (method) {\n assert.isOneOf(method, validMethods, { paramName: 'method' });\n }\n }\n // These values are referenced directly by Router so cannot be\n // altered by minificaton.\n this.handler = normalizeHandler(handler);\n this.match = match;\n this.method = method;\n }\n}\nexport { Route };\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { Route } from './Route.js';\nimport './_version.js';\n/**\n * NavigationRoute makes it easy to create a\n * [Route]{@link module:workbox-routing.Route} that matches for browser\n * [navigation requests]{@link https://developers.google.com/web/fundamentals/primers/service-workers/high-performance-loading#first_what_are_nLine truncated
@@ -0,0 +1,2 @@
this.workbox=this.workbox||{},this.workbox.routing=function(t,e){"use strict";try{self["workbox:routing:5.1.4"]&&_()}catch(t){}const s=t=>t&&"object"==typeof t?t:{handle:t};class r{constructor(t,e,r="GET"){this.handler=s(e),this.match=t,this.method=r}}class n extends r{constructor(t,e,s){super(({url:e})=>{const s=t.exec(e.href);if(s&&(e.origin===location.origin||0===s.index))return s.slice(1)},e,s)}}class o{constructor(){this.t=new Map}get routes(){return this.t}addFetchListener(){self.addEventListener("fetch",t=>{const{request:e}=t,s=this.handleRequest({request:e,event:t});s&&t.respondWith(s)})}addCacheListener(){self.addEventListener("message",t=>{if(t.data&&"CACHE_URLS"===t.data.type){const{payload:e}=t.data,s=Promise.all(e.urlsToCache.map(t=>{"string"==typeof t&&(t=[t]);const e=new Request(...t);return this.handleRequest({request:e})}));t.waitUntil(s),t.ports&&t.ports[0]&&s.then(()=>t.ports[0].postMessage(!0))}})}handleRequest({request:t,event:e}){const s=new URL(t.url,location.href);if(!s.protocol.startsWith("http"))return;const{params:r,route:n}=this.findMatchingRoute({url:s,request:t,event:e});let o,i=n&&n.handler;if(!i&&this.s&&(i=this.s),i){try{o=i.handle({url:s,request:t,event:e,params:r})}catch(t){o=Promise.reject(t)}return o instanceof Promise&&this.o&&(o=o.catch(r=>this.o.handle({url:s,request:t,event:e}))),o}}findMatchingRoute({url:t,request:e,event:s}){const r=this.t.get(e.method)||[];for(const n of r){let r;const o=n.match({url:t,request:e,event:s});if(o)return r=o,(Array.isArray(o)&&0===o.length||o.constructor===Object&&0===Object.keys(o).length||"boolean"==typeof o)&&(r=void 0),{route:n,params:r}}return{}}setDefaultHandler(t){this.s=s(t)}setCatchHandler(t){this.o=s(t)}registerRoute(t){this.t.has(t.method)||this.t.set(t.method,[]),this.t.get(t.method).push(t)}unregisterRoute(t){if(!this.t.has(t.method))throw new e.WorkboxError("unregister-route-but-not-found-with-method",{method:t.method});const s=this.t.get(t.method).indexOf(t);if(!(s>-1))throw new e.WorkboxError("unregister-route-route-not-registered");this.t.get(t.method).splice(s,1)}}let i;const u=()=>(i||(i=new o,i.addFetchListener(),i.addCacheListener()),i);return t.NavigationRoute=class extends r{constructor(t,{allowlist:e=[/./],denylist:s=[]}={}){super(t=>this.i(t),t),this.u=e,this.h=s}i({url:t,request:e}){if(e&&"navigate"!==e.mode)return!1;const s=t.pathname+t.search;for(const t of this.h)if(t.test(s))return!1;return!!this.u.some(t=>t.test(s))}},t.RegExpRoute=n,t.Route=r,t.Router=o,t.registerRoute=function(t,s,o){let i;if("string"==typeof t){const e=new URL(t,location.href);i=new r(({url:t})=>t.href===e.href,s,o)}else if(t instanceof RegExp)i=new n(t,s,o);else if("function"==typeof t)i=new r(t,s,o);else{if(!(t instanceof r))throw new e.WorkboxError("unsupported-route-type",{moduleName:"workbox-routing",funcName:"registerRoute",paramName:"capture"});i=t}return u().registerRoute(i),i},t.setCatchHandler=function(t){u().setCatchHandler(t)},t.setDefaultHandler=function(t){u().setDefaultHandler(t)},t}({},workbox.core._private);
//# sourceMappingURL=workbox-routing.prod.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-routing.prod.js","sources":["../_version.js","../utils/constants.js","../utils/normalizeHandler.js","../Route.js","../RegExpRoute.js","../Router.js","../utils/getOrCreateDefaultRouter.js","../NavigationRoute.js","../registerRoute.js","../setCatchHandler.js","../setDefaultHandler.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:routing:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * The default HTTP method, 'GET', used when there's no specific method\n * configured for a route.\n *\n * @type {string}\n *\n * @private\n */\nexport const defaultMethod = 'GET';\n/**\n * The list of valid HTTP methods associated with requests that could be routed.\n *\n * @type {Array<string>}\n *\n * @private\n */\nexport const validMethods = [\n 'DELETE',\n 'GET',\n 'HEAD',\n 'PATCH',\n 'POST',\n 'PUT',\n];\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport '../_version.js';\n/**\n * @param {function()|Object} handler Either a function, or an object with a\n * 'handle' method.\n * @return {Object} An object with a handle method.\n *\n * @private\n */\nexport const normalizeHandler = (handler) => {\n if (handler && typeof handler === 'object') {\n if (process.env.NODE_ENV !== 'production') {\n assert.hasMethod(handler, 'handle', {\n moduleName: 'workbox-routing',\n className: 'Route',\n funcName: 'constructor',\n paramName: 'handler',\n });\n }\n return handler;\n }\n else {\n if (process.env.NODE_ENV !== 'production') {\n assert.isType(handler, 'function', {\n moduleName: 'workbox-routing',\n className: 'Route',\n funcName: 'constructor',\n paramName: 'handler',\n });\n }\n return { handle: handler };\n }\n};\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { defaultMethod, validMethods } from './utils/constants.js';\nimport { normalizeHandler } from './utils/normalizeHandler.js';\nimport './_version.js';\n/**\n * A `Route` consists of a pair of callback functions, \"match\" and \"handler\".\n * The \"match\" callback determine if a route should be used to \"handle\" a\n * request by returning a non-falsy value if it can. The \"handler\" callback\n * is called when there is a match and should return a Promise that resolves\n * to a `Response`.\n *\n * @memberof module:workbox-routing\n */\nclass Route {\n /**\n * Constructor for Route class.\n *\n * @param {module:workbox-routing~matchCallback} match\n * A callback function that determines whether the route matches a given\n * `fetch` event by returning a non-falsy value.\n * @param {module:workbox-routing~handlerCallback} handler A callback\n * function that returns a Promise resolving to a Response.\n * @param {string} [method='GET'] The HTTP method to match the Route\n * against.\n */\n constructor(match, handler, method = defaultMethod) {\n if (process.env.NODE_ENV !== 'production') {\n assert.isType(match, 'function', {\n moduleName: 'workbox-routing',\n className: 'Route',\n funcName: 'constructor',\n paramName: 'match',\n });\n if (method) {\n assert.isOneOf(method, validMethods, { paramName: 'method' });\n }\n }\n // These values are referenced directly by Router so cannot be\n // altered by minificaton.\n this.handler = normalizeHandler(handler);\n this.match = match;\n this.method = method;\n }\n}\nexport { Route };\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { Route } from './Route.js';\nimport './_version.js';\n/**\n * RegExpRoute makes it easy to create a regular expression based\n * [Route]{@link module:workbox-routing.Route}.\n *\n * For same-origin requests the RegExp only needs to match part of the URL. For\n * requests against third-party servers, you must define a RLine truncated
@@ -0,0 +1,923 @@
this.workbox = this.workbox || {};
this.workbox.strategies = (function (exports, assert_js, cacheNames_js, cacheWrapper_js, fetchWrapper_js, getFriendlyURL_js, logger_js, WorkboxError_js) {
'use strict';
try {
self['workbox:strategies:5.1.4'] && _();
} catch (e) {}
/*
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 messages = {
strategyStart: (strategyName, request) => `Using ${strategyName} to respond to '${getFriendlyURL_js.getFriendlyURL(request.url)}'`,
printFinalResponse: response => {
if (response) {
logger_js.logger.groupCollapsed(`View the final response here.`);
logger_js.logger.log(response || '[No response returned]');
logger_js.logger.groupEnd();
}
}
};
/*
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.
*/
/**
* An implementation of a [cache-first]{@link https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#cache-falling-back-to-network}
* request strategy.
*
* A cache first strategy is useful for assets that have been revisioned,
* such as URLs like `/styles/example.a8f5f1.css`, since they
* can be cached for long periods of time.
*
* If the network request fails, and there is no cache match, this will throw
* a `WorkboxError` exception.
*
* @memberof module:workbox-strategies
*/
class CacheFirst {
/**
* @param {Object} options
* @param {string} options.cacheName Cache name to store and retrieve
* requests. Defaults to cache names provided by
* [workbox-core]{@link module:workbox-core.cacheNames}.
* @param {Array<Object>} options.plugins [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}
* to use in conjunction with this caching strategy.
* @param {Object} options.fetchOptions Values passed along to the
* [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters)
* of all fetch() requests made by this strategy.
* @param {Object} options.matchOptions [`CacheQueryOptions`](https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions)
*/
constructor(options = {}) {
this._cacheName = cacheNames_js.cacheNames.getRuntimeName(options.cacheName);
this._plugins = options.plugins || [];
this._fetchOptions = options.fetchOptions;
this._matchOptions = options.matchOptions;
}
/**
* This method will perform a request strategy and follows an API that
* will work with the
* [Workbox Router]{@link module:workbox-routing.Router}.
*
* @param {Object} options
* @param {Request|string} options.request A request to run this strategy for.
* @param {Event} [options.event] The event that triggered the request.
* @return {Promise<Response>}
*/
async handle({
event,
request
}) {
const logs = [];
if (typeof request === 'string') {
request = new Request(request);
}
{
assert_js.assert.isInstance(request, Request, {
moduleName: 'workbox-strategies',
className: 'CacheFirst',
funcName: 'makeRequest',
paramName: 'request'
});
}
let response = await cacheWrapper_js.cacheWrapper.match({
cacheName: this._cacheName,
request,
event,
matchOptions: this._matchOptions,
plugins: this._plugins
});
let error;
if (!response) {
{
logs.push(`No response found in the '${this._cacheName}' cache. ` + `Will respond with a network request.`);
}
try {
response = await this._getFromNetwork(request, event);
} catch (err) {
error = err;
}
{
if (response) {
logs.push(`Got response from network.`);
} else {
logs.push(`Unable to get a response from the network.`);
}
}
} else {
{
logs.push(`Found a cached response in the '${this._cacheName}' cache.`);
}
}
{
logger_js.logger.groupCollapsed(messages.strategyStart('CacheFirst', request));
for (const log of logs) {
logger_js.logger.log(log);
}
messages.printFinalResponse(response);
logger_js.logger.groupEnd();
}
if (!response) {
throw new WorkboxError_js.WorkboxError('no-response', {
url: request.url,
error
});
}
return response;
}
/**
* Handles the network and cache part of CacheFirst.
*
* @param {Request} request
* @param {Event} [event]
* @return {Promise<Response>}
*
* @private
*/
async _getFromNetwork(request, event) {
const response = await fetchWrapper_js.fetchWrapper.fetch({
request,
event,
fetchOptions: this._fetchOptions,
plugins: this._plugins
}); // Keep the service worker while we put the request to the cache
const responseClone = response.clone();
const cachePutPromise = cacheWrapper_js.cacheWrapper.put({
cacheName: this._cacheName,
request,
response: responseClone,
event,
plugins: this._plugins
});
if (event) {
try {
event.waitUntil(cachePutPromise);
} catch (error) {
{
logger_js.logger.warn(`Unable to ensure service worker stays alive when ` + `updating cache for '${getFriendlyURL_js.getFriendlyURL(request.url)}'.`);
}
}
}
return response;
}
}
/*
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.
*/
/**
* An implementation of a
* [cache-only]{@link https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#cache-only}
* request strategy.
*
* This class is useful if you want to take advantage of any
* [Workbox plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}.
*
* If there is no cache match, this will throw a `WorkboxError` exception.
*
* @memberof module:workbox-strategies
*/
class CacheOnly {
/**
* @param {Object} options
* @param {string} options.cacheName Cache name to store and retrieve
* requests. Defaults to cache names provided by
* [workbox-core]{@link module:workbox-core.cacheNames}.
* @param {Array<Object>} options.plugins [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}
* to use in conjunction with this caching strategy.
* @param {Object} options.matchOptions [`CacheQueryOptions`](https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions)
*/
constructor(options = {}) {
this._cacheName = cacheNames_js.cacheNames.getRuntimeName(options.cacheName);
this._plugins = options.plugins || [];
this._matchOptions = options.matchOptions;
}
/**
* This method will perform a request strategy and follows an API that
* will work with the
* [Workbox Router]{@link module:workbox-routing.Router}.
*
* @param {Object} options
* @param {Request|string} options.request A request to run this strategy for.
* @param {Event} [options.event] The event that triggered the request.
* @return {Promise<Response>}
*/
async handle({
event,
request
}) {
if (typeof request === 'string') {
request = new Request(request);
}
{
assert_js.assert.isInstance(request, Request, {
moduleName: 'workbox-strategies',
className: 'CacheOnly',
funcName: 'makeRequest',
paramName: 'request'
});
}
const response = await cacheWrapper_js.cacheWrapper.match({
cacheName: this._cacheName,
request,
event,
matchOptions: this._matchOptions,
plugins: this._plugins
});
{
logger_js.logger.groupCollapsed(messages.strategyStart('CacheOnly', request));
if (response) {
logger_js.logger.log(`Found a cached response in the '${this._cacheName}'` + ` cache.`);
messages.printFinalResponse(response);
} else {
logger_js.logger.log(`No response found in the '${this._cacheName}' cache.`);
}
logger_js.logger.groupEnd();
}
if (!response) {
throw new WorkboxError_js.WorkboxError('no-response', {
url: request.url
});
}
return response;
}
}
/*
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 cacheOkAndOpaquePlugin = {
/**
* Returns a valid response (to allow caching) if the status is 200 (OK) or
* 0 (opaque).
*
* @param {Object} options
* @param {Response} options.response
* @return {Response|null}
*
* @private
*/
cacheWillUpdate: async ({
response
}) => {
if (response.status === 200 || response.status === 0) {
return response;
}
return null;
}
};
/*
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.
*/
/**
* An implementation of a
* [network first]{@link https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#network-falling-back-to-cache}
* request strategy.
*
* By default, this strategy will cache responses with a 200 status code as
* well as [opaque responses]{@link https://developers.google.com/web/tools/workbox/guides/handle-third-party-requests}.
* Opaque responses are are cross-origin requests where the response doesn't
* support [CORS]{@link https://enable-cors.org/}.
*
* If the network request fails, and there is no cache match, this will throw
* a `WorkboxError` exception.
*
* @memberof module:workbox-strategies
*/
class NetworkFirst {
/**
* @param {Object} options
* @param {string} options.cacheName Cache name to store and retrieve
* requests. Defaults to cache names provided by
* [workbox-core]{@link module:workbox-core.cacheNames}.
* @param {Array<Object>} options.plugins [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}
* to use in conjunction with this caching strategy.
* @param {Object} options.fetchOptions Values passed along to the
* [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters)
* of all fetch() requests made by this strategy.
* @param {Object} options.matchOptions [`CacheQueryOptions`](https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions)
* @param {number} options.networkTimeoutSeconds If set, any network requests
* that fail to respond within the timeout will fallback to the cache.
*
* This option can be used to combat
* "[lie-fi]{@link https://developers.google.com/web/fundamentals/performance/poor-connectivity/#lie-fi}"
* scenarios.
*/
constructor(options = {}) {
this._cacheName = cacheNames_js.cacheNames.getRuntimeName(options.cacheName);
if (options.plugins) {
const isUsingCacheWillUpdate = options.plugins.some(plugin => !!plugin.cacheWillUpdate);
this._plugins = isUsingCacheWillUpdate ? options.plugins : [cacheOkAndOpaquePlugin, ...options.plugins];
} else {
// No plugins passed in, use the default plugin.
this._plugins = [cacheOkAndOpaquePlugin];
}
this._networkTimeoutSeconds = options.networkTimeoutSeconds || 0;
{
if (this._networkTimeoutSeconds) {
assert_js.assert.isType(this._networkTimeoutSeconds, 'number', {
moduleName: 'workbox-strategies',
className: 'NetworkFirst',
funcName: 'constructor',
paramName: 'networkTimeoutSeconds'
});
}
}
this._fetchOptions = options.fetchOptions;
this._matchOptions = options.matchOptions;
}
/**
* This method will perform a request strategy and follows an API that
* will work with the
* [Workbox Router]{@link module:workbox-routing.Router}.
*
* @param {Object} options
* @param {Request|string} options.request A request to run this strategy for.
* @param {Event} [options.event] The event that triggered the request.
* @return {Promise<Response>}
*/
async handle({
event,
request
}) {
const logs = [];
if (typeof request === 'string') {
request = new Request(request);
}
{
assert_js.assert.isInstance(request, Request, {
moduleName: 'workbox-strategies',
className: 'NetworkFirst',
funcName: 'handle',
paramName: 'makeRequest'
});
}
const promises = [];
let timeoutId;
if (this._networkTimeoutSeconds) {
const {
id,
promise
} = this._getTimeoutPromise({
request,
event,
logs
});
timeoutId = id;
promises.push(promise);
}
const networkPromise = this._getNetworkPromise({
timeoutId,
request,
event,
logs
});
promises.push(networkPromise); // Promise.race() will resolve as soon as the first promise resolves.
let response = await Promise.race(promises); // If Promise.race() resolved with null, it might be due to a network
// timeout + a cache miss. If that were to happen, we'd rather wait until
// the networkPromise resolves instead of returning null.
// Note that it's fine to await an already-resolved promise, so we don't
// have to check to see if it's still "in flight".
if (!response) {
response = await networkPromise;
}
{
logger_js.logger.groupCollapsed(messages.strategyStart('NetworkFirst', request));
for (const log of logs) {
logger_js.logger.log(log);
}
messages.printFinalResponse(response);
logger_js.logger.groupEnd();
}
if (!response) {
throw new WorkboxError_js.WorkboxError('no-response', {
url: request.url
});
}
return response;
}
/**
* @param {Object} options
* @param {Request} options.request
* @param {Array} options.logs A reference to the logs array
* @param {Event} [options.event]
* @return {Promise<Response>}
*
* @private
*/
_getTimeoutPromise({
request,
logs,
event
}) {
let timeoutId;
const timeoutPromise = new Promise(resolve => {
const onNetworkTimeout = async () => {
{
logs.push(`Timing out the network response at ` + `${this._networkTimeoutSeconds} seconds.`);
}
resolve(await this._respondFromCache({
request,
event
}));
};
timeoutId = setTimeout(onNetworkTimeout, this._networkTimeoutSeconds * 1000);
});
return {
promise: timeoutPromise,
id: timeoutId
};
}
/**
* @param {Object} options
* @param {number|undefined} options.timeoutId
* @param {Request} options.request
* @param {Array} options.logs A reference to the logs Array.
* @param {Event} [options.event]
* @return {Promise<Response>}
*
* @private
*/
async _getNetworkPromise({
timeoutId,
request,
logs,
event
}) {
let error;
let response;
try {
response = await fetchWrapper_js.fetchWrapper.fetch({
request,
event,
fetchOptions: this._fetchOptions,
plugins: this._plugins
});
} catch (err) {
error = err;
}
if (timeoutId) {
clearTimeout(timeoutId);
}
{
if (response) {
logs.push(`Got response from network.`);
} else {
logs.push(`Unable to get a response from the network. Will respond ` + `with a cached response.`);
}
}
if (error || !response) {
response = await this._respondFromCache({
request,
event
});
{
if (response) {
logs.push(`Found a cached response in the '${this._cacheName}'` + ` cache.`);
} else {
logs.push(`No response found in the '${this._cacheName}' cache.`);
}
}
} else {
// Keep the service worker alive while we put the request in the cache
const responseClone = response.clone();
const cachePut = cacheWrapper_js.cacheWrapper.put({
cacheName: this._cacheName,
request,
response: responseClone,
event,
plugins: this._plugins
});
if (event) {
try {
// The event has been responded to so we can keep the SW alive to
// respond to the request
event.waitUntil(cachePut);
} catch (err) {
{
logger_js.logger.warn(`Unable to ensure service worker stays alive when ` + `updating cache for '${getFriendlyURL_js.getFriendlyURL(request.url)}'.`);
}
}
}
}
return response;
}
/**
* Used if the network timeouts or fails to make the request.
*
* @param {Object} options
* @param {Request} request The request to match in the cache
* @param {Event} [options.event]
* @return {Promise<Object>}
*
* @private
*/
_respondFromCache({
event,
request
}) {
return cacheWrapper_js.cacheWrapper.match({
cacheName: this._cacheName,
request,
event,
matchOptions: this._matchOptions,
plugins: this._plugins
});
}
}
/*
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.
*/
/**
* An implementation of a
* [network-only]{@link https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#network-only}
* request strategy.
*
* This class is useful if you want to take advantage of any
* [Workbox plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}.
*
* If the network request fails, this will throw a `WorkboxError` exception.
*
* @memberof module:workbox-strategies
*/
class NetworkOnly {
/**
* @param {Object} options
* @param {string} options.cacheName Cache name to store and retrieve
* requests. Defaults to cache names provided by
* [workbox-core]{@link module:workbox-core.cacheNames}.
* @param {Array<Object>} options.plugins [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}
* to use in conjunction with this caching strategy.
* @param {Object} options.fetchOptions Values passed along to the
* [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters)
* of all fetch() requests made by this strategy.
*/
constructor(options = {}) {
this._plugins = options.plugins || [];
this._fetchOptions = options.fetchOptions;
}
/**
* This method will perform a request strategy and follows an API that
* will work with the
* [Workbox Router]{@link module:workbox-routing.Router}.
*
* @param {Object} options
* @param {Request|string} options.request The request to run this strategy for.
* @param {Event} [options.event] The event that triggered the request.
* @return {Promise<Response>}
*/
async handle({
event,
request
}) {
if (typeof request === 'string') {
request = new Request(request);
}
{
assert_js.assert.isInstance(request, Request, {
moduleName: 'workbox-strategies',
className: 'NetworkOnly',
funcName: 'handle',
paramName: 'request'
});
}
let error;
let response;
try {
response = await fetchWrapper_js.fetchWrapper.fetch({
request,
event,
fetchOptions: this._fetchOptions,
plugins: this._plugins
});
} catch (err) {
error = err;
}
{
logger_js.logger.groupCollapsed(messages.strategyStart('NetworkOnly', request));
if (response) {
logger_js.logger.log(`Got response from network.`);
} else {
logger_js.logger.log(`Unable to get a response from the network.`);
}
messages.printFinalResponse(response);
logger_js.logger.groupEnd();
}
if (!response) {
throw new WorkboxError_js.WorkboxError('no-response', {
url: request.url,
error
});
}
return response;
}
}
/*
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.
*/
/**
* An implementation of a
* [stale-while-revalidate]{@link https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#stale-while-revalidate}
* request strategy.
*
* Resources are requested from both the cache and the network in parallel.
* The strategy will respond with the cached version if available, otherwise
* wait for the network response. The cache is updated with the network response
* with each successful request.
*
* By default, this strategy will cache responses with a 200 status code as
* well as [opaque responses]{@link https://developers.google.com/web/tools/workbox/guides/handle-third-party-requests}.
* Opaque responses are cross-origin requests where the response doesn't
* support [CORS]{@link https://enable-cors.org/}.
*
* If the network request fails, and there is no cache match, this will throw
* a `WorkboxError` exception.
*
* @memberof module:workbox-strategies
*/
class StaleWhileRevalidate {
/**
* @param {Object} options
* @param {string} options.cacheName Cache name to store and retrieve
* requests. Defaults to cache names provided by
* [workbox-core]{@link module:workbox-core.cacheNames}.
* @param {Array<Object>} options.plugins [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}
* to use in conjunction with this caching strategy.
* @param {Object} options.fetchOptions Values passed along to the
* [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters)
* of all fetch() requests made by this strategy.
* @param {Object} options.matchOptions [`CacheQueryOptions`](https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions)
*/
constructor(options = {}) {
this._cacheName = cacheNames_js.cacheNames.getRuntimeName(options.cacheName);
this._plugins = options.plugins || [];
if (options.plugins) {
const isUsingCacheWillUpdate = options.plugins.some(plugin => !!plugin.cacheWillUpdate);
this._plugins = isUsingCacheWillUpdate ? options.plugins : [cacheOkAndOpaquePlugin, ...options.plugins];
} else {
// No plugins passed in, use the default plugin.
this._plugins = [cacheOkAndOpaquePlugin];
}
this._fetchOptions = options.fetchOptions;
this._matchOptions = options.matchOptions;
}
/**
* This method will perform a request strategy and follows an API that
* will work with the
* [Workbox Router]{@link module:workbox-routing.Router}.
*
* @param {Object} options
* @param {Request|string} options.request A request to run this strategy for.
* @param {Event} [options.event] The event that triggered the request.
* @return {Promise<Response>}
*/
async handle({
event,
request
}) {
const logs = [];
if (typeof request === 'string') {
request = new Request(request);
}
{
assert_js.assert.isInstance(request, Request, {
moduleName: 'workbox-strategies',
className: 'StaleWhileRevalidate',
funcName: 'handle',
paramName: 'request'
});
}
const fetchAndCachePromise = this._getFromNetwork({
request,
event
});
let response = await cacheWrapper_js.cacheWrapper.match({
cacheName: this._cacheName,
request,
event,
matchOptions: this._matchOptions,
plugins: this._plugins
});
let error;
if (response) {
{
logs.push(`Found a cached response in the '${this._cacheName}'` + ` cache. Will update with the network response in the background.`);
}
if (event) {
try {
event.waitUntil(fetchAndCachePromise);
} catch (error) {
{
logger_js.logger.warn(`Unable to ensure service worker stays alive when ` + `updating cache for '${getFriendlyURL_js.getFriendlyURL(request.url)}'.`);
}
}
}
} else {
{
logs.push(`No response found in the '${this._cacheName}' cache. ` + `Will wait for the network response.`);
}
try {
response = await fetchAndCachePromise;
} catch (err) {
error = err;
}
}
{
logger_js.logger.groupCollapsed(messages.strategyStart('StaleWhileRevalidate', request));
for (const log of logs) {
logger_js.logger.log(log);
}
messages.printFinalResponse(response);
logger_js.logger.groupEnd();
}
if (!response) {
throw new WorkboxError_js.WorkboxError('no-response', {
url: request.url,
error
});
}
return response;
}
/**
* @param {Object} options
* @param {Request} options.request
* @param {Event} [options.event]
* @return {Promise<Response>}
*
* @private
*/
async _getFromNetwork({
request,
event
}) {
const response = await fetchWrapper_js.fetchWrapper.fetch({
request,
event,
fetchOptions: this._fetchOptions,
plugins: this._plugins
});
const cachePutPromise = cacheWrapper_js.cacheWrapper.put({
cacheName: this._cacheName,
request,
response: response.clone(),
event,
plugins: this._plugins
});
if (event) {
try {
event.waitUntil(cachePutPromise);
} catch (error) {
{
logger_js.logger.warn(`Unable to ensure service worker stays alive when ` + `updating cache for '${getFriendlyURL_js.getFriendlyURL(request.url)}'.`);
}
}
}
return response;
}
}
exports.CacheFirst = CacheFirst;
exports.CacheOnly = CacheOnly;
exports.NetworkFirst = NetworkFirst;
exports.NetworkOnly = NetworkOnly;
exports.StaleWhileRevalidate = StaleWhileRevalidate;
return exports;
}({}, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private));
//# sourceMappingURL=workbox-strategies.dev.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-strategies.dev.js","sources":["../_version.js","../utils/messages.js","../CacheFirst.js","../CacheOnly.js","../plugins/cacheOkAndOpaquePlugin.js","../NetworkFirst.js","../NetworkOnly.js","../StaleWhileRevalidate.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:strategies:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { getFriendlyURL } from 'workbox-core/_private/getFriendlyURL.js';\nimport '../_version.js';\nexport const messages = {\n strategyStart: (strategyName, request) => `Using ${strategyName} to respond to '${getFriendlyURL(request.url)}'`,\n printFinalResponse: (response) => {\n if (response) {\n logger.groupCollapsed(`View the final response here.`);\n logger.log(response || '[No response returned]');\n logger.groupEnd();\n }\n },\n};\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { cacheNames } from 'workbox-core/_private/cacheNames.js';\nimport { cacheWrapper } from 'workbox-core/_private/cacheWrapper.js';\nimport { fetchWrapper } from 'workbox-core/_private/fetchWrapper.js';\nimport { getFriendlyURL } from 'workbox-core/_private/getFriendlyURL.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport { messages } from './utils/messages.js';\nimport './_version.js';\n/**\n * An implementation of a [cache-first]{@link https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#cache-falling-back-to-network}\n * request strategy.\n *\n * A cache first strategy is useful for assets that have been revisioned,\n * such as URLs like `/styles/example.a8f5f1.css`, since they\n * can be cached for long periods of time.\n *\n * If the network request fails, and there is no cache match, this will throw\n * a `WorkboxError` exception.\n *\n * @memberof module:workbox-strategies\n */\nclass CacheFirst {\n /**\n * @param {Object} options\n * @param {string} options.cacheName Cache name to store and retrieve\n * requests. Defaults to cache names provided by\n * [workbox-core]{@link module:workbox-core.cacheNames}.\n * @param {Array<Object>} options.plugins [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}\n * to use in conjunction with this caching strategy.\n * @param {Object} options.fetchOptions Values passed along to the\n * [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters)\n * of all fetch() requests made by this strategy.\n * @param {Object} options.matchOptions [`CacheQueryOptions`](https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions)\n */\n constructor(options = {}) {\n this._cacheName = cacheNames.getRuntimeName(options.cacheName);\n this._plugins = options.plugins || [];\n this._fetchOptions = options.fetchOptions;\n this._matchOptions = options.matchOptions;\n }\n /**\n * This method will perform a request strategy and follows an API that\n * will work with the\n * [Workbox Router]{@link module:workbox-routing.Router}.\n *\n * @param {Object} options\n * @param {Request|string} options.request A request to run this strategy for.\n * @param {Event} [options.event] The event that triggered the request.\n * @return {Promise<Response>}\n */\n async handle({ event, request }) {\n const logs = [];\n if (typeof request === 'string') {\n request = new Request(request);\n }\n if (process.env.NODE_ENV !== 'production') {\n assert.isInstance(request, Request, {\n moduleName: 'workbox-strategies',\n className: 'CacheFirst',\n funcName: 'makeRequest',\n paramName: 'request',\n });\n }\n let response = await cacheWrapper.match({\n cacheName: this._cacheName,\n request,\n event,\n matchOptions: this._matchOptions,\n plugins: this._plugins,\n });\n let error;\n if (!response) {\n if (process.env.NODE_ENV !== 'production') {\n logs.push(`No response found in the '${this._cacheName}' cache. ` +\n `Will respond with a network request.`);\n }\n try {\n response = await this._getFromNetwork(request, event);\n }\n catch (Line truncated
@@ -0,0 +1,2 @@
this.workbox=this.workbox||{},this.workbox.strategies=function(t,e,s,i,n){"use strict";try{self["workbox:strategies:5.1.4"]&&_()}catch(t){}const r={cacheWillUpdate:async({response:t})=>200===t.status||0===t.status?t:null};return t.CacheFirst=class{constructor(t={}){this.t=e.cacheNames.getRuntimeName(t.cacheName),this.s=t.plugins||[],this.i=t.fetchOptions,this.h=t.matchOptions}async handle({event:t,request:e}){"string"==typeof e&&(e=new Request(e));let i,r=await s.cacheWrapper.match({cacheName:this.t,request:e,event:t,matchOptions:this.h,plugins:this.s});if(!r)try{r=await this.o(e,t)}catch(t){i=t}if(!r)throw new n.WorkboxError("no-response",{url:e.url,error:i});return r}async o(t,e){const n=await i.fetchWrapper.fetch({request:t,event:e,fetchOptions:this.i,plugins:this.s}),r=n.clone(),h=s.cacheWrapper.put({cacheName:this.t,request:t,response:r,event:e,plugins:this.s});if(e)try{e.waitUntil(h)}catch(t){}return n}},t.CacheOnly=class{constructor(t={}){this.t=e.cacheNames.getRuntimeName(t.cacheName),this.s=t.plugins||[],this.h=t.matchOptions}async handle({event:t,request:e}){"string"==typeof e&&(e=new Request(e));const i=await s.cacheWrapper.match({cacheName:this.t,request:e,event:t,matchOptions:this.h,plugins:this.s});if(!i)throw new n.WorkboxError("no-response",{url:e.url});return i}},t.NetworkFirst=class{constructor(t={}){if(this.t=e.cacheNames.getRuntimeName(t.cacheName),t.plugins){const e=t.plugins.some(t=>!!t.cacheWillUpdate);this.s=e?t.plugins:[r,...t.plugins]}else this.s=[r];this.u=t.networkTimeoutSeconds||0,this.i=t.fetchOptions,this.h=t.matchOptions}async handle({event:t,request:e}){const s=[];"string"==typeof e&&(e=new Request(e));const i=[];let r;if(this.u){const{id:n,promise:h}=this.l({request:e,event:t,logs:s});r=n,i.push(h)}const h=this.p({timeoutId:r,request:e,event:t,logs:s});i.push(h);let o=await Promise.race(i);if(o||(o=await h),!o)throw new n.WorkboxError("no-response",{url:e.url});return o}l({request:t,logs:e,event:s}){let i;return{promise:new Promise(e=>{i=setTimeout(async()=>{e(await this.q({request:t,event:s}))},1e3*this.u)}),id:i}}async p({timeoutId:t,request:e,logs:n,event:r}){let h,o;try{o=await i.fetchWrapper.fetch({request:e,event:r,fetchOptions:this.i,plugins:this.s})}catch(t){h=t}if(t&&clearTimeout(t),h||!o)o=await this.q({request:e,event:r});else{const t=o.clone(),i=s.cacheWrapper.put({cacheName:this.t,request:e,response:t,event:r,plugins:this.s});if(r)try{r.waitUntil(i)}catch(t){}}return o}q({event:t,request:e}){return s.cacheWrapper.match({cacheName:this.t,request:e,event:t,matchOptions:this.h,plugins:this.s})}},t.NetworkOnly=class{constructor(t={}){this.s=t.plugins||[],this.i=t.fetchOptions}async handle({event:t,request:e}){let s,r;"string"==typeof e&&(e=new Request(e));try{r=await i.fetchWrapper.fetch({request:e,event:t,fetchOptions:this.i,plugins:this.s})}catch(t){s=t}if(!r)throw new n.WorkboxError("no-response",{url:e.url,error:s});return r}},t.StaleWhileRevalidate=class{constructor(t={}){if(this.t=e.cacheNames.getRuntimeName(t.cacheName),this.s=t.plugins||[],t.plugins){const e=t.plugins.some(t=>!!t.cacheWillUpdate);this.s=e?t.plugins:[r,...t.plugins]}else this.s=[r];this.i=t.fetchOptions,this.h=t.matchOptions}async handle({event:t,request:e}){"string"==typeof e&&(e=new Request(e));const i=this.o({request:e,event:t});let r,h=await s.cacheWrapper.match({cacheName:this.t,request:e,event:t,matchOptions:this.h,plugins:this.s});if(h){if(t)try{t.waitUntil(i)}catch(r){}}else try{h=await i}catch(t){r=t}if(!h)throw new n.WorkboxError("no-response",{url:e.url,error:r});return h}async o({request:t,event:e}){const n=await i.fetchWrapper.fetch({request:t,event:e,fetchOptions:this.i,plugins:this.s}),r=s.cacheWrapper.put({cacheName:this.t,request:t,response:n.clone(),event:e,plugins:this.s});if(e)try{e.waitUntil(r)}catch(t){}return n}},t}({},workbox.core._private,workbox.core._private,workbox.core._private,workbox.core._private);
//# sourceMappingURL=workbox-strategies.prod.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-strategies.prod.js","sources":["../_version.js","../plugins/cacheOkAndOpaquePlugin.js","../CacheFirst.js","../CacheOnly.js","../NetworkFirst.js","../NetworkOnly.js","../StaleWhileRevalidate.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:strategies:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\nexport const cacheOkAndOpaquePlugin = {\n /**\n * Returns a valid response (to allow caching) if the status is 200 (OK) or\n * 0 (opaque).\n *\n * @param {Object} options\n * @param {Response} options.response\n * @return {Response|null}\n *\n * @private\n */\n cacheWillUpdate: async ({ response }) => {\n if (response.status === 200 || response.status === 0) {\n return response;\n }\n return null;\n },\n};\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { cacheNames } from 'workbox-core/_private/cacheNames.js';\nimport { cacheWrapper } from 'workbox-core/_private/cacheWrapper.js';\nimport { fetchWrapper } from 'workbox-core/_private/fetchWrapper.js';\nimport { getFriendlyURL } from 'workbox-core/_private/getFriendlyURL.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';\nimport { messages } from './utils/messages.js';\nimport './_version.js';\n/**\n * An implementation of a [cache-first]{@link https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#cache-falling-back-to-network}\n * request strategy.\n *\n * A cache first strategy is useful for assets that have been revisioned,\n * such as URLs like `/styles/example.a8f5f1.css`, since they\n * can be cached for long periods of time.\n *\n * If the network request fails, and there is no cache match, this will throw\n * a `WorkboxError` exception.\n *\n * @memberof module:workbox-strategies\n */\nclass CacheFirst {\n /**\n * @param {Object} options\n * @param {string} options.cacheName Cache name to store and retrieve\n * requests. Defaults to cache names provided by\n * [workbox-core]{@link module:workbox-core.cacheNames}.\n * @param {Array<Object>} options.plugins [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}\n * to use in conjunction with this caching strategy.\n * @param {Object} options.fetchOptions Values passed along to the\n * [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters)\n * of all fetch() requests made by this strategy.\n * @param {Object} options.matchOptions [`CacheQueryOptions`](https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions)\n */\n constructor(options = {}) {\n this._cacheName = cacheNames.getRuntimeName(options.cacheName);\n this._plugins = options.plugins || [];\n this._fetchOptions = options.fetchOptions;\n this._matchOptions = options.matchOptions;\n }\n /**\n * This method will perform a request strategy and follows an API that\n * will work with the\n * [Workbox Router]{@link module:workbox-routing.Router}.\n *\n * @param {Object} options\n * @param {Request|string} options.request A request to run this strategy for.\n * @param {Event} [options.event] The event that triggered the request.\n * @return {Promise<Response>}\n */\n async handle({ event, request }) {\n const logs = [];\n if (typeof request === 'string') {\n request = new Request(request);\n }\n if (process.env.NODE_ENV !== 'production') {\n assert.isInstance(request, Request, {\n moduleName: 'workbox-strategies',\n className: 'CacheFirst',\n funcName: 'makeRequest',\n paramName: 'request',\n });\n }\n let response = await cacheWrapper.match({\n cacheName: this._cacheName,\n request,\n event,\n matchOptions: this._matchOptions,\n plugins: this._plugins,\n });\n let error;\n if (!response) {\n if (process.env.NODE_ENV !== 'production') {\n logs.push(`No response found in the '${this._cacheName}' cache. ` +\n `Will respond with a network request.`);\n }\n try {\n response = await this._getFromNetwork(request, event);\n }\n catch (err) {\n error = err;\n }\n ifLine truncated
@@ -0,0 +1,318 @@
this.workbox = this.workbox || {};
this.workbox.streams = (function (exports, logger_js, assert_js, Deferred_js, canConstructReadableStream_js) {
'use strict';
try {
self['workbox:streams:5.1.4'] && _();
} catch (e) {}
/*
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.
*/
/**
* Takes either a Response, a ReadableStream, or a
* [BodyInit](https://fetch.spec.whatwg.org/#bodyinit) and returns the
* ReadableStreamReader object associated with it.
*
* @param {module:workbox-streams.StreamSource} source
* @return {ReadableStreamReader}
* @private
*/
function _getReaderFromSource(source) {
if (source instanceof Response) {
return source.body.getReader();
}
if (source instanceof ReadableStream) {
return source.getReader();
}
return new Response(source).body.getReader();
}
/**
* Takes multiple source Promises, each of which could resolve to a Response, a
* ReadableStream, or a [BodyInit](https://fetch.spec.whatwg.org/#bodyinit).
*
* Returns an object exposing a ReadableStream with each individual stream's
* data returned in sequence, along with a Promise which signals when the
* stream is finished (useful for passing to a FetchEvent's waitUntil()).
*
* @param {Array<Promise<module:workbox-streams.StreamSource>>} sourcePromises
* @return {Object<{done: Promise, stream: ReadableStream}>}
*
* @memberof module:workbox-streams
*/
function concatenate(sourcePromises) {
{
assert_js.assert.isArray(sourcePromises, {
moduleName: 'workbox-streams',
funcName: 'concatenate',
paramName: 'sourcePromises'
});
}
const readerPromises = sourcePromises.map(sourcePromise => {
return Promise.resolve(sourcePromise).then(source => {
return _getReaderFromSource(source);
});
});
const streamDeferred = new Deferred_js.Deferred();
let i = 0;
const logMessages = [];
const stream = new ReadableStream({
pull(controller) {
return readerPromises[i].then(reader => reader.read()).then(result => {
if (result.done) {
{
logMessages.push(['Reached the end of source:', sourcePromises[i]]);
}
i++;
if (i >= readerPromises.length) {
// Log all the messages in the group at once in a single group.
{
logger_js.logger.groupCollapsed(`Concatenating ${readerPromises.length} sources.`);
for (const message of logMessages) {
if (Array.isArray(message)) {
logger_js.logger.log(...message);
} else {
logger_js.logger.log(message);
}
}
logger_js.logger.log('Finished reading all sources.');
logger_js.logger.groupEnd();
}
controller.close();
streamDeferred.resolve();
return;
} // The `pull` method is defined because we're inside it.
return this.pull(controller);
} else {
controller.enqueue(result.value);
}
}).catch(error => {
{
logger_js.logger.error('An error occurred:', error);
}
streamDeferred.reject(error);
throw error;
});
},
cancel() {
{
logger_js.logger.warn('The ReadableStream was cancelled.');
}
streamDeferred.resolve();
}
});
return {
done: streamDeferred.promise,
stream
};
}
/*
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 is a utility method that determines whether the current browser supports
* the features required to create streamed responses. Currently, it checks if
* [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/ReadableStream)
* is available.
*
* @private
* @param {HeadersInit} [headersInit] If there's no `Content-Type` specified,
* `'text/html'` will be used by default.
* @return {boolean} `true`, if the current browser meets the requirements for
* streaming responses, and `false` otherwise.
*
* @memberof module:workbox-streams
*/
function createHeaders(headersInit = {}) {
// See https://github.com/GoogleChrome/workbox/issues/1461
const headers = new Headers(headersInit);
if (!headers.has('content-type')) {
headers.set('content-type', 'text/html');
}
return headers;
}
/*
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.
*/
/**
* Takes multiple source Promises, each of which could resolve to a Response, a
* ReadableStream, or a [BodyInit](https://fetch.spec.whatwg.org/#bodyinit),
* along with a
* [HeadersInit](https://fetch.spec.whatwg.org/#typedefdef-headersinit).
*
* Returns an object exposing a Response whose body consists of each individual
* stream's data returned in sequence, along with a Promise which signals when
* the stream is finished (useful for passing to a FetchEvent's waitUntil()).
*
* @param {Array<Promise<module:workbox-streams.StreamSource>>} sourcePromises
* @param {HeadersInit} [headersInit] If there's no `Content-Type` specified,
* `'text/html'` will be used by default.
* @return {Object<{done: Promise, response: Response}>}
*
* @memberof module:workbox-streams
*/
function concatenateToResponse(sourcePromises, headersInit) {
const {
done,
stream
} = concatenate(sourcePromises);
const headers = createHeaders(headersInit);
const response = new Response(stream, {
headers
});
return {
done,
response
};
}
/*
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 is a utility method that determines whether the current browser supports
* the features required to create streamed responses. Currently, it checks if
* [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/ReadableStream)
* can be created.
*
* @return {boolean} `true`, if the current browser meets the requirements for
* streaming responses, and `false` otherwise.
*
* @memberof module:workbox-streams
*/
function isSupported() {
return canConstructReadableStream_js.canConstructReadableStream();
}
/*
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.
*/
/**
* A shortcut to create a strategy that could be dropped-in to Workbox's router.
*
* On browsers that do not support constructing new `ReadableStream`s, this
* strategy will automatically wait for all the `sourceFunctions` to complete,
* and create a final response that concatenates their values together.
*
* @param {Array<function({event, request, url, params})>} sourceFunctions
* An array of functions similar to {@link module:workbox-routing~handlerCallback}
* but that instead return a {@link module:workbox-streams.StreamSource} (or a
* Promise which resolves to one).
* @param {HeadersInit} [headersInit] If there's no `Content-Type` specified,
* `'text/html'` will be used by default.
* @return {module:workbox-routing~handlerCallback}
* @memberof module:workbox-streams
*/
function strategy(sourceFunctions, headersInit) {
return async ({
event,
request,
url,
params
}) => {
const sourcePromises = sourceFunctions.map(fn => {
// Ensure the return value of the function is always a promise.
return Promise.resolve(fn({
event,
request,
url,
params
}));
});
if (isSupported()) {
const {
done,
response
} = concatenateToResponse(sourcePromises, headersInit);
if (event) {
event.waitUntil(done);
}
return response;
}
{
logger_js.logger.log(`The current browser doesn't support creating response ` + `streams. Falling back to non-streaming response instead.`);
} // Fallback to waiting for everything to finish, and concatenating the
// responses.
const blobPartsPromises = sourcePromises.map(async sourcePromise => {
const source = await sourcePromise;
if (source instanceof Response) {
return source.blob();
} else {
// Technically, a `StreamSource` object can include any valid
// `BodyInit` type, including `FormData` and `URLSearchParams`, which
// cannot be passed to the Blob constructor directly, so we have to
// convert them to actual Blobs first.
return new Response(source).blob();
}
});
const blobParts = await Promise.all(blobPartsPromises);
const headers = createHeaders(headersInit); // Constructing a new Response from a Blob source is well-supported.
// So is constructing a new Blob from multiple source Blobs or strings.
return new Response(new Blob(blobParts), {
headers
});
};
}
exports.concatenate = concatenate;
exports.concatenateToResponse = concatenateToResponse;
exports.isSupported = isSupported;
exports.strategy = strategy;
return exports;
}({}, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private));
//# sourceMappingURL=workbox-streams.dev.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-streams.dev.js","sources":["../_version.js","../concatenate.js","../utils/createHeaders.js","../concatenateToResponse.js","../isSupported.js","../strategy.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:streams:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { Deferred } from 'workbox-core/_private/Deferred.js';\nimport './_version.js';\n/**\n * Takes either a Response, a ReadableStream, or a\n * [BodyInit](https://fetch.spec.whatwg.org/#bodyinit) and returns the\n * ReadableStreamReader object associated with it.\n *\n * @param {module:workbox-streams.StreamSource} source\n * @return {ReadableStreamReader}\n * @private\n */\nfunction _getReaderFromSource(source) {\n if (source instanceof Response) {\n return source.body.getReader();\n }\n if (source instanceof ReadableStream) {\n return source.getReader();\n }\n return new Response(source).body.getReader();\n}\n/**\n * Takes multiple source Promises, each of which could resolve to a Response, a\n * ReadableStream, or a [BodyInit](https://fetch.spec.whatwg.org/#bodyinit).\n *\n * Returns an object exposing a ReadableStream with each individual stream's\n * data returned in sequence, along with a Promise which signals when the\n * stream is finished (useful for passing to a FetchEvent's waitUntil()).\n *\n * @param {Array<Promise<module:workbox-streams.StreamSource>>} sourcePromises\n * @return {Object<{done: Promise, stream: ReadableStream}>}\n *\n * @memberof module:workbox-streams\n */\nfunction concatenate(sourcePromises) {\n if (process.env.NODE_ENV !== 'production') {\n assert.isArray(sourcePromises, {\n moduleName: 'workbox-streams',\n funcName: 'concatenate',\n paramName: 'sourcePromises',\n });\n }\n const readerPromises = sourcePromises.map((sourcePromise) => {\n return Promise.resolve(sourcePromise).then((source) => {\n return _getReaderFromSource(source);\n });\n });\n const streamDeferred = new Deferred();\n let i = 0;\n const logMessages = [];\n const stream = new ReadableStream({\n pull(controller) {\n return readerPromises[i]\n .then((reader) => reader.read())\n .then((result) => {\n if (result.done) {\n if (process.env.NODE_ENV !== 'production') {\n logMessages.push(['Reached the end of source:',\n sourcePromises[i]]);\n }\n i++;\n if (i >= readerPromises.length) {\n // Log all the messages in the group at once in a single group.\n if (process.env.NODE_ENV !== 'production') {\n logger.groupCollapsed(`Concatenating ${readerPromises.length} sources.`);\n for (const message of logMessages) {\n if (Array.isArray(message)) {\n logger.log(...message);\n }\n else {\n logger.log(message);\n }\n }\n logger.log('Finished reading all sources.');\n logger.groupEnd();\n }\n controller.close();\n streamDeferred.resolve();\n return;\n }\n // The `pull` method is defined because we're inside it.\n return this.pull(controller);\n }\n else {\n controller.enqueue(result.value);\n }\n }).catch((error) => {\n if (process.env.NODE_ENV !== 'production') {\n logger.error('An error occurred:', error);\n }\n streamDeferred.reject(error);\n throw error;\n });\n },\n cancel() {\n if (process.env.NODE_ENV !== 'production') {\n logger.warn('The ReadableStream was cancelled.');\n }\n streamDeferred.resolve();\n },\n });\n return { done: streamDeferred.promise, stream };\n}\nexport { concatenate };\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * This is a utility method that deterLine truncated
@@ -0,0 +1,2 @@
this.workbox=this.workbox||{},this.workbox.streams=function(e,n,t){"use strict";try{self["workbox:streams:5.1.4"]&&_()}catch(e){}function s(e){const t=e.map(e=>Promise.resolve(e).then(e=>function(e){return e instanceof Response?e.body.getReader():e instanceof ReadableStream?e.getReader():new Response(e).body.getReader()}(e))),s=new n.Deferred;let r=0;const o=new ReadableStream({pull(e){return t[r].then(e=>e.read()).then(n=>{if(n.done)return r++,r>=t.length?(e.close(),void s.resolve()):this.pull(e);e.enqueue(n.value)}).catch(e=>{throw s.reject(e),e})},cancel(){s.resolve()}});return{done:s.promise,stream:o}}function r(e={}){const n=new Headers(e);return n.has("content-type")||n.set("content-type","text/html"),n}function o(e,n){const{done:t,stream:o}=s(e),c=r(n);return{done:t,response:new Response(o,{headers:c})}}function c(){return t.canConstructReadableStream()}return e.concatenate=s,e.concatenateToResponse=o,e.isSupported=c,e.strategy=function(e,n){return async({event:t,request:s,url:a,params:u})=>{const i=e.map(e=>Promise.resolve(e({event:t,request:s,url:a,params:u})));if(c()){const{done:e,response:s}=o(i,n);return t&&t.waitUntil(e),s}const f=i.map(async e=>{const n=await e;return n instanceof Response?n.blob():new Response(n).blob()}),p=await Promise.all(f),w=r(n);return new Response(new Blob(p),{headers:w})}},e}({},workbox.core._private,workbox.core._private);
//# sourceMappingURL=workbox-streams.prod.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-streams.prod.js","sources":["../_version.js","../concatenate.js","../utils/createHeaders.js","../concatenateToResponse.js","../isSupported.js","../strategy.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:streams:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { assert } from 'workbox-core/_private/assert.js';\nimport { Deferred } from 'workbox-core/_private/Deferred.js';\nimport './_version.js';\n/**\n * Takes either a Response, a ReadableStream, or a\n * [BodyInit](https://fetch.spec.whatwg.org/#bodyinit) and returns the\n * ReadableStreamReader object associated with it.\n *\n * @param {module:workbox-streams.StreamSource} source\n * @return {ReadableStreamReader}\n * @private\n */\nfunction _getReaderFromSource(source) {\n if (source instanceof Response) {\n return source.body.getReader();\n }\n if (source instanceof ReadableStream) {\n return source.getReader();\n }\n return new Response(source).body.getReader();\n}\n/**\n * Takes multiple source Promises, each of which could resolve to a Response, a\n * ReadableStream, or a [BodyInit](https://fetch.spec.whatwg.org/#bodyinit).\n *\n * Returns an object exposing a ReadableStream with each individual stream's\n * data returned in sequence, along with a Promise which signals when the\n * stream is finished (useful for passing to a FetchEvent's waitUntil()).\n *\n * @param {Array<Promise<module:workbox-streams.StreamSource>>} sourcePromises\n * @return {Object<{done: Promise, stream: ReadableStream}>}\n *\n * @memberof module:workbox-streams\n */\nfunction concatenate(sourcePromises) {\n if (process.env.NODE_ENV !== 'production') {\n assert.isArray(sourcePromises, {\n moduleName: 'workbox-streams',\n funcName: 'concatenate',\n paramName: 'sourcePromises',\n });\n }\n const readerPromises = sourcePromises.map((sourcePromise) => {\n return Promise.resolve(sourcePromise).then((source) => {\n return _getReaderFromSource(source);\n });\n });\n const streamDeferred = new Deferred();\n let i = 0;\n const logMessages = [];\n const stream = new ReadableStream({\n pull(controller) {\n return readerPromises[i]\n .then((reader) => reader.read())\n .then((result) => {\n if (result.done) {\n if (process.env.NODE_ENV !== 'production') {\n logMessages.push(['Reached the end of source:',\n sourcePromises[i]]);\n }\n i++;\n if (i >= readerPromises.length) {\n // Log all the messages in the group at once in a single group.\n if (process.env.NODE_ENV !== 'production') {\n logger.groupCollapsed(`Concatenating ${readerPromises.length} sources.`);\n for (const message of logMessages) {\n if (Array.isArray(message)) {\n logger.log(...message);\n }\n else {\n logger.log(message);\n }\n }\n logger.log('Finished reading all sources.');\n logger.groupEnd();\n }\n controller.close();\n streamDeferred.resolve();\n return;\n }\n // The `pull` method is defined because we're inside it.\n return this.pull(controller);\n }\n else {\n controller.enqueue(result.value);\n }\n }).catch((error) => {\n if (process.env.NODE_ENV !== 'production') {\n logger.error('An error occurred:', error);\n }\n streamDeferred.reject(error);\n throw error;\n });\n },\n cancel() {\n if (process.env.NODE_ENV !== 'production') {\n logger.warn('The ReadableStream was cancelled.');\n }\n streamDeferred.resolve();\n },\n });\n return { done: streamDeferred.promise, stream };\n}\nexport { concatenate };\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * This is a utility method that deteLine truncated
@@ -0,0 +1,2 @@
!function(){"use strict";try{self["workbox:sw:5.1.4"]&&_()}catch(t){}const t={backgroundSync:"background-sync",broadcastUpdate:"broadcast-update",cacheableResponse:"cacheable-response",core:"core",expiration:"expiration",googleAnalytics:"offline-ga",navigationPreload:"navigation-preload",precaching:"precaching",rangeRequests:"range-requests",routing:"routing",strategies:"strategies",streams:"streams"};self.workbox=new class{constructor(){return this.v={},this.t={debug:"localhost"===self.location.hostname,modulePathPrefix:null,modulePathCb:null},this.s=this.t.debug?"dev":"prod",this.o=!1,new Proxy(this,{get(e,s){if(e[s])return e[s];const o=t[s];return o&&e.loadModule("workbox-"+o),e[s]}})}setConfig(t={}){if(this.o)throw new Error("Config must be set before accessing workbox.* modules");Object.assign(this.t,t),this.s=this.t.debug?"dev":"prod"}loadModule(t){const e=this.i(t);try{importScripts(e),this.o=!0}catch(s){throw console.error(`Unable to import module '${t}' from '${e}'.`),s}}i(t){if(this.t.modulePathCb)return this.t.modulePathCb(t,this.t.debug);let e=["https://storage.googleapis.com/workbox-cdn/releases/5.1.4"];const s=`${t}.${this.s}.js`,o=this.t.modulePathPrefix;return o&&(e=o.split("/"),""===e[e.length-1]&&e.splice(e.length-1,1)),e.push(s),e.join("/")}}}();
//# sourceMappingURL=workbox-sw.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-sw.js","sources":["../_version.mjs","../controllers/WorkboxSW.mjs","../index.mjs"],"sourcesContent":["try{self['workbox:sw:5.1.4']&&_()}catch(e){}// eslint-disable-line","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\n\nimport '../_version.mjs';\n\nconst CDN_PATH = `WORKBOX_CDN_ROOT_URL`;\n\nconst MODULE_KEY_TO_NAME_MAPPING = {\n /**\n * @name backgroundSync\n * @memberof workbox\n * @see module:workbox-background-sync\n */\n backgroundSync: 'background-sync',\n /**\n * @name broadcastUpdate\n * @memberof workbox\n * @see module:workbox-broadcast-update\n */\n broadcastUpdate: 'broadcast-update',\n /**\n * @name cacheableResponse\n * @memberof workbox\n * @see module:workbox-cacheable-response\n */\n cacheableResponse: 'cacheable-response',\n /**\n * @name core\n * @memberof workbox\n * @see module:workbox-core\n */\n core: 'core',\n /**\n * @name expiration\n * @memberof workbox\n * @see module:workbox-expiration\n */\n expiration: 'expiration',\n /**\n * @name googleAnalytics\n * @memberof workbox\n * @see module:workbox-google-analytics\n */\n googleAnalytics: 'offline-ga',\n /**\n * @name navigationPreload\n * @memberof workbox\n * @see module:workbox-navigation-preload\n */\n navigationPreload: 'navigation-preload',\n /**\n * @name precaching\n * @memberof workbox\n * @see module:workbox-precaching\n */\n precaching: 'precaching',\n /**\n * @name rangeRequests\n * @memberof workbox\n * @see module:workbox-range-requests\n */\n rangeRequests: 'range-requests',\n /**\n * @name routing\n * @memberof workbox\n * @see module:workbox-routing\n */\n routing: 'routing',\n /**\n * @name strategies\n * @memberof workbox\n * @see module:workbox-strategies\n */\n strategies: 'strategies',\n /**\n * @name streams\n * @memberof workbox\n * @see module:workbox-streams\n */\n streams: 'streams',\n};\n\n/**\n * This class can be used to make it easy to use the various parts of\n * Workbox.\n *\n * @private\n */\nexport class WorkboxSW {\n /**\n * Creates a proxy that automatically loads workbox namespaces on demand.\n *\n * @private\n */\n constructor() {\n this.v = {};\n this._options = {\n debug: self.location.hostname === 'localhost',\n modulePathPrefix: null,\n modulePathCb: null,\n };\n\n this._env = this._options.debug ? 'dev' : 'prod';\n this._modulesLoaded = false;\n\n return new Proxy(this, {\n get(target, key) {\n if (target[key]) {\n return target[key];\n }\n\n const moduleName = MODULE_KEY_TO_NAME_MAPPING[key];\n if (moduleName) {\n target.loadModule(`workbox-${moduleName}`);\n }\n\n return target[key];\n },\n });\n }\n\n /**\n * Updates the configuration options. You can specify whether to treat as a\n * debug build and whether to use a CDN or a specific path when importing\n * other workbox-modules\n *\n * @param {Object} [options]\n * @param {boolean} [options.debug] If true, `dev` builds are using, otherwise\n * `prod` builds are used. By default, `prod` is used unless on localhost.\n * @param {Function} [options.modulePathPrefix] To avoid using the CDN with\n * `workbox-sw` set the path prefix of where modules should be loaded from.\n * For example `modulePathPrefix: '/third_party/workbox/v3.0.0/'`.\n * @param {workbox~ModulePathCallback} [options.modulePathCb] If defined,\n * this callback will be responsible for determining the path of each\n * workbox module.\n *\n * @alias workbox.setConfig\n */\n setConfig(options = {}) {\n if (!this._modulesLoaded) {\n Object.assign(this._options, options);\n this._env = this._options.debug ? 'dev' : 'prod';\n } else {\n throw new Error('Config must be set before accessing workbox.* modules');\n }\n }\n\n /**\n * Load a Workbox module by passing in the appropriate module name.\n *\n * This is not generally needed unless you know there are modules that are\n * dynamically used and you want to safe guard use of the module while the\n * user may be offline.\n *\n * @param {string} moduleName\n *\n * @alias workbox.loadModule\n */\n loadModule(moduleName) {\n const modulePath = this._getImportPath(moduleName);\n try {\n importScripts(modulePath);\n this._modulesLoaded = true;\n } catch (err) {\n // TODO Add context of this error if using the CDN vs the local file.\n\n // We can't rely on workbox-core being loaded so using console\n // eslint-disable-next-line\n console.error(\n `Unable to import module '${moduleName}' from '${modulePath}'.`);\n throw err;\n }\n }\n\n /**\n * This method will get the path / CDN URL to be used foLine truncated
File diff suppressed because it is too large. Load diff
@@ -0,0 +1 @@
{"version":3,"file":"workbox-window.dev.es5.mjs","sources":["../_version.js","../messageSW.js","../../workbox-core/_version.js","../../workbox-core/_private/Deferred.js","../../workbox-core/_private/dontWaitFor.js","../../workbox-core/_private/logger.js","../utils/WorkboxEventTarget.js","../utils/urlsMatch.js","../utils/WorkboxEvent.js","../Workbox.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:window:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport './_version.js';\n/**\n * Sends a data object to a service worker via `postMessage` and resolves with\n * a response (if any).\n *\n * A response can be set in a message handler in the service worker by\n * calling `event.ports[0].postMessage(...)`, which will resolve the promise\n * returned by `messageSW()`. If no response is set, the promise will not\n * resolve.\n *\n * @param {ServiceWorker} sw The service worker to send the message to.\n * @param {Object} data An object to send to the service worker.\n * @return {Promise<Object|undefined>}\n * @memberof module:workbox-window\n */\nfunction messageSW(sw, data) {\n return new Promise((resolve) => {\n const messageChannel = new MessageChannel();\n messageChannel.port1.onmessage = (event) => {\n resolve(event.data);\n };\n sw.postMessage(data, [messageChannel.port2]);\n });\n}\nexport { messageSW };\n","\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:core:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * The Deferred class composes Promises in a way that allows for them to be\n * resolved or rejected from outside the constructor. In most cases promises\n * should be used directly, but Deferreds can be necessary when the logic to\n * resolve a promise must be separate.\n *\n * @private\n */\nclass Deferred {\n /**\n * Creates a promise and exposes its resolve and reject functions as methods.\n */\n constructor() {\n this.promise = new Promise((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n }\n}\nexport { Deferred };\n","/*\n Copyright 2019 Google LLC\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * A helper function that prevents a promise from being flagged as unused.\n *\n * @private\n **/\nexport function dontWaitFor(promise) {\n // Effective no-op.\n promise.then(() => { });\n}\n","/*\n Copyright 2019 Google LLC\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\nconst logger = (process.env.NODE_ENV === 'production' ? null : (() => {\n // Don't overwrite this value if it's already set.\n // See https://github.com/GoogleChrome/workbox/pull/2284#issuecomment-560470923\n if (!('__WB_DISABLE_DEV_LOGS' in self)) {\n self.__WB_DISABLE_DEV_LOGS = false;\n }\n let inGroup = false;\n const methodToColorMap = {\n debug: `#7f8c8d`,\n log: `#2ecc71`,\n warn: `#f39c12`,\n error: `#c0392b`,\n groupCollapsed: `#3498db`,\n groupEnd: null,\n };\n const print = function (method, args) {\n if (self.__WB_DISABLE_DEV_LOGS) {\n return;\n }\n if (method === 'groupCollapsed') {\n // Safari doesn't print all console.groupCollapsed() arguments:\n // https://bugs.webkit.org/show_bug.cgi?id=182754\n if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {\n console[method](...args);\n return;\n }\n }\n const styles = [\n `background: ${methodToColorMap[method]}`,\n `border-radius: 0.5em`,\n `color: white`,\n `font-weight: bold`,\n `padding: 2px 0.5em`,\n ];\n // When in a group, the workbox prefix is not displayed.\n const logPrefix = inGroup ? [] : ['%cworkbox', styles.join(';')];\n console[method](...logPrefix, ...args);\n if (method === 'groupCollapsed') {\n inGroup = true;\n }\n if (method === 'groupEnd') {\n inGroup = false;\n }\n };\n const api = {};\n const loggerMethods = Object.keys(methodToColorMap);\n for (const key of loggerMethods) {\n const method = key;\n api[method] = (...args) => {\n print(method, args);\n };\n Line truncated
@@ -0,0 +1,943 @@
try {
self['workbox:window:5.1.4'] && _();
} catch (e) {}
/*
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.
*/
/**
* Sends a data object to a service worker via `postMessage` and resolves with
* a response (if any).
*
* A response can be set in a message handler in the service worker by
* calling `event.ports[0].postMessage(...)`, which will resolve the promise
* returned by `messageSW()`. If no response is set, the promise will not
* resolve.
*
* @param {ServiceWorker} sw The service worker to send the message to.
* @param {Object} data An object to send to the service worker.
* @return {Promise<Object|undefined>}
* @memberof module:workbox-window
*/
function messageSW(sw, data) {
return new Promise(resolve => {
const messageChannel = new MessageChannel();
messageChannel.port1.onmessage = event => {
resolve(event.data);
};
sw.postMessage(data, [messageChannel.port2]);
});
}
try {
self['workbox:core:5.1.4'] && _();
} catch (e) {}
/*
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.
*/
/**
* The Deferred class composes Promises in a way that allows for them to be
* resolved or rejected from outside the constructor. In most cases promises
* should be used directly, but Deferreds can be necessary when the logic to
* resolve a promise must be separate.
*
* @private
*/
class Deferred {
/**
* Creates a promise and exposes its resolve and reject functions as methods.
*/
constructor() {
this.promise = new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
}
}
/*
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.
*/
/**
* A helper function that prevents a promise from being flagged as unused.
*
* @private
**/
function dontWaitFor(promise) {
// Effective no-op.
promise.then(() => {});
}
/*
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 logger = (() => {
// Don't overwrite this value if it's already set.
// See https://github.com/GoogleChrome/workbox/pull/2284#issuecomment-560470923
if (!('__WB_DISABLE_DEV_LOGS' in self)) {
self.__WB_DISABLE_DEV_LOGS = false;
}
let inGroup = false;
const methodToColorMap = {
debug: `#7f8c8d`,
log: `#2ecc71`,
warn: `#f39c12`,
error: `#c0392b`,
groupCollapsed: `#3498db`,
groupEnd: null
};
const print = function (method, args) {
if (self.__WB_DISABLE_DEV_LOGS) {
return;
}
if (method === 'groupCollapsed') {
// Safari doesn't print all console.groupCollapsed() arguments:
// https://bugs.webkit.org/show_bug.cgi?id=182754
if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {
console[method](...args);
return;
}
}
const styles = [`background: ${methodToColorMap[method]}`, `border-radius: 0.5em`, `color: white`, `font-weight: bold`, `padding: 2px 0.5em`]; // When in a group, the workbox prefix is not displayed.
const logPrefix = inGroup ? [] : ['%cworkbox', styles.join(';')];
console[method](...logPrefix, ...args);
if (method === 'groupCollapsed') {
inGroup = true;
}
if (method === 'groupEnd') {
inGroup = false;
}
};
const api = {};
const loggerMethods = Object.keys(methodToColorMap);
for (const key of loggerMethods) {
const method = key;
api[method] = (...args) => {
print(method, args);
};
}
return api;
})();
/*
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.
*/
/**
* A minimal `EventTarget` shim.
* This is necessary because not all browsers support constructable
* `EventTarget`, so using a real `EventTarget` will error.
* @private
*/
class WorkboxEventTarget {
constructor() {
this._eventListenerRegistry = new Map();
}
/**
* @param {string} type
* @param {Function} listener
* @private
*/
addEventListener(type, listener) {
const foo = this._getEventListenersByType(type);
foo.add(listener);
}
/**
* @param {string} type
* @param {Function} listener
* @private
*/
removeEventListener(type, listener) {
this._getEventListenersByType(type).delete(listener);
}
/**
* @param {Object} event
* @private
*/
dispatchEvent(event) {
event.target = this;
const listeners = this._getEventListenersByType(event.type);
for (const listener of listeners) {
listener(event);
}
}
/**
* Returns a Set of listeners associated with the passed event type.
* If no handlers have been registered, an empty Set is returned.
*
* @param {string} type The event type.
* @return {Set<ListenerCallback>} An array of handler functions.
* @private
*/
_getEventListenersByType(type) {
if (!this._eventListenerRegistry.has(type)) {
this._eventListenerRegistry.set(type, new Set());
}
return this._eventListenerRegistry.get(type);
}
}
/*
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.
*/
/**
* Returns true if two URLs have the same `.href` property. The URLS can be
* relative, and if they are the current location href is used to resolve URLs.
*
* @private
* @param {string} url1
* @param {string} url2
* @return {boolean}
*/
function urlsMatch(url1, url2) {
const {
href
} = location;
return new URL(url1, href).href === new URL(url2, href).href;
}
/*
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.
*/
/**
* A minimal `Event` subclass shim.
* This doesn't *actually* subclass `Event` because not all browsers support
* constructable `EventTarget`, and using a real `Event` will error.
* @private
*/
class WorkboxEvent {
constructor(type, props) {
this.type = type;
Object.assign(this, props);
}
}
/*
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.
*/
// `skipWaiting()` wasn't called. This 200 amount wasn't scientifically
// chosen, but it seems to avoid false positives in my testing.
const WAITING_TIMEOUT_DURATION = 200; // The amount of time after a registration that we can reasonably conclude
// that the registration didn't trigger an update.
const REGISTRATION_TIMEOUT_DURATION = 60000;
/**
* A class to aid in handling service worker registration, updates, and
* reacting to service worker lifecycle events.
*
* @fires [message]{@link module:workbox-window.Workbox#message}
* @fires [installed]{@link module:workbox-window.Workbox#installed}
* @fires [waiting]{@link module:workbox-window.Workbox#waiting}
* @fires [controlling]{@link module:workbox-window.Workbox#controlling}
* @fires [activated]{@link module:workbox-window.Workbox#activated}
* @fires [redundant]{@link module:workbox-window.Workbox#redundant}
* @fires [externalinstalled]{@link module:workbox-window.Workbox#externalinstalled}
* @fires [externalwaiting]{@link module:workbox-window.Workbox#externalwaiting}
* @fires [externalactivated]{@link module:workbox-window.Workbox#externalactivated}
* @memberof module:workbox-window
*/
class Workbox extends WorkboxEventTarget {
/**
* Creates a new Workbox instance with a script URL and service worker
* options. The script URL and options are the same as those used when
* calling `navigator.serviceWorker.register(scriptURL, options)`. See:
* https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register
*
* @param {string} scriptURL The service worker script associated with this
* instance.
* @param {Object} [registerOptions] The service worker options associated
* with this instance.
*/
constructor(scriptURL, registerOptions = {}) {
super();
this._registerOptions = {};
this._updateFoundCount = 0; // Deferreds we can resolve later.
this._swDeferred = new Deferred();
this._activeDeferred = new Deferred();
this._controllingDeferred = new Deferred();
this._registrationTime = 0;
this._ownSWs = new Set();
/**
* @private
*/
this._onUpdateFound = () => {
// `this._registration` will never be `undefined` after an update is found.
const registration = this._registration;
const installingSW = registration.installing; // If the script URL passed to `navigator.serviceWorker.register()` is
// different from the current controlling SW's script URL, we know any
// successful registration calls will trigger an `updatefound` event.
// But if the registered script URL is the same as the current controlling
// SW's script URL, we'll only get an `updatefound` event if the file
// changed since it was last registered. This can be a problem if the user
// opens up the same page in a different tab, and that page registers
// a SW that triggers an update. It's a problem because this page has no
// good way of knowing whether the `updatefound` event came from the SW
// script it registered or from a registration attempt made by a newer
// version of the page running in another tab.
// To minimize the possibility of a false positive, we use the logic here:
const updateLikelyTriggeredExternally = // Since we enforce only calling `register()` once, and since we don't
// add the `updatefound` event listener until the `register()` call, if
// `_updateFoundCount` is > 0 then it means this method has already
// been called, thus this SW must be external
this._updateFoundCount > 0 || // If the script URL of the installing SW is different from this
// instance's script URL, we know it's definitely not from our
// registration.
!urlsMatch(installingSW.scriptURL, this._scriptURL) || // If all of the above are false, then we use a time-based heuristic:
// Any `updatefound` event that occurs long after our registration is
// assumed to be external.
performance.now() > this._registrationTime + REGISTRATION_TIMEOUT_DURATION ? // If any of the above are not true, we assume the update was
// triggered by this instance.
true : false;
if (updateLikelyTriggeredExternally) {
this._externalSW = installingSW;
registration.removeEventListener('updatefound', this._onUpdateFound);
} else {
// If the update was not triggered externally we know the installing
// SW is the one we registered, so we set it.
this._sw = installingSW;
this._ownSWs.add(installingSW);
this._swDeferred.resolve(installingSW); // The `installing` state isn't something we have a dedicated
// callback for, but we do log messages for it in development.
{
if (navigator.serviceWorker.controller) {
logger.log('Updated service worker found. Installing now...');
} else {
logger.log('Service worker is installing...');
}
}
} // Increment the `updatefound` count, so future invocations of this
// method can be sure they were triggered externally.
++this._updateFoundCount; // Add a `statechange` listener regardless of whether this update was
// triggered externally, since we have callbacks for both.
installingSW.addEventListener('statechange', this._onStateChange);
};
/**
* @private
* @param {Event} originalEvent
*/
this._onStateChange = originalEvent => {
// `this._registration` will never be `undefined` after an update is found.
const registration = this._registration;
const sw = originalEvent.target;
const {
state
} = sw;
const isExternal = sw === this._externalSW;
const eventPrefix = isExternal ? 'external' : '';
const eventProps = {
sw,
originalEvent
};
if (!isExternal && this._isUpdate) {
eventProps.isUpdate = true;
}
this.dispatchEvent(new WorkboxEvent(eventPrefix + state, eventProps));
if (state === 'installed') {
// This timeout is used to ignore cases where the service worker calls
// `skipWaiting()` in the install event, thus moving it directly in the
// activating state. (Since all service workers *must* go through the
// waiting phase, the only way to detect `skipWaiting()` called in the
// install event is to observe that the time spent in the waiting phase
// is very short.)
// NOTE: we don't need separate timeouts for the own and external SWs
// since they can't go through these phases at the same time.
this._waitingTimeout = self.setTimeout(() => {
// Ensure the SW is still waiting (it may now be redundant).
if (state === 'installed' && registration.waiting === sw) {
this.dispatchEvent(new WorkboxEvent(eventPrefix + 'waiting', eventProps));
{
if (isExternal) {
logger.warn('An external service worker has installed but is ' + 'waiting for this client to close before activating...');
} else {
logger.warn('The service worker has installed but is waiting ' + 'for existing clients to close before activating...');
}
}
}
}, WAITING_TIMEOUT_DURATION);
} else if (state === 'activating') {
clearTimeout(this._waitingTimeout);
if (!isExternal) {
this._activeDeferred.resolve(sw);
}
}
{
switch (state) {
case 'installed':
if (isExternal) {
logger.warn('An external service worker has installed. ' + 'You may want to suggest users reload this page.');
} else {
logger.log('Registered service worker installed.');
}
break;
case 'activated':
if (isExternal) {
logger.warn('An external service worker has activated.');
} else {
logger.log('Registered service worker activated.');
if (sw !== navigator.serviceWorker.controller) {
logger.warn('The registered service worker is active but ' + 'not yet controlling the page. Reload or run ' + '`clients.claim()` in the service worker.');
}
}
break;
case 'redundant':
if (sw === this._compatibleControllingSW) {
logger.log('Previously controlling service worker now redundant!');
} else if (!isExternal) {
logger.log('Registered service worker now redundant!');
}
break;
}
}
};
/**
* @private
* @param {Event} originalEvent
*/
this._onControllerChange = originalEvent => {
const sw = this._sw;
if (sw === navigator.serviceWorker.controller) {
this.dispatchEvent(new WorkboxEvent('controlling', {
sw,
originalEvent,
isUpdate: this._isUpdate
}));
{
logger.log('Registered service worker now controlling this page.');
}
this._controllingDeferred.resolve(sw);
}
};
/**
* @private
* @param {Event} originalEvent
*/
this._onMessage = async originalEvent => {
const {
data,
source
} = originalEvent; // Wait until there's an "own" service worker. This is used to buffer
// `message` events that may be received prior to calling `register()`.
await this.getSW(); // If the service worker that sent the message is in the list of own
// service workers for this instance, dispatch a `message` event.
// NOTE: we check for all previously owned service workers rather than
// just the current one because some messages (e.g. cache updates) use
// a timeout when sent and may be delayed long enough for a service worker
// update to be found.
if (this._ownSWs.has(source)) {
this.dispatchEvent(new WorkboxEvent('message', {
data,
sw: source,
originalEvent
}));
}
};
this._scriptURL = scriptURL;
this._registerOptions = registerOptions; // Add a message listener immediately since messages received during
// page load are buffered only until the DOMContentLoaded event:
// https://github.com/GoogleChrome/workbox/issues/2202
navigator.serviceWorker.addEventListener('message', this._onMessage);
}
/**
* Registers a service worker for this instances script URL and service
* worker options. By default this method delays registration until after
* the window has loaded.
*
* @param {Object} [options]
* @param {Function} [options.immediate=false] Setting this to true will
* register the service worker immediately, even if the window has
* not loaded (not recommended).
*/
async register({
immediate = false
} = {}) {
{
if (this._registrationTime) {
logger.error('Cannot re-register a Workbox instance after it has ' + 'been registered. Create a new instance instead.');
return;
}
}
if (!immediate && document.readyState !== 'complete') {
await new Promise(res => window.addEventListener('load', res));
} // Set this flag to true if any service worker was controlling the page
// at registration time.
this._isUpdate = Boolean(navigator.serviceWorker.controller); // Before registering, attempt to determine if a SW is already controlling
// the page, and if that SW script (and version, if specified) matches this
// instance's script.
this._compatibleControllingSW = this._getControllingSWIfCompatible();
this._registration = await this._registerScript(); // If we have a compatible controller, store the controller as the "own"
// SW, resolve active/controlling deferreds and add necessary listeners.
if (this._compatibleControllingSW) {
this._sw = this._compatibleControllingSW;
this._activeDeferred.resolve(this._compatibleControllingSW);
this._controllingDeferred.resolve(this._compatibleControllingSW);
this._compatibleControllingSW.addEventListener('statechange', this._onStateChange, {
once: true
});
} // If there's a waiting service worker with a matching URL before the
// `updatefound` event fires, it likely means that this site is open
// in another tab, or the user refreshed the page (and thus the previous
// page wasn't fully unloaded before this page started loading).
// https://developers.google.com/web/fundamentals/primers/service-workers/lifecycle#waiting
const waitingSW = this._registration.waiting;
if (waitingSW && urlsMatch(waitingSW.scriptURL, this._scriptURL)) {
// Store the waiting SW as the "own" Sw, even if it means overwriting
// a compatible controller.
this._sw = waitingSW; // Run this in the next microtask, so any code that adds an event
// listener after awaiting `register()` will get this event.
dontWaitFor(Promise.resolve().then(() => {
this.dispatchEvent(new WorkboxEvent('waiting', {
sw: waitingSW,
wasWaitingBeforeRegister: true
}));
{
logger.warn('A service worker was already waiting to activate ' + 'before this script was registered...');
}
}));
} // If an "own" SW is already set, resolve the deferred.
if (this._sw) {
this._swDeferred.resolve(this._sw);
this._ownSWs.add(this._sw);
}
{
logger.log('Successfully registered service worker.', this._scriptURL);
if (navigator.serviceWorker.controller) {
if (this._compatibleControllingSW) {
logger.debug('A service worker with the same script URL ' + 'is already controlling this page.');
} else {
logger.debug('A service worker with a different script URL is ' + 'currently controlling the page. The browser is now fetching ' + 'the new script now...');
}
}
const currentPageIsOutOfScope = () => {
const scopeURL = new URL(this._registerOptions.scope || this._scriptURL, document.baseURI);
const scopeURLBasePath = new URL('./', scopeURL.href).pathname;
return !location.pathname.startsWith(scopeURLBasePath);
};
if (currentPageIsOutOfScope()) {
logger.warn('The current page is not in scope for the registered ' + 'service worker. Was this a mistake?');
}
}
this._registration.addEventListener('updatefound', this._onUpdateFound);
navigator.serviceWorker.addEventListener('controllerchange', this._onControllerChange, {
once: true
});
return this._registration;
}
/**
* Checks for updates of the registered service worker.
*/
async update() {
if (!this._registration) {
{
logger.error('Cannot update a Workbox instance without ' + 'being registered. Register the Workbox instance first.');
}
return;
} // Try to update registration
await this._registration.update();
}
/**
* Resolves to the service worker registered by this instance as soon as it
* is active. If a service worker was already controlling at registration
* time then it will resolve to that if the script URLs (and optionally
* script versions) match, otherwise it will wait until an update is found
* and activates.
*
* @return {Promise<ServiceWorker>}
*/
get active() {
return this._activeDeferred.promise;
}
/**
* Resolves to the service worker registered by this instance as soon as it
* is controlling the page. If a service worker was already controlling at
* registration time then it will resolve to that if the script URLs (and
* optionally script versions) match, otherwise it will wait until an update
* is found and starts controlling the page.
* Note: the first time a service worker is installed it will active but
* not start controlling the page unless `clients.claim()` is called in the
* service worker.
*
* @return {Promise<ServiceWorker>}
*/
get controlling() {
return this._controllingDeferred.promise;
}
/**
* Resolves with a reference to a service worker that matches the script URL
* of this instance, as soon as it's available.
*
* If, at registration time, there's already an active or waiting service
* worker with a matching script URL, it will be used (with the waiting
* service worker taking precedence over the active service worker if both
* match, since the waiting service worker would have been registered more
* recently).
* If there's no matching active or waiting service worker at registration
* time then the promise will not resolve until an update is found and starts
* installing, at which point the installing service worker is used.
*
* @return {Promise<ServiceWorker>}
*/
async getSW() {
// If `this._sw` is set, resolve with that as we want `getSW()` to
// return the correct (new) service worker if an update is found.
return this._sw !== undefined ? this._sw : this._swDeferred.promise;
}
/**
* Sends the passed data object to the service worker registered by this
* instance (via [`getSW()`]{@link module:workbox-window.Workbox#getSW}) and resolves
* with a response (if any).
*
* A response can be set in a message handler in the service worker by
* calling `event.ports[0].postMessage(...)`, which will resolve the promise
* returned by `messageSW()`. If no response is set, the promise will never
* resolve.
*
* @param {Object} data An object to send to the service worker
* @return {Promise<Object>}
*/
async messageSW(data) {
const sw = await this.getSW();
return messageSW(sw, data);
}
/**
* Checks for a service worker already controlling the page and returns
* it if its script URL matches.
*
* @private
* @return {ServiceWorker|undefined}
*/
_getControllingSWIfCompatible() {
const controller = navigator.serviceWorker.controller;
if (controller && urlsMatch(controller.scriptURL, this._scriptURL)) {
return controller;
} else {
return undefined;
}
}
/**
* Registers a service worker for this instances script URL and register
* options and tracks the time registration was complete.
*
* @private
*/
async _registerScript() {
try {
const reg = await navigator.serviceWorker.register(this._scriptURL, this._registerOptions); // Keep track of when registration happened, so it can be used in the
// `this._onUpdateFound` heuristic. Also use the presence of this
// property as a way to see if `.register()` has been called.
this._registrationTime = performance.now();
return reg;
} catch (error) {
{
logger.error(error);
} // Re-throw the error.
throw error;
}
}
}
// -----------------------------------------------------------------------
/**
* The `message` event is dispatched any time a `postMessage` is received.
*
* @event module:workbox-window.Workbox#message
* @type {WorkboxEvent}
* @property {*} data The `data` property from the original `message` event.
* @property {Event} originalEvent The original [`message`]{@link https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent}
* event.
* @property {string} type `message`.
* @property {Workbox} target The `Workbox` instance.
*/
/**
* The `installed` event is dispatched if the state of a
* [`Workbox`]{@link module:workbox-window.Workbox} instance's
* [registered service worker]{@link https://developers.google.com/web/tools/workbox/modules/workbox-precaching#def-registered-sw}
* changes to `installed`.
*
* Then can happen either the very first time a service worker is installed,
* or after an update to the current service worker is found. In the case
* of an update being found, the event's `isUpdate` property will be `true`.
*
* @event module:workbox-window.Workbox#installed
* @type {WorkboxEvent}
* @property {ServiceWorker} sw The service worker instance.
* @property {Event} originalEvent The original [`statechange`]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker/onstatechange}
* event.
* @property {boolean|undefined} isUpdate True if a service worker was already
* controlling when this `Workbox` instance called `register()`.
* @property {string} type `installed`.
* @property {Workbox} target The `Workbox` instance.
*/
/**
* The `waiting` event is dispatched if the state of a
* [`Workbox`]{@link module:workbox-window.Workbox} instance's
* [registered service worker]{@link https://developers.google.com/web/tools/workbox/modules/workbox-precaching#def-registered-sw}
* changes to `installed` and then doesn't immediately change to `activating`.
* It may also be dispatched if a service worker with the same
* [`scriptURL`]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker/scriptURL}
* was already waiting when the [`register()`]{@link module:workbox-window.Workbox#register}
* method was called.
*
* @event module:workbox-window.Workbox#waiting
* @type {WorkboxEvent}
* @property {ServiceWorker} sw The service worker instance.
* @property {Event|undefined} originalEvent The original
* [`statechange`]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker/onstatechange}
* event, or `undefined` in the case where the service worker was waiting
* to before `.register()` was called.
* @property {boolean|undefined} isUpdate True if a service worker was already
* controlling when this `Workbox` instance called `register()`.
* @property {boolean|undefined} wasWaitingBeforeRegister True if a service worker with
* a matching `scriptURL` was already waiting when this `Workbox`
* instance called `register()`.
* @property {string} type `waiting`.
* @property {Workbox} target The `Workbox` instance.
*/
/**
* The `controlling` event is dispatched if a
* [`controllerchange`]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/oncontrollerchange}
* fires on the service worker [container]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer}
* and the [`scriptURL`]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker/scriptURL}
* of the new [controller]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/controller}
* matches the `scriptURL` of the `Workbox` instance's
* [registered service worker]{@link https://developers.google.com/web/tools/workbox/modules/workbox-precaching#def-registered-sw}.
*
* @event module:workbox-window.Workbox#controlling
* @type {WorkboxEvent}
* @property {ServiceWorker} sw The service worker instance.
* @property {Event} originalEvent The original [`controllerchange`]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/oncontrollerchange}
* event.
* @property {boolean|undefined} isUpdate True if a service worker was already
* controlling when this service worker was registered.
* @property {string} type `controlling`.
* @property {Workbox} target The `Workbox` instance.
*/
/**
* The `activated` event is dispatched if the state of a
* [`Workbox`]{@link module:workbox-window.Workbox} instance's
* [registered service worker]{@link https://developers.google.com/web/tools/workbox/modules/workbox-precaching#def-registered-sw}
* changes to `activated`.
*
* @event module:workbox-window.Workbox#activated
* @type {WorkboxEvent}
* @property {ServiceWorker} sw The service worker instance.
* @property {Event} originalEvent The original [`statechange`]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker/onstatechange}
* event.
* @property {boolean|undefined} isUpdate True if a service worker was already
* controlling when this `Workbox` instance called `register()`.
* @property {string} type `activated`.
* @property {Workbox} target The `Workbox` instance.
*/
/**
* The `redundant` event is dispatched if the state of a
* [`Workbox`]{@link module:workbox-window.Workbox} instance's
* [registered service worker]{@link https://developers.google.com/web/tools/workbox/modules/workbox-precaching#def-registered-sw}
* changes to `redundant`.
*
* @event module:workbox-window.Workbox#redundant
* @type {WorkboxEvent}
* @property {ServiceWorker} sw The service worker instance.
* @property {Event} originalEvent The original [`statechange`]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker/onstatechange}
* event.
* @property {boolean|undefined} isUpdate True if a service worker was already
* controlling when this `Workbox` instance called `register()`.
* @property {string} type `redundant`.
* @property {Workbox} target The `Workbox` instance.
*/
/**
* The `externalinstalled` event is dispatched if the state of an
* [external service worker]{@link https://developers.google.com/web/tools/workbox/modules/workbox-window#when_an_unexpected_version_of_the_service_worker_is_found}
* changes to `installed`.
*
* @event module:workbox-window.Workbox#externalinstalled
* @type {WorkboxEvent}
* @property {ServiceWorker} sw The service worker instance.
* @property {Event} originalEvent The original [`statechange`]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker/onstatechange}
* event.
* @property {string} type `externalinstalled`.
* @property {Workbox} target The `Workbox` instance.
*/
/**
* The `externalwaiting` event is dispatched if the state of an
* [external service worker]{@link https://developers.google.com/web/tools/workbox/modules/workbox-window#when_an_unexpected_version_of_the_service_worker_is_found}
* changes to `waiting`.
*
* @event module:workbox-window.Workbox#externalwaiting
* @type {WorkboxEvent}
* @property {ServiceWorker} sw The service worker instance.
* @property {Event} originalEvent The original [`statechange`]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker/onstatechange}
* event.
* @property {string} type `externalwaiting`.
* @property {Workbox} target The `Workbox` instance.
*/
/**
* The `externalactivated` event is dispatched if the state of an
* [external service worker]{@link https://developers.google.com/web/tools/workbox/modules/workbox-window#when_an_unexpected_version_of_the_service_worker_is_found}
* changes to `activated`.
*
* @event module:workbox-window.Workbox#externalactivated
* @type {WorkboxEvent}
* @property {ServiceWorker} sw The service worker instance.
* @property {Event} originalEvent The original [`statechange`]{@link https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker/onstatechange}
* event.
* @property {string} type `externalactivated`.
* @property {Workbox} target The `Workbox` instance.
*/
export { Workbox, messageSW };
//# sourceMappingURL=workbox-window.dev.mjs.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-window.dev.mjs","sources":["../_version.js","../messageSW.js","../../workbox-core/_version.js","../../workbox-core/_private/Deferred.js","../../workbox-core/_private/dontWaitFor.js","../../workbox-core/_private/logger.js","../utils/WorkboxEventTarget.js","../utils/urlsMatch.js","../utils/WorkboxEvent.js","../Workbox.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:window:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport './_version.js';\n/**\n * Sends a data object to a service worker via `postMessage` and resolves with\n * a response (if any).\n *\n * A response can be set in a message handler in the service worker by\n * calling `event.ports[0].postMessage(...)`, which will resolve the promise\n * returned by `messageSW()`. If no response is set, the promise will not\n * resolve.\n *\n * @param {ServiceWorker} sw The service worker to send the message to.\n * @param {Object} data An object to send to the service worker.\n * @return {Promise<Object|undefined>}\n * @memberof module:workbox-window\n */\nfunction messageSW(sw, data) {\n return new Promise((resolve) => {\n const messageChannel = new MessageChannel();\n messageChannel.port1.onmessage = (event) => {\n resolve(event.data);\n };\n sw.postMessage(data, [messageChannel.port2]);\n });\n}\nexport { messageSW };\n","\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:core:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * The Deferred class composes Promises in a way that allows for them to be\n * resolved or rejected from outside the constructor. In most cases promises\n * should be used directly, but Deferreds can be necessary when the logic to\n * resolve a promise must be separate.\n *\n * @private\n */\nclass Deferred {\n /**\n * Creates a promise and exposes its resolve and reject functions as methods.\n */\n constructor() {\n this.promise = new Promise((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n }\n}\nexport { Deferred };\n","/*\n Copyright 2019 Google LLC\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * A helper function that prevents a promise from being flagged as unused.\n *\n * @private\n **/\nexport function dontWaitFor(promise) {\n // Effective no-op.\n promise.then(() => { });\n}\n","/*\n Copyright 2019 Google LLC\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\nconst logger = (process.env.NODE_ENV === 'production' ? null : (() => {\n // Don't overwrite this value if it's already set.\n // See https://github.com/GoogleChrome/workbox/pull/2284#issuecomment-560470923\n if (!('__WB_DISABLE_DEV_LOGS' in self)) {\n self.__WB_DISABLE_DEV_LOGS = false;\n }\n let inGroup = false;\n const methodToColorMap = {\n debug: `#7f8c8d`,\n log: `#2ecc71`,\n warn: `#f39c12`,\n error: `#c0392b`,\n groupCollapsed: `#3498db`,\n groupEnd: null,\n };\n const print = function (method, args) {\n if (self.__WB_DISABLE_DEV_LOGS) {\n return;\n }\n if (method === 'groupCollapsed') {\n // Safari doesn't print all console.groupCollapsed() arguments:\n // https://bugs.webkit.org/show_bug.cgi?id=182754\n if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {\n console[method](...args);\n return;\n }\n }\n const styles = [\n `background: ${methodToColorMap[method]}`,\n `border-radius: 0.5em`,\n `color: white`,\n `font-weight: bold`,\n `padding: 2px 0.5em`,\n ];\n // When in a group, the workbox prefix is not displayed.\n const logPrefix = inGroup ? [] : ['%cworkbox', styles.join(';')];\n console[method](...logPrefix, ...args);\n if (method === 'groupCollapsed') {\n inGroup = true;\n }\n if (method === 'groupEnd') {\n inGroup = false;\n }\n };\n const api = {};\n const loggerMethods = Object.keys(methodToColorMap);\n for (const key of loggerMethods) {\n const method = key;\n api[method] = (...args) => {\n print(method, args);\n };\n }\n Line truncated
File diff suppressed because it is too large. Load diff
@@ -0,0 +1 @@
{"version":3,"file":"workbox-window.dev.umd.js","sources":["../_version.js","../messageSW.js","../../workbox-core/_version.js","../../workbox-core/_private/Deferred.js","../../workbox-core/_private/dontWaitFor.js","../../workbox-core/_private/logger.js","../utils/WorkboxEventTarget.js","../utils/urlsMatch.js","../utils/WorkboxEvent.js","../Workbox.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:window:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport './_version.js';\n/**\n * Sends a data object to a service worker via `postMessage` and resolves with\n * a response (if any).\n *\n * A response can be set in a message handler in the service worker by\n * calling `event.ports[0].postMessage(...)`, which will resolve the promise\n * returned by `messageSW()`. If no response is set, the promise will not\n * resolve.\n *\n * @param {ServiceWorker} sw The service worker to send the message to.\n * @param {Object} data An object to send to the service worker.\n * @return {Promise<Object|undefined>}\n * @memberof module:workbox-window\n */\nfunction messageSW(sw, data) {\n return new Promise((resolve) => {\n const messageChannel = new MessageChannel();\n messageChannel.port1.onmessage = (event) => {\n resolve(event.data);\n };\n sw.postMessage(data, [messageChannel.port2]);\n });\n}\nexport { messageSW };\n","\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:core:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * The Deferred class composes Promises in a way that allows for them to be\n * resolved or rejected from outside the constructor. In most cases promises\n * should be used directly, but Deferreds can be necessary when the logic to\n * resolve a promise must be separate.\n *\n * @private\n */\nclass Deferred {\n /**\n * Creates a promise and exposes its resolve and reject functions as methods.\n */\n constructor() {\n this.promise = new Promise((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n }\n}\nexport { Deferred };\n","/*\n Copyright 2019 Google LLC\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * A helper function that prevents a promise from being flagged as unused.\n *\n * @private\n **/\nexport function dontWaitFor(promise) {\n // Effective no-op.\n promise.then(() => { });\n}\n","/*\n Copyright 2019 Google LLC\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\nconst logger = (process.env.NODE_ENV === 'production' ? null : (() => {\n // Don't overwrite this value if it's already set.\n // See https://github.com/GoogleChrome/workbox/pull/2284#issuecomment-560470923\n if (!('__WB_DISABLE_DEV_LOGS' in self)) {\n self.__WB_DISABLE_DEV_LOGS = false;\n }\n let inGroup = false;\n const methodToColorMap = {\n debug: `#7f8c8d`,\n log: `#2ecc71`,\n warn: `#f39c12`,\n error: `#c0392b`,\n groupCollapsed: `#3498db`,\n groupEnd: null,\n };\n const print = function (method, args) {\n if (self.__WB_DISABLE_DEV_LOGS) {\n return;\n }\n if (method === 'groupCollapsed') {\n // Safari doesn't print all console.groupCollapsed() arguments:\n // https://bugs.webkit.org/show_bug.cgi?id=182754\n if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {\n console[method](...args);\n return;\n }\n }\n const styles = [\n `background: ${methodToColorMap[method]}`,\n `border-radius: 0.5em`,\n `color: white`,\n `font-weight: bold`,\n `padding: 2px 0.5em`,\n ];\n // When in a group, the workbox prefix is not displayed.\n const logPrefix = inGroup ? [] : ['%cworkbox', styles.join(';')];\n console[method](...logPrefix, ...args);\n if (method === 'groupCollapsed') {\n inGroup = true;\n }\n if (method === 'groupEnd') {\n inGroup = false;\n }\n };\n const api = {};\n const loggerMethods = Object.keys(methodToColorMap);\n for (const key of loggerMethods) {\n const method = key;\n api[method] = (...args) => {\n print(method, args);\n };\n }Line truncated
@@ -0,0 +1,2 @@
try{self["workbox:window:5.1.4"]&&_()}catch(n){}function n(n,t){return new Promise((function(r){var e=new MessageChannel;e.port1.onmessage=function(n){r(n.data)},n.postMessage(t,[e.port2])}))}function t(n,t){for(var r=0;r<t.length;r++){var e=t[r];e.enumerable=e.enumerable||!1,e.configurable=!0,"value"in e&&(e.writable=!0),Object.defineProperty(n,e.key,e)}}function r(n,t){(null==t||t>n.length)&&(t=n.length);for(var r=0,e=new Array(t);r<t;r++)e[r]=n[r];return e}function e(n,t){var e;if("undefined"==typeof Symbol||null==n[Symbol.iterator]){if(Array.isArray(n)||(e=function(n,t){if(n){if("string"==typeof n)return r(n,t);var e=Object.prototype.toString.call(n).slice(8,-1);return"Object"===e&&n.constructor&&(e=n.constructor.name),"Map"===e||"Set"===e?Array.from(n):"Arguments"===e||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(e)?r(n,t):void 0}}(n))||t&&n&&"number"==typeof n.length){e&&(n=e);var i=0;return function(){return i>=n.length?{done:!0}:{done:!1,value:n[i++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}return(e=n[Symbol.iterator]()).next.bind(e)}try{self["workbox:core:5.1.4"]&&_()}catch(n){}var i=function(){var n=this;this.promise=new Promise((function(t,r){n.resolve=t,n.reject=r}))};function o(n,t){var r=location.href;return new URL(n,r).href===new URL(t,r).href}var u=function(n,t){this.type=n,Object.assign(this,t)};function a(n,t,r){return r?t?t(n):n:(n&&n.then||(n=Promise.resolve(n)),t?n.then(t):n)}function c(){}var f=function(r){var e,c;function f(n,t){var e,c;return void 0===t&&(t={}),(e=r.call(this)||this).t={},e.i=0,e.o=new i,e.u=new i,e.s=new i,e.v=0,e.h=new Set,e.l=function(){var n=e.m,t=n.installing;e.i>0||!o(t.scriptURL,e.g)||performance.now()>e.v+6e4?(e.p=t,n.removeEventListener("updatefound",e.l)):(e.P=t,e.h.add(t),e.o.resolve(t)),++e.i,t.addEventListener("statechange",e.S)},e.S=function(n){var t=e.m,r=n.target,i=r.state,o=r===e.p,a=o?"external":"",c={sw:r,originalEvent:n};!o&&e.j&&(c.isUpdate=!0),e.dispatchEvent(new u(a+i,c)),"installed"===i?e.A=self.setTimeout((function(){"installed"===i&&t.waiting===r&&e.dispatchEvent(new u(a+"waiting",c))}),200):"activating"===i&&(clearTimeout(e.A),o||e.u.resolve(r))},e.O=function(n){var t=e.P;t===navigator.serviceWorker.controller&&(e.dispatchEvent(new u("controlling",{sw:t,originalEvent:n,isUpdate:e.j})),e.s.resolve(t))},e.U=(c=function(n){var t=n.data,r=n.source;return a(e.getSW(),(function(){e.h.has(r)&&e.dispatchEvent(new u("message",{data:t,sw:r,originalEvent:n}))}))},function(){for(var n=[],t=0;t<arguments.length;t++)n[t]=arguments[t];try{return Promise.resolve(c.apply(this,n))}catch(n){return Promise.reject(n)}}),e.g=n,e.t=t,navigator.serviceWorker.addEventListener("message",e.U),e}c=r,(e=f).prototype=Object.create(c.prototype),e.prototype.constructor=e,e.__proto__=c;var v,h,l,m=f.prototype;return m.register=function(n){var t=(void 0===n?{}:n).immediate,r=void 0!==t&&t;try{var e=this;return function(n,t){var r=n();if(r&&r.then)return r.then(t);return t(r)}((function(){if(!r&&"complete"!==document.readyState)return s(new Promise((function(n){return window.addEventListener("load",n)})))}),(function(){return e.j=Boolean(navigator.serviceWorker.controller),e.I=e.M(),a(e.R(),(function(n){e.m=n,e.I&&(e.P=e.I,e.u.resolve(e.I),e.s.resolve(e.I),e.I.addEventListener("statechange",e.S,{once:!0}));var t=e.m.waiting;return t&&o(t.scriptURL,e.g)&&(e.P=t,Promise.resolve().then((function(){e.dispatchEvent(new u("waiting",{sw:t,wasWaitingBeforeRegister:!0}))})).then((function(){}))),e.P&&(e.o.resolve(e.P),e.h.add(e.P)),e.m.addEventListener("updatefound",e.l),navigator.serviceWorker.addEventListener("controllerchange",e.O,{once:!0}),e.m}))}))}catch(n){return Promise.reject(n)}},m.update=function(){try{return this.m?s(this.m.update()):void 0}catch(n){return Promise.reject(n)}},m.getSW=function(){try{return void 0!==this.P?this.P:this.o.promise}catch(n){return Promise.reject(n)}},m.messageSW=function(t){try{return a(this.getSW(),(function(r){return n(r,t)}))}catch(n){return Promise.reject(n)}},m.M=function(){var n=navigator.serviceWorker.controller;return n&&o(n.scriptURL,this.g)?n:void 0},m.R=function(){try{var n=this;return function(n,t){try{var r=n()}catch(n){return t(n)}if(r&&r.then)return r.then(void 0,t);return r}((function(){return a(navigator.serviceWorker.register(n.g,n.t),(function(t){return n.v=performance.now(),t}))}),(function(n){throw n}))}catch(n){return Promise.reject(n)}},v=f,(h=[{key:"active",get:function(){return this.u.promise}},{key:"controlling",get:function(){return this.s.promise}}])&&t(v.prototype,h),l&&t(v,l),f}(function(){function n(){this.k=new Map}var t=n.prototype;return t.addEventListener=function(n,t){this.B(n).add(t)},t.removeEventListener=function(n,t){this.B(n).delete(t)},t.dispatchEvent=function(n){n.target=this;for(var t,r=e(this.B(n.type));!(t=r()).done;){(0,t.value)(n)}},t.B=function(n){return this.k.has(n)||this.kLine truncated
//# sourceMappingURL=workbox-window.prod.es5.mjs.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-window.prod.es5.mjs","sources":["../_version.js","../messageSW.js","../../workbox-core/_version.js","../../workbox-core/_private/Deferred.js","../utils/urlsMatch.js","../utils/WorkboxEvent.js","../Workbox.js","../../workbox-core/_private/dontWaitFor.js","../utils/WorkboxEventTarget.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:window:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport './_version.js';\n/**\n * Sends a data object to a service worker via `postMessage` and resolves with\n * a response (if any).\n *\n * A response can be set in a message handler in the service worker by\n * calling `event.ports[0].postMessage(...)`, which will resolve the promise\n * returned by `messageSW()`. If no response is set, the promise will not\n * resolve.\n *\n * @param {ServiceWorker} sw The service worker to send the message to.\n * @param {Object} data An object to send to the service worker.\n * @return {Promise<Object|undefined>}\n * @memberof module:workbox-window\n */\nfunction messageSW(sw, data) {\n return new Promise((resolve) => {\n const messageChannel = new MessageChannel();\n messageChannel.port1.onmessage = (event) => {\n resolve(event.data);\n };\n sw.postMessage(data, [messageChannel.port2]);\n });\n}\nexport { messageSW };\n","\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:core:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * The Deferred class composes Promises in a way that allows for them to be\n * resolved or rejected from outside the constructor. In most cases promises\n * should be used directly, but Deferreds can be necessary when the logic to\n * resolve a promise must be separate.\n *\n * @private\n */\nclass Deferred {\n /**\n * Creates a promise and exposes its resolve and reject functions as methods.\n */\n constructor() {\n this.promise = new Promise((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n }\n}\nexport { Deferred };\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * Returns true if two URLs have the same `.href` property. The URLS can be\n * relative, and if they are the current location href is used to resolve URLs.\n *\n * @private\n * @param {string} url1\n * @param {string} url2\n * @return {boolean}\n */\nexport function urlsMatch(url1, url2) {\n const { href } = location;\n return new URL(url1, href).href === new URL(url2, href).href;\n}\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * A minimal `Event` subclass shim.\n * This doesn't *actually* subclass `Event` because not all browsers support\n * constructable `EventTarget`, and using a real `Event` will error.\n * @private\n */\nexport class WorkboxEvent {\n constructor(type, props) {\n this.type = type;\n Object.assign(this, props);\n }\n}\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { Deferred } from 'workbox-core/_private/Deferred.js';\nimport { dontWaitFor } from 'workbox-core/_private/dontWaitFor.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { messageSW } from './messageSW.js';\nimport { WorkboxEventTarget } from './utils/WorkboxEventTarget.js';\nimport { urlsMatch } from './utils/urlsMatch.js';\nimport { WorkboxEvent } from './utils/WorkboxEvent.js';\nimport './_version.js';\n// The time a SW must be in the waiting phase before we can conclude\n// `skipWaiting()` wasn't called. This 200 amount wasn't scientifically\n// chosen, but it seems to avoid false positives in my testing.\nconst WAITING_TIMEOUT_DURATION = 200;\n// The amount of time after a registration that we can reasonably conclude\n// that the registration didn't trigger an update.\nconst REGISTRATION_TIMEOUT_DURATION = 60000;\n/**\n * A class to aid in handling service worker registration, updates, and\n * reacting to service worker lifecycle events.\n *\n * @fires [message]{@link module:workbox-window.Workbox#message}\n * @fires [installed]{@link module:workbox-window.Workbox#installed}\n * @fires [waiting]{@linLine truncated
@@ -0,0 +1,2 @@
try{self["workbox:window:5.1.4"]&&_()}catch(t){}function t(t,s){return new Promise(i=>{const e=new MessageChannel;e.port1.onmessage=t=>{i(t.data)},t.postMessage(s,[e.port2])})}try{self["workbox:core:5.1.4"]&&_()}catch(t){}class s{constructor(){this.promise=new Promise((t,s)=>{this.resolve=t,this.reject=s})}}function i(t,s){const{href:i}=location;return new URL(t,i).href===new URL(s,i).href}class e{constructor(t,s){this.type=t,Object.assign(this,s)}}class h extends class{constructor(){this.t=new Map}addEventListener(t,s){this.s(t).add(s)}removeEventListener(t,s){this.s(t).delete(s)}dispatchEvent(t){t.target=this;const s=this.s(t.type);for(const i of s)i(t)}s(t){return this.t.has(t)||this.t.set(t,new Set),this.t.get(t)}}{constructor(t,h={}){super(),this.i={},this.h=0,this.o=new s,this.g=new s,this.l=new s,this.u=0,this.v=new Set,this.m=()=>{const t=this.p,s=t.installing;this.h>0||!i(s.scriptURL,this.S)||performance.now()>this.u+6e4?(this.L=s,t.removeEventListener("updatefound",this.m)):(this._=s,this.v.add(s),this.o.resolve(s)),++this.h,s.addEventListener("statechange",this.P)},this.P=t=>{const s=this.p,i=t.target,{state:h}=i,n=i===this.L,a=n?"external":"",r={sw:i,originalEvent:t};!n&&this.W&&(r.isUpdate=!0),this.dispatchEvent(new e(a+h,r)),"installed"===h?this.B=self.setTimeout(()=>{"installed"===h&&s.waiting===i&&this.dispatchEvent(new e(a+"waiting",r))},200):"activating"===h&&(clearTimeout(this.B),n||this.g.resolve(i))},this.C=t=>{const s=this._;s===navigator.serviceWorker.controller&&(this.dispatchEvent(new e("controlling",{sw:s,originalEvent:t,isUpdate:this.W})),this.l.resolve(s))},this.R=async t=>{const{data:s,source:i}=t;await this.getSW(),this.v.has(i)&&this.dispatchEvent(new e("message",{data:s,sw:i,originalEvent:t}))},this.S=t,this.i=h,navigator.serviceWorker.addEventListener("message",this.R)}async register({immediate:t=!1}={}){t||"complete"===document.readyState||await new Promise(t=>window.addEventListener("load",t)),this.W=Boolean(navigator.serviceWorker.controller),this.U=this.M(),this.p=await this.T(),this.U&&(this._=this.U,this.g.resolve(this.U),this.l.resolve(this.U),this.U.addEventListener("statechange",this.P,{once:!0}));const s=this.p.waiting;return s&&i(s.scriptURL,this.S)&&(this._=s,Promise.resolve().then(()=>{this.dispatchEvent(new e("waiting",{sw:s,wasWaitingBeforeRegister:!0}))}).then(()=>{})),this._&&(this.o.resolve(this._),this.v.add(this._)),this.p.addEventListener("updatefound",this.m),navigator.serviceWorker.addEventListener("controllerchange",this.C,{once:!0}),this.p}async update(){this.p&&await this.p.update()}get active(){return this.g.promise}get controlling(){return this.l.promise}async getSW(){return void 0!==this._?this._:this.o.promise}async messageSW(s){return t(await this.getSW(),s)}M(){const t=navigator.serviceWorker.controller;return t&&i(t.scriptURL,this.S)?t:void 0}async T(){try{const t=await navigator.serviceWorker.register(this.S,this.i);return this.u=performance.now(),t}catch(t){throw t}}}export{h as Workbox,t as messageSW};
//# sourceMappingURL=workbox-window.prod.mjs.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-window.prod.mjs","sources":["../_version.js","../messageSW.js","../../workbox-core/_version.js","../../workbox-core/_private/Deferred.js","../utils/urlsMatch.js","../utils/WorkboxEvent.js","../Workbox.js","../utils/WorkboxEventTarget.js","../../workbox-core/_private/dontWaitFor.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:window:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport './_version.js';\n/**\n * Sends a data object to a service worker via `postMessage` and resolves with\n * a response (if any).\n *\n * A response can be set in a message handler in the service worker by\n * calling `event.ports[0].postMessage(...)`, which will resolve the promise\n * returned by `messageSW()`. If no response is set, the promise will not\n * resolve.\n *\n * @param {ServiceWorker} sw The service worker to send the message to.\n * @param {Object} data An object to send to the service worker.\n * @return {Promise<Object|undefined>}\n * @memberof module:workbox-window\n */\nfunction messageSW(sw, data) {\n return new Promise((resolve) => {\n const messageChannel = new MessageChannel();\n messageChannel.port1.onmessage = (event) => {\n resolve(event.data);\n };\n sw.postMessage(data, [messageChannel.port2]);\n });\n}\nexport { messageSW };\n","\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:core:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * The Deferred class composes Promises in a way that allows for them to be\n * resolved or rejected from outside the constructor. In most cases promises\n * should be used directly, but Deferreds can be necessary when the logic to\n * resolve a promise must be separate.\n *\n * @private\n */\nclass Deferred {\n /**\n * Creates a promise and exposes its resolve and reject functions as methods.\n */\n constructor() {\n this.promise = new Promise((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n }\n}\nexport { Deferred };\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * Returns true if two URLs have the same `.href` property. The URLS can be\n * relative, and if they are the current location href is used to resolve URLs.\n *\n * @private\n * @param {string} url1\n * @param {string} url2\n * @return {boolean}\n */\nexport function urlsMatch(url1, url2) {\n const { href } = location;\n return new URL(url1, href).href === new URL(url2, href).href;\n}\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * A minimal `Event` subclass shim.\n * This doesn't *actually* subclass `Event` because not all browsers support\n * constructable `EventTarget`, and using a real `Event` will error.\n * @private\n */\nexport class WorkboxEvent {\n constructor(type, props) {\n this.type = type;\n Object.assign(this, props);\n }\n}\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { Deferred } from 'workbox-core/_private/Deferred.js';\nimport { dontWaitFor } from 'workbox-core/_private/dontWaitFor.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { messageSW } from './messageSW.js';\nimport { WorkboxEventTarget } from './utils/WorkboxEventTarget.js';\nimport { urlsMatch } from './utils/urlsMatch.js';\nimport { WorkboxEvent } from './utils/WorkboxEvent.js';\nimport './_version.js';\n// The time a SW must be in the waiting phase before we can conclude\n// `skipWaiting()` wasn't called. This 200 amount wasn't scientifically\n// chosen, but it seems to avoid false positives in my testing.\nconst WAITING_TIMEOUT_DURATION = 200;\n// The amount of time after a registration that we can reasonably conclude\n// that the registration didn't trigger an update.\nconst REGISTRATION_TIMEOUT_DURATION = 60000;\n/**\n * A class to aid in handling service worker registration, updates, and\n * reacting to service worker lifecycle events.\n *\n * @fires [message]{@link module:workbox-window.Workbox#message}\n * @fires [installed]{@link module:workbox-window.Workbox#installed}\n * @fires [waiting]{@link moLine truncated
@@ -0,0 +1,2 @@
!function(n,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((n=n||self).workbox={})}(this,(function(n){"use strict";try{self["workbox:window:5.1.4"]&&_()}catch(n){}function t(n,t){return new Promise((function(r){var e=new MessageChannel;e.port1.onmessage=function(n){r(n.data)},n.postMessage(t,[e.port2])}))}function r(n,t){for(var r=0;r<t.length;r++){var e=t[r];e.enumerable=e.enumerable||!1,e.configurable=!0,"value"in e&&(e.writable=!0),Object.defineProperty(n,e.key,e)}}function e(n,t){(null==t||t>n.length)&&(t=n.length);for(var r=0,e=new Array(t);r<t;r++)e[r]=n[r];return e}function i(n,t){var r;if("undefined"==typeof Symbol||null==n[Symbol.iterator]){if(Array.isArray(n)||(r=function(n,t){if(n){if("string"==typeof n)return e(n,t);var r=Object.prototype.toString.call(n).slice(8,-1);return"Object"===r&&n.constructor&&(r=n.constructor.name),"Map"===r||"Set"===r?Array.from(n):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?e(n,t):void 0}}(n))||t&&n&&"number"==typeof n.length){r&&(n=r);var i=0;return function(){return i>=n.length?{done:!0}:{done:!1,value:n[i++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}return(r=n[Symbol.iterator]()).next.bind(r)}try{self["workbox:core:5.1.4"]&&_()}catch(n){}var o=function(){var n=this;this.promise=new Promise((function(t,r){n.resolve=t,n.reject=r}))};function u(n,t){var r=location.href;return new URL(n,r).href===new URL(t,r).href}var a=function(n,t){this.type=n,Object.assign(this,t)};function c(n,t,r){return r?t?t(n):n:(n&&n.then||(n=Promise.resolve(n)),t?n.then(t):n)}function f(){}var s=function(n){var e,i;function f(t,r){var e,i;return void 0===r&&(r={}),(e=n.call(this)||this).t={},e.i=0,e.o=new o,e.u=new o,e.s=new o,e.v=0,e.h=new Set,e.l=function(){var n=e.m,t=n.installing;e.i>0||!u(t.scriptURL,e.g)||performance.now()>e.v+6e4?(e.p=t,n.removeEventListener("updatefound",e.l)):(e.P=t,e.h.add(t),e.o.resolve(t)),++e.i,t.addEventListener("statechange",e.j)},e.j=function(n){var t=e.m,r=n.target,i=r.state,o=r===e.p,u=o?"external":"",c={sw:r,originalEvent:n};!o&&e.S&&(c.isUpdate=!0),e.dispatchEvent(new a(u+i,c)),"installed"===i?e.O=self.setTimeout((function(){"installed"===i&&t.waiting===r&&e.dispatchEvent(new a(u+"waiting",c))}),200):"activating"===i&&(clearTimeout(e.O),o||e.u.resolve(r))},e.A=function(n){var t=e.P;t===navigator.serviceWorker.controller&&(e.dispatchEvent(new a("controlling",{sw:t,originalEvent:n,isUpdate:e.S})),e.s.resolve(t))},e.M=(i=function(n){var t=n.data,r=n.source;return c(e.getSW(),(function(){e.h.has(r)&&e.dispatchEvent(new a("message",{data:t,sw:r,originalEvent:n}))}))},function(){for(var n=[],t=0;t<arguments.length;t++)n[t]=arguments[t];try{return Promise.resolve(i.apply(this,n))}catch(n){return Promise.reject(n)}}),e.g=t,e.t=r,navigator.serviceWorker.addEventListener("message",e.M),e}i=n,(e=f).prototype=Object.create(i.prototype),e.prototype.constructor=e,e.__proto__=i;var s,h,l,d=f.prototype;return d.register=function(n){var t=(void 0===n?{}:n).immediate,r=void 0!==t&&t;try{var e=this;return function(n,t){var r=n();if(r&&r.then)return r.then(t);return t(r)}((function(){if(!r&&"complete"!==document.readyState)return v(new Promise((function(n){return window.addEventListener("load",n)})))}),(function(){return e.S=Boolean(navigator.serviceWorker.controller),e.U=e._(),c(e.I(),(function(n){e.m=n,e.U&&(e.P=e.U,e.u.resolve(e.U),e.s.resolve(e.U),e.U.addEventListener("statechange",e.j,{once:!0}));var t=e.m.waiting;return t&&u(t.scriptURL,e.g)&&(e.P=t,Promise.resolve().then((function(){e.dispatchEvent(new a("waiting",{sw:t,wasWaitingBeforeRegister:!0}))})).then((function(){}))),e.P&&(e.o.resolve(e.P),e.h.add(e.P)),e.m.addEventListener("updatefound",e.l),navigator.serviceWorker.addEventListener("controllerchange",e.A,{once:!0}),e.m}))}))}catch(n){return Promise.reject(n)}},d.update=function(){try{return this.m?v(this.m.update()):void 0}catch(n){return Promise.reject(n)}},d.getSW=function(){try{return void 0!==this.P?this.P:this.o.promise}catch(n){return Promise.reject(n)}},d.messageSW=function(n){try{return c(this.getSW(),(function(r){return t(r,n)}))}catch(n){return Promise.reject(n)}},d._=function(){var n=navigator.serviceWorker.controller;return n&&u(n.scriptURL,this.g)?n:void 0},d.I=function(){try{var n=this;return function(n,t){try{var r=n()}catch(n){return t(n)}if(r&&r.then)return r.then(void 0,t);return r}((function(){return c(navigator.serviceWorker.register(n.g,n.t),(function(t){return n.v=performance.now(),t}))}),(function(n){throw n}))}catch(n){return Promise.reject(n)}},s=f,(h=[{key:"active",get:function(){return this.u.promise}},{key:"controlling",get:function(){return this.s.promise}}])&&r(s.prototype,h),l&&r(s,l),f}(function(){function n(){this.R=new Map}var t=n.prototype;return t.addEventListener=function(n,t){this.k(n).add(t)},t.removeELine truncated
//# sourceMappingURL=workbox-window.prod.umd.js.map
@@ -0,0 +1 @@
{"version":3,"file":"workbox-window.prod.umd.js","sources":["../_version.js","../messageSW.js","../../workbox-core/_version.js","../../workbox-core/_private/Deferred.js","../utils/urlsMatch.js","../utils/WorkboxEvent.js","../Workbox.js","../../workbox-core/_private/dontWaitFor.js","../utils/WorkboxEventTarget.js"],"sourcesContent":["\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:window:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport './_version.js';\n/**\n * Sends a data object to a service worker via `postMessage` and resolves with\n * a response (if any).\n *\n * A response can be set in a message handler in the service worker by\n * calling `event.ports[0].postMessage(...)`, which will resolve the promise\n * returned by `messageSW()`. If no response is set, the promise will not\n * resolve.\n *\n * @param {ServiceWorker} sw The service worker to send the message to.\n * @param {Object} data An object to send to the service worker.\n * @return {Promise<Object|undefined>}\n * @memberof module:workbox-window\n */\nfunction messageSW(sw, data) {\n return new Promise((resolve) => {\n const messageChannel = new MessageChannel();\n messageChannel.port1.onmessage = (event) => {\n resolve(event.data);\n };\n sw.postMessage(data, [messageChannel.port2]);\n });\n}\nexport { messageSW };\n","\"use strict\";\n// @ts-ignore\ntry {\n self['workbox:core:5.1.4'] && _();\n}\ncatch (e) { }\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * The Deferred class composes Promises in a way that allows for them to be\n * resolved or rejected from outside the constructor. In most cases promises\n * should be used directly, but Deferreds can be necessary when the logic to\n * resolve a promise must be separate.\n *\n * @private\n */\nclass Deferred {\n /**\n * Creates a promise and exposes its resolve and reject functions as methods.\n */\n constructor() {\n this.promise = new Promise((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n }\n}\nexport { Deferred };\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * Returns true if two URLs have the same `.href` property. The URLS can be\n * relative, and if they are the current location href is used to resolve URLs.\n *\n * @private\n * @param {string} url1\n * @param {string} url2\n * @return {boolean}\n */\nexport function urlsMatch(url1, url2) {\n const { href } = location;\n return new URL(url1, href).href === new URL(url2, href).href;\n}\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport '../_version.js';\n/**\n * A minimal `Event` subclass shim.\n * This doesn't *actually* subclass `Event` because not all browsers support\n * constructable `EventTarget`, and using a real `Event` will error.\n * @private\n */\nexport class WorkboxEvent {\n constructor(type, props) {\n this.type = type;\n Object.assign(this, props);\n }\n}\n","/*\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 LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\nimport { Deferred } from 'workbox-core/_private/Deferred.js';\nimport { dontWaitFor } from 'workbox-core/_private/dontWaitFor.js';\nimport { logger } from 'workbox-core/_private/logger.js';\nimport { messageSW } from './messageSW.js';\nimport { WorkboxEventTarget } from './utils/WorkboxEventTarget.js';\nimport { urlsMatch } from './utils/urlsMatch.js';\nimport { WorkboxEvent } from './utils/WorkboxEvent.js';\nimport './_version.js';\n// The time a SW must be in the waiting phase before we can conclude\n// `skipWaiting()` wasn't called. This 200 amount wasn't scientifically\n// chosen, but it seems to avoid false positives in my testing.\nconst WAITING_TIMEOUT_DURATION = 200;\n// The amount of time after a registration that we can reasonably conclude\n// that the registration didn't trigger an update.\nconst REGISTRATION_TIMEOUT_DURATION = 60000;\n/**\n * A class to aid in handling service worker registration, updates, and\n * reacting to service worker lifecycle events.\n *\n * @fires [message]{@link module:workbox-window.Workbox#message}\n * @fires [installed]{@link module:workbox-window.Workbox#installed}\n * @fires [waiting]{@linkLine truncated
+17
View File
@@ -1,7 +1,24 @@
// https://developers.google.com/web/tools/workbox/guides/troubleshoot-and-debug
//
// Uncomment the 'Embedded version' and use the 'Internet version' if
// the internet version is preferred. Make sure to use the correct
// version though.
//
// Embedded version
importScripts('/third_party/workbox/workbox-v5.1.4/workbox-sw.js');
workbox.setConfig({
modulePathPrefix: '/third_party/workbox/workbox-v5.1.4/',
});
// Internet version
/*
importScripts(
'https://storage.googleapis.com/workbox-cdn/releases/5.0.0-beta.1/workbox-sw.js'
);
*/
// Install newest
// https://developers.google.com/web/tools/workbox/modules/workbox-core
+4 -9
View File
@@ -6940,20 +6940,15 @@ dicom-parser@^1.8.3:
resolved "https://registry.yarnpkg.com/dicom-parser/-/dicom-parser-1.8.3.tgz#6e4b862898112304db30143147562011c1ce6a4d"
integrity sha512-CMeUr+jea7Ml70N+/Z5Pd2MYtvLp6IU+TnvdLe6VRVKzZuTeYLYyuAQa9R+sFK4v4N39hig+hKHN+Wfi9sQ6GA==
dicomweb-client@^0.4.4:
version "0.4.4"
resolved "https://registry.yarnpkg.com/dicomweb-client/-/dicomweb-client-0.4.4.tgz#0ca0c7706556f3114330a3c40946ee66808148e4"
integrity sha512-5S7wLYxQgHnOyEgR1zlZlt79IjzOk+YDB/Jjzte6ijRZsAoj9RUiIZcsTyxvBD9gLMYs/954n2kYHdbz83Xbtw==
dicomweb-client@^0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/dicomweb-client/-/dicomweb-client-0.5.2.tgz#aa5a4a6a5044b0702bb0a8a2662c86cd16901951"
integrity sha512-e11n2+g7HfBuMyopWq76W11eSZJ707g4U1XiO8URA+23aoe0g1kGAtlPB29NKXl7zX7RznTJ7wfRBxFkW6EJDA==
dicomweb-client@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/dicomweb-client/-/dicomweb-client-0.6.0.tgz#5e35ada52fe0155af1cc1f0e84f9c7f76477f92d"
integrity sha512-VAkBg4W6odIo2XsFxqjN/rptd7bQ8oHpRuKH5d46E9BUIPzRschazE8Dx1xg7/l3N3f1M70jB7yJ339arAXiDQ==
dicomweb-client@^0.8.1:
version "0.8.1"
resolved "https://registry.yarnpkg.com/dicomweb-client/-/dicomweb-client-0.8.1.tgz#12bdf0e9698bcf82730f38829ac30158164bb3fd"
integrity sha512-5EbK8epfSuonSnCW3nr2tkA1CcO1aFT3grEVvKXqv0tVyHsBvbEcEmBcPEbu1m/cF6t7+3uQRLOQ4dw4CodxFg==
diff-sequences@^24.9.0:
version "24.9.0"