Socket
Socket
Sign inDemoInstall

workbox-background-sync

Package Overview
Dependencies
Maintainers
4
Versions
97
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

workbox-background-sync - npm Package Compare versions

Comparing version 4.0.0-alpha.0 to 4.0.0-beta.0

701

build/workbox-background-sync.dev.js
this.workbox = this.workbox || {};
this.workbox.backgroundSync = (function (DBWrapper_mjs,WorkboxError_mjs,logger_mjs,assert_mjs,getFriendlyURL_mjs) {
this.workbox.backgroundSync = (function (assert_mjs,DBWrapper_mjs,migrateDb_mjs,WorkboxError_mjs,logger_mjs,getFriendlyURL_mjs) {
'use strict';
try {
self.workbox.v['workbox:background-sync:4.0.0-alpha.0'] = 1;
self.workbox.v['workbox:background-sync:4.0.0-beta.0'] = 1;
} catch (e) {} // eslint-disable-line

@@ -16,6 +16,19 @@

*/
const serializableProperties = ['method', 'referrer', 'referrerPolicy', 'mode', 'credentials', 'cache', 'redirect', 'integrity', 'keepalive'];
const DB_VERSION = 2;
const DB_NAME = 'workbox-background-sync';
const OBJECT_STORE_NAME = 'requests';
const INDEXED_PROP = 'queueName';
const TAG_PREFIX = 'workbox-background-sync';
const MAX_RETENTION_TIME = 60 * 24 * 7; // 7 days in minutes
/*
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 to make it easier to serialize and de-serialize requests so they
* can be stored in IndexedDB.
* A class to manage storing requests from a Queue in IndexedbDB,
* indexed by their queue name for easier access.
*

@@ -25,127 +38,204 @@ * @private

class StorableRequest {
class QueueStore {
/**
* Converts a Request object to a plain object that can be structured
* cloned or JSON-stringified.
* Associates this instance with a Queue instance, so entries added can be
* identified by their queue name.
*
* @param {Request} request
* @return {Promise<StorableRequest>}
*
* @param {string} queueName
* @private
*/
static async fromRequest(request) {
const requestInit = {
headers: {}
}; // Set the body if present.
constructor(queueName) {
this._queueName = queueName;
this._db = new DBWrapper_mjs.DBWrapper(DB_NAME, DB_VERSION, {
onupgradeneeded: evt => this._upgradeDb(evt)
});
}
/**
* Append an entry last in the queue.
*
* @param {Object} entry
* @param {Object} entry.requestData
* @param {number} [entry.timestamp]
* @param {Object} [entry.metadata]
*/
if (request.method !== 'GET') {
// Use blob to support non-text request bodies,
// and clone first in case the caller still needs the request.
requestInit.body = await request.clone().blob();
} // Convert the headers from an iterable to an object.
async pushEntry(entry) {
{
assert_mjs.assert.isType(entry, 'object', {
moduleName: 'workbox-background-sync',
className: 'QueueStore',
funcName: 'pushEntry',
paramName: 'entry'
});
assert_mjs.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.
for (const [key, value] of request.headers.entries()) {
requestInit.headers[key] = value;
} // Add all other serializable request properties
for (const prop of serializableProperties) {
if (request[prop] !== undefined) {
requestInit[prop] = request[prop];
}
}
return new StorableRequest({
url: request.url,
requestInit
});
delete entry.id;
entry.queueName = this._queueName;
await this._db.add(OBJECT_STORE_NAME, entry);
}
/**
* Accepts a URL and RequestInit dictionary that can be used to create a
* new Request object. A timestamp is also generated so consumers can
* reference when the object was created.
* Preppend an entry first in the queue.
*
* @param {Object} param1
* @param {string} param1.url
* @param {Object} param1.requestInit
* See: https://fetch.spec.whatwg.org/#requestinit
* @param {number} param1.timestamp The time the request was created,
* defaulting to the current time if not specified.
*
* @private
* @param {Object} entry
* @param {Object} entry.requestData
* @param {number} [entry.timestamp]
* @param {Object} [entry.metadata]
*/
constructor({
url,
requestInit,
timestamp = Date.now()
}) {
this.url = url;
this.requestInit = requestInit; // "Private"
async unshiftEntry(entry) {
{
assert_mjs.assert.isType(entry, 'object', {
moduleName: 'workbox-background-sync',
className: 'QueueStore',
funcName: 'unshiftEntry',
paramName: 'entry'
});
assert_mjs.assert.isType(entry.requestData, 'object', {
moduleName: 'workbox-background-sync',
className: 'QueueStore',
funcName: 'unshiftEntry',
paramName: 'entry.requestData'
});
}
this._timestamp = timestamp;
const firstEntry = await this._db.get(OBJECT_STORE_NAME);
if (firstEntry) {
// Pick an ID one less than the lowest ID in the object store.
entry.id = firstEntry.id - 1;
} else {
delete entry.id;
}
entry.queueName = this._queueName;
await this._db.add(OBJECT_STORE_NAME, entry);
}
/**
* Gets the private _timestamp property.
* Removes and returns the last entry in the queue matching the `queueName`.
*
* @return {number}
*
* @private
* @return {Promise<Object>}
*/
get timestamp() {
return this._timestamp;
async popEntry() {
return this._removeEntry({
direction: 'prev'
});
}
/**
* Coverts this instance to a plain Object.
* Removes and returns the first entry in the queue matching the `queueName`.
*
* @return {Object}
*
* @private
* @return {Promise<Object>}
*/
toObject() {
return {
url: this.url,
timestamp: this.timestamp,
requestInit: this.requestInit
};
async shiftEntry() {
return this._removeEntry({
direction: 'next'
});
}
/**
* Converts this instance to a Request.
* Removes and returns the first or last entry in the queue (based on the
* `direction` argument) matching the `queueName`.
*
* @return {Request}
*
* @private
* @return {Promise<Object>}
*/
toRequest() {
return new Request(this.url, this.requestInit);
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._db.delete(OBJECT_STORE_NAME, entry.id); // Dont' expose the ID or queueName;
delete entry.id;
delete entry.queueName;
return entry;
}
}
/**
* Creates and returns a deep clone of the instance.
* Upgrades the database given an `upgradeneeded` event.
*
* @return {StorableRequest}
*
* @private
* @param {Event} event
*/
clone() {
const requestInit = Object.assign({}, this.requestInit);
requestInit.headers = Object.assign({}, this.requestInit.headers);
_upgradeDb(event) {
const db = event.target.result;
const txn = event.target.transaction;
let oldEntries = [];
migrateDb_mjs.migrateDb(event, {
v1: next => {
// When migrating from version 0, this will not exist.
if (db.objectStoreNames.contains(OBJECT_STORE_NAME)) {
// Get any existing entries in the v1 requests store
// and then delete it.
const objStore = txn.objectStore(OBJECT_STORE_NAME);
if (this.requestInit.body) {
requestInit.body = this.requestInit.body.slice();
}
objStore.openCursor().onsuccess = ({
target
}) => {
const cursor = target.result;
return new StorableRequest({
url: this.url,
timestamp: this.timestamp,
requestInit
if (cursor) {
oldEntries.push(cursor.value);
cursor.continue();
} else {
db.deleteObjectStore(OBJECT_STORE_NAME);
next();
}
};
} else {
next();
}
},
v2: next => {
// Creates v2 of the requests store and adds back any existing
// entries in the new format.
const objStore = db.createObjectStore(OBJECT_STORE_NAME, {
autoIncrement: true,
keyPath: 'id'
});
objStore.createIndex(INDEXED_PROP, INDEXED_PROP, {
unique: false
});
if (oldEntries.length) {
for (const _ref of oldEntries) {
const {
queueName,
storableRequest
} = _ref;
// Move the timestamp from `storableRequest` to the top level.
const timestamp = storableRequest.timestamp; // Reformat the storable request data
const requestData = Object.assign(storableRequest.requestInit, {
url: storableRequest.url
});
objStore.add({
queueName,
timestamp,
requestData
});
}
}
next();
}
});

@@ -163,18 +253,6 @@ }

*/
const DB_NAME = 'workbox-background-sync';
const OBJECT_STORE_NAME = 'requests';
const INDEXED_PROP = 'queueName';
const TAG_PREFIX = 'workbox-background-sync';
const MAX_RETENTION_TIME = 60 * 24 * 7; // 7 days in minutes
/*
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 manage storing requests from a Queue in IndexedbDB,
* indexed by their queue name for easier access.
* A class to make it easier to serialize and de-serialize requests so they
* can be stored in IndexedDB.
*

@@ -184,27 +262,45 @@ * @private

class QueueStore {
class StorableRequest {
/**
* Associates this instance with a Queue instance, so entries added can be
* identified by their queue name.
* Converts a Request object to a plain object that can be structured
* cloned or JSON-stringified.
*
* @param {Queue} queue
* @param {Request} request
* @return {Promise<StorableRequest>}
*
* @private
*/
constructor(queue) {
this._queue = queue;
this._db = new DBWrapper_mjs.DBWrapper(DB_NAME, 1, {
onupgradeneeded: evt => evt.target.result.createObjectStore(OBJECT_STORE_NAME, {
autoIncrement: true
}).createIndex(INDEXED_PROP, INDEXED_PROP, {
unique: false
})
});
static async fromRequest(request) {
const requestData = {
url: request.url,
headers: {}
}; // Set the body if present.
if (request.method !== 'GET') {
// Use blob to support non-text request bodies,
// and clone first in case the caller still needs the request.
requestData.body = await request.clone().blob();
} // 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);
}
/**
* Takes a StorableRequest instance, converts it to an object and adds it
* as an entry in the object store.
* Accepts an object of request data that can be used to construct a
* `Request` but can also be stored in IndexedDB.
*
* @param {StorableRequest} storableRequest
*
* @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

@@ -214,14 +310,24 @@ */

async addEntry(storableRequest) {
await this._db.add(OBJECT_STORE_NAME, {
queueName: this._queue.name,
storableRequest: storableRequest.toObject()
});
constructor(requestData) {
{
assert_mjs.assert.isType(requestData, 'object', {
moduleName: 'workbox-background-sync',
className: 'StorableRequest',
funcName: 'constructor',
paramName: 'requestData'
});
assert_mjs.assert.isType(requestData.url, 'string', {
moduleName: 'workbox-background-sync',
className: 'StorableRequest',
funcName: 'constructor',
paramName: 'requestData.url'
});
}
this._requestData = requestData;
}
/**
* Gets the oldest entry in the object store, removes it, and returns the
* value as a StorableRequest instance. If no entry exists, it returns
* undefined.
* Returns a deep clone of the instances `_requestData` object.
*
* @return {StorableRequest|undefined}
* @return {Object}
*

@@ -232,16 +338,37 @@ * @private

async getAndRemoveOldestEntry() {
const [entry] = await this._db.getAllMatching(OBJECT_STORE_NAME, {
index: INDEXED_PROP,
query: IDBKeyRange.only(this._queue.name),
count: 1,
includeKeys: true
});
toObject() {
const requestData = Object.assign({}, this._requestData);
requestData.headers = Object.assign({}, this._requestData.headers);
if (entry) {
await this._db.delete(OBJECT_STORE_NAME, entry.primaryKey);
return new StorableRequest(entry.value.storableRequest);
if (requestData.body) {
requestData.body = requestData.body.slice();
}
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());
}
}

@@ -274,17 +401,8 @@

* @param {Object} [options]
* @param {Object} [options.callbacks] Callbacks to observe the lifecycle of
* queued requests. Use these to respond to or modify the requests
* during the replay process.
* @param {function(StorableRequest):undefined}
* [options.callbacks.requestWillEnqueue]
* Invoked immediately before the request is stored to IndexedDB. Use
* this callback to modify request data at store time.
* @param {function(StorableRequest):undefined}
* [options.callbacks.requestWillReplay]
* Invoked immediately before the request is re-fetched. Use this
* callback to modify request data at fetch time.
* @param {function(Array<StorableRequest>):undefined}
* [options.callbacks.queueDidReplay]
* Invoked after all requests in the queue have successfully replayed.
* @param {number} [options.maxRetentionTime = 7 days] The amount of time (in
* @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.
* @param {number} [options.maxRetentionTime=7 days] The amount of time (in
* minutes) a request may be retried. After this amount of time has

@@ -294,4 +412,4 @@ * passed, the request will be deleted from the queue.

constructor(name, {
callbacks = {},
maxRetentionTime = MAX_RETENTION_TIME
onSync,
maxRetentionTime
} = {}) {

@@ -308,5 +426,5 @@ // Ensure the store name is not already being used

this._name = name;
this._callbacks = callbacks;
this._maxRetentionTime = maxRetentionTime;
this._queueStore = new QueueStore(this);
this._onSync = onSync || this.replayRequests;
this._maxRetentionTime = maxRetentionTime || MAX_RETENTION_TIME;
this._queueStore = new QueueStore(this._name);

@@ -324,107 +442,207 @@ this._addSyncListener();

/**
* Stores the passed request into IndexedDB. The database used is
* `workbox-background-sync` and the object store name is the same as
* the name this instance was created with (to guarantee it's unique).
* Stores the passed request in IndexedDB (with its timestamp and any
* metadata) at the end of the queue.
*
* @param {Request} request The request object to store.
* @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 addRequest(request) {
async pushRequest(entry) {
{
assert_mjs.assert.isInstance(request, Request, {
assert_mjs.assert.isType(entry, 'object', {
moduleName: 'workbox-background-sync',
className: 'Queue',
funcName: 'addRequest',
paramName: 'request'
funcName: 'pushRequest',
paramName: 'entry'
});
assert_mjs.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_mjs.assert.isType(entry, 'object', {
moduleName: 'workbox-background-sync',
className: 'Queue',
funcName: 'unshiftRequest',
paramName: 'entry'
});
assert_mjs.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');
}
/**
* 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')
*/
async _addRequest({
request,
metadata,
timestamp = Date.now()
}, operation) {
const storableRequest = await StorableRequest.fromRequest(request.clone());
await this._runCallback('requestWillEnqueue', storableRequest);
await this._queueStore.addEntry(storableRequest);
await this._registerSync();
const entry = {
requestData: storableRequest.toObject(),
timestamp
}; // Only include metadata if it's present.
if (metadata) {
entry.metadata = metadata;
}
await this._queueStore[`${operation}Entry`](entry);
await this.registerSync();
{
logger_mjs.logger.log(`Request for '${getFriendlyURL_mjs.getFriendlyURL(storableRequest.url)}' has been
added to background sync queue '${this._name}'.`);
logger_mjs.logger.log(`Request for '${getFriendlyURL_mjs.getFriendlyURL(storableRequest.url)}' has ` + `been added to background sync queue '${this._name}'.`);
}
}
/**
* Retrieves all stored requests in IndexedDB and retries them. If the
* queue contained requests that were successfully replayed, the
* `queueDidReplay` callback is invoked (which implies the queue is
* now empty). If any of the requests fail, a new sync registration is
* created to retry again later.
* Removes and returns the first or last (depending on `operation`) entry
* form the QueueStore that's not older than the `maxRetentionTime`.
*
* @param {string} operation ('pop' or 'shift')
* @return {Object|undefined}
*/
async replayRequests() {
async _removeRequest(operation) {
const now = Date.now();
const replayedRequests = [];
const failedRequests = [];
let storableRequest;
const entry = await this._queueStore[`${operation}Entry`]();
while (storableRequest = await this._queueStore.getAndRemoveOldestEntry()) {
// Make a copy so the unmodified request can be stored
// in the event of a replay failure.
const storableRequestClone = storableRequest.clone(); // Ignore requests older than maxRetentionTime.
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 - storableRequest.timestamp > maxRetentionTimeInMs) {
continue;
if (now - entry.timestamp > maxRetentionTimeInMs) {
return this._removeRequest(operation);
}
await this._runCallback('requestWillReplay', storableRequest);
const replay = {
request: storableRequest.toRequest()
};
entry.request = new StorableRequest(entry.requestData).toRequest();
delete entry.requestData;
return entry;
}
}
/**
* 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 {
// Clone the request before fetching so callbacks get an unused one.
replay.response = await fetch(replay.request.clone());
await fetch(entry.request);
{
logger_mjs.logger.log(`Request for '${getFriendlyURL_mjs.getFriendlyURL(storableRequest.url)}'
has been replayed`);
logger_mjs.logger.log(`Request for '${getFriendlyURL_mjs.getFriendlyURL(entry.request.url)}'` + `has been replayed in queue '${this._name}'`);
}
} catch (err) {
} catch (error) {
await this.unshiftRequest(entry);
{
logger_mjs.logger.log(`Request for '${getFriendlyURL_mjs.getFriendlyURL(storableRequest.url)}'
failed to replay`);
logger_mjs.logger.log(`Request for '${getFriendlyURL_mjs.getFriendlyURL(entry.request.url)}'` + `failed to replay, putting it back in queue '${this._name}'`);
}
replay.error = err;
failedRequests.push(storableRequestClone);
throw new WorkboxError_mjs.WorkboxError('queue-replay-failed', {
name: this._name
});
}
replayedRequests.push(replay);
}
await this._runCallback('queueDidReplay', replayedRequests); // If any requests failed, put the failed requests back in the queue
// and rethrow the failed requests count.
if (failedRequests.length) {
await Promise.all(failedRequests.map(storableRequest => {
return this._queueStore.addEntry(storableRequest);
}));
throw new WorkboxError_mjs.WorkboxError('queue-replay-failed', {
name: this._name,
count: failedRequests.length
});
{
logger_mjs.logger.log(`All requests in queue '${this.name}' have successfully ` + `replayed; the queue is now empty!`);
}
}
/**
* Runs the passed callback if it exists.
*
* @private
* @param {string} name The name of the callback on this._callbacks.
* @param {...*} args The arguments to invoke the callback with.
* Registers a sync event with a tag unique to this instance.
*/
async _runCallback(name, ...args) {
if (typeof this._callbacks[name] === 'function') {
await this._callbacks[name].apply(null, args);
async registerSync() {
if ('sync' in registration) {
try {
await 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_mjs.logger.warn(`Unable to register sync event for '${this._name}'.`, err);
}
}
}

@@ -446,7 +664,8 @@ }

{
logger_mjs.logger.log(`Background sync for tag '${event.tag}'
has been received, starting replay now`);
logger_mjs.logger.log(`Background sync for tag '${event.tag}'` + `has been received`);
}
event.waitUntil(this.replayRequests());
event.waitUntil(this._onSync({
queue: this
}));
}

@@ -461,26 +680,8 @@ });

this.replayRequests();
this._onSync({
queue: this
});
}
}
/**
* Registers a sync event with a tag unique to this instance.
*
* @private
*/
async _registerSync() {
if ('sync' in registration) {
try {
await 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_mjs.logger.warn(`Unable to register sync event for '${this._name}'.`, err);
}
}
}
}
/**
* Returns the set of queue names. This is primarily used to reset the list

@@ -535,3 +736,5 @@ * of queue names in tests.

}) {
await this._queue.addRequest(request);
await this._queue.pushRequest({
request
});
}

@@ -564,4 +767,4 @@

}(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._private,workbox.core._private,workbox.core._private));
//# sourceMappingURL=workbox-background-sync.dev.js.map

@@ -1,3 +0,3 @@

this.workbox=this.workbox||{},this.workbox.backgroundSync=function(t,e){"use strict";try{self.workbox.v["workbox:background-sync:4.0.0-alpha.0"]=1}catch(t){}const s=["method","referrer","referrerPolicy","mode","credentials","cache","redirect","integrity","keepalive"];class i{static async fromRequest(t){const e={headers:{}};"GET"!==t.method&&(e.body=await t.clone().blob());for(const[s,i]of t.headers.entries())e.headers[s]=i;for(const i of s)void 0!==t[i]&&(e[i]=t[i]);return new i({url:t.url,requestInit:e})}constructor({url:t,requestInit:e,timestamp:s=Date.now()}){this.url=t,this.requestInit=e,this.t=s}get timestamp(){return this.t}toObject(){return{url:this.url,timestamp:this.timestamp,requestInit:this.requestInit}}toRequest(){return new Request(this.url,this.requestInit)}clone(){const t=Object.assign({},this.requestInit);return t.headers=Object.assign({},this.requestInit.headers),this.requestInit.body&&(t.body=this.requestInit.body.slice()),new i({url:this.url,timestamp:this.timestamp,requestInit:t})}}const n="workbox-background-sync",a="requests",r="queueName",c="workbox-background-sync",u=10080;class h{constructor(e){this.e=e,this.s=new t.DBWrapper(n,1,{onupgradeneeded:t=>t.target.result.createObjectStore(a,{autoIncrement:!0}).createIndex(r,r,{unique:!1})})}async addEntry(t){await this.s.add(a,{queueName:this.e.name,storableRequest:t.toObject()})}async getAndRemoveOldestEntry(){const[t]=await this.s.getAllMatching(a,{index:r,query:IDBKeyRange.only(this.e.name),count:1,includeKeys:!0});if(t)return await this.s.delete(a,t.primaryKey),new i(t.value.storableRequest)}}const o=new Set;class l{constructor(t,{callbacks:s={},maxRetentionTime:i=u}={}){if(o.has(t))throw new e.WorkboxError("duplicate-queue-name",{name:t});o.add(t),this.i=t,this.n=s,this.a=i,this.r=new h(this),this.c()}get name(){return this.i}async addRequest(t){const e=await i.fromRequest(t.clone());await this.u("requestWillEnqueue",e),await this.r.addEntry(e),await this.h()}async replayRequests(){const t=Date.now(),s=[],i=[];let n;for(;n=await this.r.getAndRemoveOldestEntry();){const e=n.clone(),a=60*this.a*1e3;if(t-n.timestamp>a)continue;await this.u("requestWillReplay",n);const r={request:n.toRequest()};try{r.response=await fetch(r.request.clone())}catch(t){r.error=t,i.push(e)}s.push(r)}if(await this.u("queueDidReplay",s),i.length)throw await Promise.all(i.map(t=>this.r.addEntry(t))),new e.WorkboxError("queue-replay-failed",{name:this.i,count:i.length})}async u(t,...e){"function"==typeof this.n[t]&&await this.n[t].apply(null,e)}c(){"sync"in registration?self.addEventListener("sync",t=>{t.tag===`${c}:${this.i}`&&t.waitUntil(this.replayRequests())}):this.replayRequests()}async h(){if("sync"in registration)try{await registration.sync.register(`${c}:${this.i}`)}catch(t){}}static get o(){return o}}return Object.freeze({Queue:l,Plugin:class{constructor(...t){this.e=new l(...t),this.fetchDidFail=this.fetchDidFail.bind(this)}async fetchDidFail({request:t}){await this.e.addRequest(t)}}})}(workbox.core._private,workbox.core._private);
this.workbox=this.workbox||{},this.workbox.backgroundSync=function(t,e,s){"use strict";try{self.workbox.v["workbox:background-sync:4.0.0-beta.0"]=1}catch(t){}const i=2,n="workbox-background-sync",r="requests",a="queueName",c="workbox-background-sync",h=10080;class o{constructor(e){this.t=e,this.e=new t.DBWrapper(n,i,{onupgradeneeded:t=>this.s(t)})}async pushEntry(t){delete t.id,t.queueName=this.t,await this.e.add(r,t)}async unshiftEntry(t){const e=await this.e.get(r);e?t.id=e.id-1:delete t.id,t.queueName=this.t,await this.e.add(r,t)}async popEntry(){return this.i({direction:"prev"})}async shiftEntry(){return this.i({direction:"next"})}async i({direction:t}){const[e]=await this.e.getAllMatching(r,{direction:t,index:a,query:IDBKeyRange.only(this.t),count:1});if(e)return await this.e.delete(r,e.id),delete e.id,delete e.queueName,e}s(t){const s=t.target.result,i=t.target.transaction;let n=[];e.migrateDb(t,{v1:t=>{if(s.objectStoreNames.contains(r)){i.objectStore(r).openCursor().onsuccess=(({target:e})=>{const i=e.result;i?(n.push(i.value),i.continue()):(s.deleteObjectStore(r),t())})}else t()},v2:t=>{const e=s.createObjectStore(r,{autoIncrement:!0,keyPath:"id"});if(e.createIndex(a,a,{unique:!1}),n.length)for(const t of n){const{queueName:s,storableRequest:i}=t,n=i.timestamp,r=Object.assign(i.requestInit,{url:i.url});e.add({queueName:s,timestamp:n,requestData:r})}t()}})}}const u=["method","referrer","referrerPolicy","mode","credentials","cache","redirect","integrity","keepalive"];class y{static async fromRequest(t){const e={url:t.url,headers:{}};"GET"!==t.method&&(e.body=await t.clone().blob());for(const[s,i]of t.headers.entries())e.headers[s]=i;for(const s of u)void 0!==t[s]&&(e[s]=t[s]);return new y(e)}constructor(t){this.n=t}toObject(){const t=Object.assign({},this.n);return t.headers=Object.assign({},this.n.headers),t.body&&(t.body=t.body.slice()),t}toRequest(){return new Request(this.n.url,this.n)}clone(){return new y(this.toObject())}}const w=new Set;class d{constructor(t,{onSync:e,maxRetentionTime:i}={}){if(w.has(t))throw new s.WorkboxError("duplicate-queue-name",{name:t});w.add(t),this.r=t,this.a=e||this.replayRequests,this.c=i||h,this.h=new o(this.r),this.o()}get name(){return this.r}async pushRequest(t){await this.u(t,"push")}async unshiftRequest(t){await this.u(t,"unshift")}async popRequest(){return this.y("pop")}async shiftRequest(){return this.y("shift")}async u({request:t,metadata:e,timestamp:s=Date.now()},i){const n={requestData:(await y.fromRequest(t.clone())).toObject(),timestamp:s};e&&(n.metadata=e),await this.h[`${i}Entry`](n),await this.registerSync()}async y(t){const e=Date.now(),s=await this.h[`${t}Entry`]();if(s){const i=60*this.c*1e3;return e-s.timestamp>i?this.y(t):(s.request=new y(s.requestData).toRequest(),delete s.requestData,s)}}async replayRequests(){let t;for(;t=await this.shiftRequest();)try{await fetch(t.request)}catch(e){throw await this.unshiftRequest(t),new s.WorkboxError("queue-replay-failed",{name:this.r})}}async registerSync(){if("sync"in registration)try{await registration.sync.register(`${c}:${this.r}`)}catch(t){}}o(){"sync"in registration?self.addEventListener("sync",t=>{t.tag===`${c}:${this.r}`&&t.waitUntil(this.a({queue:this}))}):this.a({queue:this})}static get w(){return w}}return Object.freeze({Queue:d,Plugin:class{constructor(...t){this.d=new d(...t),this.fetchDidFail=this.fetchDidFail.bind(this)}async fetchDidFail({request:t}){await this.d.pushRequest({request:t})}}})}(workbox.core._private,workbox.core._private,workbox.core._private);
//# sourceMappingURL=workbox-background-sync.prod.js.map
{
"name": "workbox-background-sync",
"version": "4.0.0-alpha.0",
"version": "4.0.0-beta.0",
"license": "MIT",

@@ -30,5 +30,5 @@ "author": "Google's Web DevRel Team",

"dependencies": {
"workbox-core": "^4.0.0-alpha.0"
"workbox-core": "^4.0.0-beta.0"
},
"gitHead": "db1fb73fd32fbd5cbf42e246e6144011a5c6edc2"
"gitHead": "bc90cc4bdb1f8ad435564aa84b0c90acfac611e2"
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc