aboutsummaryrefslogtreecommitdiff
path: root/node_modules/workbox-cache-expiration/Plugin.mjs
diff options
context:
space:
mode:
authorruki <waruqi@gmail.com>2018-11-08 00:38:48 +0800
committerruki <waruqi@gmail.com>2018-11-07 21:53:09 +0800
commit26105034da4fcce7ac883c899d781f016559310d (patch)
treec459a5dc4e3aa0972d9919033ece511ce76dd129 /node_modules/workbox-cache-expiration/Plugin.mjs
parent2c77f00f1a7ecb6c8192f9c16d3b2001b254a107 (diff)
downloadxmake-docs-26105034da4fcce7ac883c899d781f016559310d.tar.gz
xmake-docs-26105034da4fcce7ac883c899d781f016559310d.zip
switch to vuepress
Diffstat (limited to 'node_modules/workbox-cache-expiration/Plugin.mjs')
-rw-r--r--node_modules/workbox-cache-expiration/Plugin.mjs257
1 files changed, 257 insertions, 0 deletions
diff --git a/node_modules/workbox-cache-expiration/Plugin.mjs b/node_modules/workbox-cache-expiration/Plugin.mjs
new file mode 100644
index 00000000..eb879677
--- /dev/null
+++ b/node_modules/workbox-cache-expiration/Plugin.mjs
@@ -0,0 +1,257 @@
+/*
+ Copyright 2016 Google Inc. All Rights Reserved.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+import {CacheExpiration} from './CacheExpiration.mjs';
+import {WorkboxError} from 'workbox-core/_private/WorkboxError.mjs';
+import {assert} from 'workbox-core/_private/assert.mjs';
+import {cacheNames} from 'workbox-core/_private/cacheNames.mjs';
+import {registerQuotaErrorCallback} from 'workbox-core/index.mjs';
+
+import './_version.mjs';
+
+/**
+ * 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 last request to be used will be the request
+ * that is removed from the Cache.
+ *
+ * @memberof workbox.expiration
+ */
+class Plugin {
+ /**
+ * @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 = {}) {
+ if (process.env.NODE_ENV !== 'production') {
+ if (!(config.maxEntries || config.maxAgeSeconds)) {
+ throw new WorkboxError('max-entries-or-age-required', {
+ moduleName: 'workbox-cache-expiration',
+ className: 'Plugin',
+ funcName: 'constructor',
+ });
+ }
+
+ if (config.maxEntries) {
+ assert.isType(config.maxEntries, 'number', {
+ moduleName: 'workbox-cache-expiration',
+ className: 'Plugin',
+ funcName: 'constructor',
+ paramName: 'config.maxEntries',
+ });
+ }
+
+ if (config.maxAgeSeconds) {
+ assert.isType(config.maxAgeSeconds, 'number', {
+ moduleName: 'workbox-cache-expiration',
+ className: 'Plugin',
+ funcName: 'constructor',
+ paramName: 'config.maxAgeSeconds',
+ });
+ }
+ }
+
+ this._config = config;
+ this._maxAgeSeconds = config.maxAgeSeconds;
+ this._cacheExpirations = new Map();
+
+ if (config.purgeOnQuotaError) {
+ 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.getRuntimeName()) {
+ throw new 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;
+ }
+
+ /**
+ * A "lifecycle" callback that will be triggered automatically by the
+ * `workbox.runtimeCaching` 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
+ */
+ cachedResponseWillBeUsed({cacheName, cachedResponse}) {
+ if (!cachedResponse) {
+ return null;
+ }
+
+ let 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);
+ cacheExpiration.expireEntries();
+
+ return isFresh ? cachedResponse : null;
+ }
+
+ /**
+ * @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}
+ *
+ * @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;
+ }
+
+ /**
+ * A "lifecycle" callback that will be triggered automatically by the
+ * `workbox.runtimeCaching` 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
+ */
+ async cacheDidUpdate({cacheName, request}) {
+ if (process.env.NODE_ENV !== 'production') {
+ assert.isType(cacheName, 'string', {
+ moduleName: 'workbox-cache-expiration',
+ className: 'Plugin',
+ funcName: 'cacheDidUpdate',
+ paramName: 'cacheName',
+ });
+ assert.isInstance(request, Request, {
+ moduleName: 'workbox-cache-expiration',
+ className: 'Plugin',
+ funcName: 'cacheDidUpdate',
+ paramName: 'request',
+ });
+ }
+
+ const cacheExpiration = this._getCacheExpiration(cacheName);
+ await cacheExpiration.updateTimestamp(request.url);
+ await cacheExpiration.expireEntries();
+ }
+
+
+ /**
+ * 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 you 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 caches.delete(cacheName);
+ await cacheExpiration.delete();
+ }
+
+ // Reset this._cacheExpirations to its initial state.
+ this._cacheExpirations = new Map();
+ }
+}
+
+export {Plugin};