{“version”:3,“file”:“workbox-expiration.prod.js”,“sources”:,“sourcesContent”:[“"use strict";n// @ts-ignorentry {n self && _();n}ncatch (e) { }n”,“/*n Copyright 2018 Google LLCnn Use of this source code is governed by an MIT-stylen license that can be found in the LICENSE file or atn 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 * @privaten */nclass CacheTimestampsModel {n /**n *n * @param {string} cacheNamen *n * @privaten */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} eventn *n * @privaten */n _handleUpgrade(event) {n const db = event.target.result;n // TODO(philipwalton): EdgeHTML doesn't support arrays as a keyPath, so wen // have to use the `id` keyPath here and create our own values (an // concatenation of `url + cacheName`) instead of simply usingn // `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 cann // 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} urln * @param {number} timestampn *n * @privaten */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 oncen // Edge switches to Chromium and all browsers we support work withn // 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} urln * @return {number}n *n * @privaten */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 ton * oldest) and removes entries once either `maxCount` is reached or then * entry's timestamp is less than `minTimestamp`.n *n * @param {number} minTimestampn * @param {number} maxCountn * @return {Array<string>}n *n * @privaten */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, wen // 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 orn // 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 then // entry right here, but doing so causes an iterationn // bug in Safari stable (fixed in TP). Instead we cann // store the keys of the entries to delete, and thenn // delete the separate transactions.n // github.com/GoogleChrome/workbox/issues/1978n // cursor.delete();n // We only need to return the URL, not the whole entry.n entriesToDelete.push(cursor.value);n }n else {n entriesNotDeletedCount++;n }n }n cursor.continue();n }n else {n done(entriesToDelete);n }n };n });n // TODO(philipwalton): once the Safari bug in the following issue is fixed,n // we should be able to remove this loop and do the entry deletion in then // cursor loop above:n // github.com/GoogleChrome/workbox/issues/1978n const urlsDeleted = [];n for (const entry of entriesToDelete) {n await this._db.delete(OBJECT_STORE_NAME, entry.id);n urlsDeleted.push(entry.url);n }n return urlsDeleted;n }n /**n * Takes a URL and returns an ID that will be unique in the object store.n *n * @param {string} urln * @return {string}n *n * @privaten */n _getId(url) {n // Creating an ID from the URL and cache name won't be necessary oncen // Edge switches to Chromium and all browsers we support work withn // array keyPaths.n return this._cacheName + '|' + normalizeURL(url);n }n}nexport { CacheTimestampsModel };n”,“/*n Copyright 2018 Google LLCnn Use of this source code is governed by an MIT-stylen license that can be found in the LICENSE file or atn opensource.org/licenses/MIT.n*/nimport { assert } from 'workbox-core/_private/assert.js';nimport { dontWaitFor } from 'workbox-core/_private/dontWaitFor.js';nimport { logger } from 'workbox-core/_private/logger.js';nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';nimport { CacheTimestampsModel } from './models/CacheTimestampsModel.js';nimport './_version.js';n/**n * The `CacheExpiration` class allows you define an expiration and / orn * limit on the number of responses stored in an * [`Cache`](developer.mozilla.org/en-US/docs/Web/API/Cache).n *n * @memberof module:workbox-expirationn */nclass CacheExpiration {n /**n * To construct a new CacheExpiration instance you must provide at leastn * one of the `config` properties.n *n * @param {string} cacheName Name of the cache to apply restrictions to.n * @param {Object} confign * @param {number} [config.maxEntries] The maximum number of entries to cache.n * Entries used the least will be removed as the maximum is reached.n * @param {number} [config.maxAgeSeconds] The maximum age of an entry beforen * it's treated as stale and removed.n */n constructor(cacheName, config = {}) {n this._isRunning = false;n this._rerunRequested = false;n if (process.env.NODE_ENV !== 'production') {n assert.isType(cacheName, 'string', {n moduleName: 'workbox-expiration',n className: 'CacheExpiration',n funcName: 'constructor',n paramName: 'cacheName',n });n if (!(config.maxEntries || config.maxAgeSeconds)) {n throw new WorkboxError('max-entries-or-age-required', {n moduleName: 'workbox-expiration',n className: 'CacheExpiration',n funcName: 'constructor',n });n }n if (config.maxEntries) {n assert.isType(config.maxEntries, 'number', {n moduleName: 'workbox-expiration',n className: 'CacheExpiration',n funcName: 'constructor',n paramName: 'config.maxEntries',n });n // TODO: Assert is positiven }n if (config.maxAgeSeconds) {n assert.isType(config.maxAgeSeconds, 'number', {n moduleName: 'workbox-expiration',n className: 'CacheExpiration',n funcName: 'constructor',n paramName: 'config.maxAgeSeconds',n });n // TODO: Assert is positiven }n }n this._maxEntries = config.maxEntries;n this._maxAgeSeconds = config.maxAgeSeconds;n this._cacheName = cacheName;n this._timestampModel = new CacheTimestampsModel(cacheName);n }n /**n * Expires entries for the given cache and given criteria.n */n async expireEntries() {n if (this._isRunning) {n this._rerunRequested = true;n return;n }n this._isRunning = true;n const minTimestamp = this._maxAgeSeconds ?n Date.now() - (this._maxAgeSeconds * 1000) : 0;n const urlsExpired = await this._timestampModel.expireEntries(minTimestamp, this._maxEntries);n // Delete URLs from the cachen const cache = await self.caches.open(this._cacheName);n for (const url of urlsExpired) {n await cache.delete(url);n }n if (process.env.NODE_ENV !== 'production') {n if (urlsExpired.length > 0) {n logger.groupCollapsed(`Expired ${urlsExpired.length} ` +n `${urlsExpired.length === 1 ? 'entry' : 'entries'} and removed ` +n `${urlsExpired.length === 1 ? 'it' : 'them'} from the ` +n `'${this._cacheName}' cache.`);n logger.log(`Expired the following ${urlsExpired.length === 1 ?n 'URL' : 'URLs'}:`);n urlsExpired.forEach((url) => logger.log(` ${url}`));n logger.groupEnd();n }n else {n logger.debug(`Cache expiration ran and found no entries to remove.`);n }n }n this._isRunning = false;n if (this._rerunRequested) {n this._rerunRequested = false;n dontWaitFor(this.expireEntries());n }n }n /**n * Update the timestamp for the given URL. This ensures the whenn * removing entries based on maximum entries, most recently usedn * is accurate or when expiring, the timestamp is up-to-date.n *n * @param {string} urln */n async updateTimestamp(url) {n if (process.env.NODE_ENV !== 'production') {n assert.isType(url, 'string', {n moduleName: 'workbox-expiration',n className: 'CacheExpiration',n funcName: 'updateTimestamp',n paramName: 'url',n });n }n await this._timestampModel.setTimestamp(url, Date.now());n }n /**n * Can be used to check if a URL has expired or not before it's used.n *n * This requires a look up from IndexedDB, so can be slow.n *n * Note: This method will not remove the cached entry, calln * `expireEntries()` to remove indexedDB and Cache entries.n *n * @param {string} urln * @return {boolean}n */n async isURLExpired(url) {n if (!this._maxAgeSeconds) {n if (process.env.NODE_ENV !== 'production') {n throw new WorkboxError(`expired-test-without-max-age`, {n methodName: 'isURLExpired',n paramName: 'maxAgeSeconds',n });n }n return false;n }n else {n const timestamp = await this._timestampModel.getTimestamp(url);n const expireOlderThan = Date.now() - (this._maxAgeSeconds * 1000);n return (timestamp < expireOlderThan);n }n }n /**n * Removes the IndexedDB object store used to keep track of cache expirationn * metadata.n */n async delete() {n // Make sure we don't attempt another rerun if we're called in the middle ofn // a cache expiration.n this._rerunRequested = false;n await this._timestampModel.expireEntries(Infinity); // Expires all.n }n}nexport { CacheExpiration };n”,“/*n Copyright 2018 Google LLCnn Use of this source code is governed by an MIT-stylen license that can be found in the LICENSE file or atn opensource.org/licenses/MIT.n*/nimport { assert } from 'workbox-core/_private/assert.js';nimport { cacheNames } from 'workbox-core/_private/cacheNames.js';nimport { dontWaitFor } from 'workbox-core/_private/dontWaitFor.js';nimport { getFriendlyURL } from 'workbox-core/_private/getFriendlyURL.js';nimport { logger } from 'workbox-core/_private/logger.js';nimport { registerQuotaErrorCallback } from 'workbox-core/registerQuotaErrorCallback.js';nimport { WorkboxError } from 'workbox-core/_private/WorkboxError.js';nimport { CacheExpiration } from './CacheExpiration.js';nimport './_version.js';n/**n * This plugin can be used in the Workbox APIs to regularly enforce an * limit on the age and / or the number of cached requests.n *n * Whenever a cached request is used or updated, this plugin will lookn * at the used Cache and remove any old or extra requests.n *n * When using `maxAgeSeconds`, requests may be used once after expiringn * because the expiration clean up will not have occurred until after then * cached request has been used. If the request has a "Date" header, thenn * a light weight expiration check is performed and the request will not ben * used immediately.n *n * When using `maxEntries`, the entry least-recently requested will be removedn * from the cache first.n *n * @memberof module:workbox-expirationn */nclass ExpirationPlugin {n /**n * @param {Object} confign * @param {number} [config.maxEntries] The maximum number of entries to cache.n * Entries used the least will be removed as the maximum is reached.n * @param {number} [config.maxAgeSeconds] The maximum age of an entry beforen * it's treated as stale and removed.n * @param {boolean} [config.purgeOnQuotaError] Whether to opt this cache in ton * automatic deletion if the available storage quota has been exceeded.n */n constructor(config = {}) {n /**n * A "lifecycle" callback that will be triggered automatically by then * `workbox-strategies` handlers when a `Response` is about to be returnedn * from a [Cache](developer.mozilla.org/en-US/docs/Web/API/Cache) ton * the handler. It allows the `Response` to be inspected for freshness andn * prevents it from being used if the `Response`'s `Date` header value isn * older than the configured `maxAgeSeconds`.n *n * @param {Object} optionsn * @param {string} options.cacheName Name of the cache the response is in.n * @param {Response} options.cachedResponse The `Response` object that's beenn * read from a cache and whose freshness should be checked.n * @return {Response} Either the `cachedResponse`, if it'sn * fresh, or `null` if the `Response` is older than `maxAgeSeconds`.n *n * @privaten */n this.cachedResponseWillBeUsed = async ({ event, request, cacheName, cachedResponse }) => {n if (!cachedResponse) {n return null;n }n const isFresh = this._isResponseDateFresh(cachedResponse);n // Expire entries to ensure that even if the expiration date hasn // expired, it'll only be used once.n const cacheExpiration = this._getCacheExpiration(cacheName);n dontWaitFor(cacheExpiration.expireEntries());n // Update the metadata for the request URL to the current timestamp,n // but don't `await` it as we don't want to block the response.n const updateTimestampDone = cacheExpiration.updateTimestamp(request.url);n if (event) {n try {n event.waitUntil(updateTimestampDone);n }n catch (error) {n if (process.env.NODE_ENV !== 'production') {n // The event may not be a fetch event; only log the URL if it is.n if ('request' in event) {n logger.warn(`Unable to ensure service worker stays alive when ` +n `updating cache entry for ` +n `'${getFriendlyURL(event.request.url)}'.`);n }n }n }n }n return isFresh ? cachedResponse : null;n };n /**n * A "lifecycle" callback that will be triggered automatically by then * `workbox-strategies` handlers when an entry is added to a cache.n *n * @param {Object} optionsn * @param {string} options.cacheName Name of the cache that was updated.n * @param {string} options.request The Request for the cached entry.n *n * @privaten */n this.cacheDidUpdate = async ({ cacheName, request }) => {n if (process.env.NODE_ENV !== 'production') {n assert.isType(cacheName, 'string', {n moduleName: 'workbox-expiration',n className: 'Plugin',n funcName: 'cacheDidUpdate',n paramName: 'cacheName',n });n assert.isInstance(request, Request, {n moduleName: 'workbox-expiration',n className: 'Plugin',n funcName: 'cacheDidUpdate',n paramName: 'request',n });n }n const cacheExpiration = this._getCacheExpiration(cacheName);n await cacheExpiration.updateTimestamp(request.url);n await cacheExpiration.expireEntries();n };n if (process.env.NODE_ENV !== 'production') {n if (!(config.maxEntries || config.maxAgeSeconds)) {n throw new WorkboxError('max-entries-or-age-required', {n moduleName: 'workbox-expiration',n className: 'Plugin',n funcName: 'constructor',n });n }n if (config.maxEntries) {n assert.isType(config.maxEntries, 'number', {n moduleName: 'workbox-expiration',n className: 'Plugin',n funcName: 'constructor',n paramName: 'config.maxEntries',n });n }n if (config.maxAgeSeconds) {n assert.isType(config.maxAgeSeconds, 'number', {n moduleName: 'workbox-expiration',n className: 'Plugin',n funcName: 'constructor',n paramName: 'config.maxAgeSeconds',n });n }n }n this._config = config;n this._maxAgeSeconds = config.maxAgeSeconds;n this._cacheExpirations = new Map();n if (config.purgeOnQuotaError) {n registerQuotaErrorCallback(() => this.deleteCacheAndMetadata());n }n }n /**n * A simple helper method to return a CacheExpiration instance for a givenn * cache name.n *n * @param {string} cacheNamen * @return {CacheExpiration}n *n * @privaten */n _getCacheExpiration(cacheName) {n if (cacheName === cacheNames.getRuntimeName()) {n throw new WorkboxError('expire-custom-caches-only');n }n let cacheExpiration = this._cacheExpirations.get(cacheName);n if (!cacheExpiration) {n cacheExpiration = new CacheExpiration(cacheName, this._config);n this._cacheExpirations.set(cacheName, cacheExpiration);n }n return cacheExpiration;n }n /**n * @param {Response} cachedResponsen * @return {boolean}n *n * @privaten */n _isResponseDateFresh(cachedResponse) {n if (!this._maxAgeSeconds) {n // We aren't expiring by age, so return true, it's freshn return true;n }n // Check if the 'date' header will suffice a quick expiration check.n // See github.com/GoogleChromeLabs/sw-toolbox/issues/164 forn // discussion.n const dateHeaderTimestamp = this._getDateHeaderTimestamp(cachedResponse);n if (dateHeaderTimestamp === null) {n // Unable to parse date, so assume it's fresh.n return true;n }n // If we have a valid headerTime, then our response is fresh iff then // headerTime plus maxAgeSeconds is greater than the current time.n const now = Date.now();n return dateHeaderTimestamp >= now - (this._maxAgeSeconds * 1000);n }n /**n * This method will extract the data header and parse it into a usefuln * value.n *n * @param {Response} cachedResponsen * @return {number|null}n *n * @privaten */n _getDateHeaderTimestamp(cachedResponse) {n if (!cachedResponse.headers.has('date')) {n return null;n }n const dateHeader = cachedResponse.headers.get('date');n const parsedDate = new Date(dateHeader);n const headerTime = parsedDate.getTime();n // If the Date header was invalid for some reason, parsedDate.getTime()n // will return NaN.n if (isNaN(headerTime)) {n return null;n }n return headerTime;n }n /**n * This is a helper method that performs two operations:n *n * - Deletes all the underlying Cache instances associated with this pluginn * instance, by calling caches.delete() on your behalf.n * - Deletes the metadata from IndexedDB used to keep track of expirationn * details for each Cache instance.n *n * When using cache expiration, calling this method is preferable to callingn * `caches.delete()` directly, since this will ensure that the IndexedDBn * metadata is also cleanly removed and open IndexedDB instances are deleted.n *n * Note that if you're not using cache expiration for a given cache, callingn * `caches.delete()` and passing in the cache's name should be sufficient.n * There is no Workbox-specific method needed for cleanup in that case.n */n async deleteCacheAndMetadata() {n // Do this one at a time instead of all at once via `Promise.all()` ton // reduce the chance of inconsistency if a promise rejects.n for (const [cacheName, cacheExpiration] of this._cacheExpirations) {n await self.caches.delete(cacheName);n await cacheExpiration.delete();n }n // Reset this._cacheExpirations to its initial state.n this._cacheExpirations = new Map();n }n}nexport { ExpirationPlugin };n”],“names”:,“mappings”:“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”}