workbox-background-sync.dev.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822
  1. this.workbox = this.workbox || {};
  2. this.workbox.backgroundSync = (function (exports, WorkboxError_mjs, logger_mjs, assert_mjs, getFriendlyURL_mjs, DBWrapper_mjs) {
  3. 'use strict';
  4. try {
  5. self['workbox:background-sync:4.3.1'] && _();
  6. } catch (e) {} // eslint-disable-line
  7. /*
  8. Copyright 2018 Google LLC
  9. Use of this source code is governed by an MIT-style
  10. license that can be found in the LICENSE file or at
  11. https://opensource.org/licenses/MIT.
  12. */
  13. const DB_VERSION = 3;
  14. const DB_NAME = 'workbox-background-sync';
  15. const OBJECT_STORE_NAME = 'requests';
  16. const INDEXED_PROP = 'queueName';
  17. /**
  18. * A class to manage storing requests from a Queue in IndexedbDB,
  19. * indexed by their queue name for easier access.
  20. *
  21. * @private
  22. */
  23. class QueueStore {
  24. /**
  25. * Associates this instance with a Queue instance, so entries added can be
  26. * identified by their queue name.
  27. *
  28. * @param {string} queueName
  29. * @private
  30. */
  31. constructor(queueName) {
  32. this._queueName = queueName;
  33. this._db = new DBWrapper_mjs.DBWrapper(DB_NAME, DB_VERSION, {
  34. onupgradeneeded: this._upgradeDb
  35. });
  36. }
  37. /**
  38. * Append an entry last in the queue.
  39. *
  40. * @param {Object} entry
  41. * @param {Object} entry.requestData
  42. * @param {number} [entry.timestamp]
  43. * @param {Object} [entry.metadata]
  44. * @private
  45. */
  46. async pushEntry(entry) {
  47. {
  48. assert_mjs.assert.isType(entry, 'object', {
  49. moduleName: 'workbox-background-sync',
  50. className: 'QueueStore',
  51. funcName: 'pushEntry',
  52. paramName: 'entry'
  53. });
  54. assert_mjs.assert.isType(entry.requestData, 'object', {
  55. moduleName: 'workbox-background-sync',
  56. className: 'QueueStore',
  57. funcName: 'pushEntry',
  58. paramName: 'entry.requestData'
  59. });
  60. } // Don't specify an ID since one is automatically generated.
  61. delete entry.id;
  62. entry.queueName = this._queueName;
  63. await this._db.add(OBJECT_STORE_NAME, entry);
  64. }
  65. /**
  66. * Preppend an entry first in the queue.
  67. *
  68. * @param {Object} entry
  69. * @param {Object} entry.requestData
  70. * @param {number} [entry.timestamp]
  71. * @param {Object} [entry.metadata]
  72. * @private
  73. */
  74. async unshiftEntry(entry) {
  75. {
  76. assert_mjs.assert.isType(entry, 'object', {
  77. moduleName: 'workbox-background-sync',
  78. className: 'QueueStore',
  79. funcName: 'unshiftEntry',
  80. paramName: 'entry'
  81. });
  82. assert_mjs.assert.isType(entry.requestData, 'object', {
  83. moduleName: 'workbox-background-sync',
  84. className: 'QueueStore',
  85. funcName: 'unshiftEntry',
  86. paramName: 'entry.requestData'
  87. });
  88. }
  89. const [firstEntry] = await this._db.getAllMatching(OBJECT_STORE_NAME, {
  90. count: 1
  91. });
  92. if (firstEntry) {
  93. // Pick an ID one less than the lowest ID in the object store.
  94. entry.id = firstEntry.id - 1;
  95. } else {
  96. // Otherwise let the auto-incrementor assign the ID.
  97. delete entry.id;
  98. }
  99. entry.queueName = this._queueName;
  100. await this._db.add(OBJECT_STORE_NAME, entry);
  101. }
  102. /**
  103. * Removes and returns the last entry in the queue matching the `queueName`.
  104. *
  105. * @return {Promise<Object>}
  106. * @private
  107. */
  108. async popEntry() {
  109. return this._removeEntry({
  110. direction: 'prev'
  111. });
  112. }
  113. /**
  114. * Removes and returns the first entry in the queue matching the `queueName`.
  115. *
  116. * @return {Promise<Object>}
  117. * @private
  118. */
  119. async shiftEntry() {
  120. return this._removeEntry({
  121. direction: 'next'
  122. });
  123. }
  124. /**
  125. * Returns all entries in the store matching the `queueName`.
  126. *
  127. * @param {Object} options See workbox.backgroundSync.Queue~getAll}
  128. * @return {Promise<Array<Object>>}
  129. * @private
  130. */
  131. async getAll() {
  132. return await this._db.getAllMatching(OBJECT_STORE_NAME, {
  133. index: INDEXED_PROP,
  134. query: IDBKeyRange.only(this._queueName)
  135. });
  136. }
  137. /**
  138. * Deletes the entry for the given ID.
  139. *
  140. * WARNING: this method does not ensure the deleted enry belongs to this
  141. * queue (i.e. matches the `queueName`). But this limitation is acceptable
  142. * as this class is not publicly exposed. An additional check would make
  143. * this method slower than it needs to be.
  144. *
  145. * @private
  146. * @param {number} id
  147. */
  148. async deleteEntry(id) {
  149. await this._db.delete(OBJECT_STORE_NAME, id);
  150. }
  151. /**
  152. * Removes and returns the first or last entry in the queue (based on the
  153. * `direction` argument) matching the `queueName`.
  154. *
  155. * @return {Promise<Object>}
  156. * @private
  157. */
  158. async _removeEntry({
  159. direction
  160. }) {
  161. const [entry] = await this._db.getAllMatching(OBJECT_STORE_NAME, {
  162. direction,
  163. index: INDEXED_PROP,
  164. query: IDBKeyRange.only(this._queueName),
  165. count: 1
  166. });
  167. if (entry) {
  168. await this.deleteEntry(entry.id);
  169. return entry;
  170. }
  171. }
  172. /**
  173. * Upgrades the database given an `upgradeneeded` event.
  174. *
  175. * @param {Event} event
  176. * @private
  177. */
  178. _upgradeDb(event) {
  179. const db = event.target.result;
  180. if (event.oldVersion > 0 && event.oldVersion < DB_VERSION) {
  181. if (db.objectStoreNames.contains(OBJECT_STORE_NAME)) {
  182. db.deleteObjectStore(OBJECT_STORE_NAME);
  183. }
  184. }
  185. const objStore = db.createObjectStore(OBJECT_STORE_NAME, {
  186. autoIncrement: true,
  187. keyPath: 'id'
  188. });
  189. objStore.createIndex(INDEXED_PROP, INDEXED_PROP, {
  190. unique: false
  191. });
  192. }
  193. }
  194. /*
  195. Copyright 2018 Google LLC
  196. Use of this source code is governed by an MIT-style
  197. license that can be found in the LICENSE file or at
  198. https://opensource.org/licenses/MIT.
  199. */
  200. const serializableProperties = ['method', 'referrer', 'referrerPolicy', 'mode', 'credentials', 'cache', 'redirect', 'integrity', 'keepalive'];
  201. /**
  202. * A class to make it easier to serialize and de-serialize requests so they
  203. * can be stored in IndexedDB.
  204. *
  205. * @private
  206. */
  207. class StorableRequest {
  208. /**
  209. * Converts a Request object to a plain object that can be structured
  210. * cloned or JSON-stringified.
  211. *
  212. * @param {Request} request
  213. * @return {Promise<StorableRequest>}
  214. *
  215. * @private
  216. */
  217. static async fromRequest(request) {
  218. const requestData = {
  219. url: request.url,
  220. headers: {}
  221. }; // Set the body if present.
  222. if (request.method !== 'GET') {
  223. // Use ArrayBuffer to support non-text request bodies.
  224. // NOTE: we can't use Blobs becuse Safari doesn't support storing
  225. // Blobs in IndexedDB in some cases:
  226. // https://github.com/dfahlander/Dexie.js/issues/618#issuecomment-398348457
  227. requestData.body = await request.clone().arrayBuffer();
  228. } // Convert the headers from an iterable to an object.
  229. for (const [key, value] of request.headers.entries()) {
  230. requestData.headers[key] = value;
  231. } // Add all other serializable request properties
  232. for (const prop of serializableProperties) {
  233. if (request[prop] !== undefined) {
  234. requestData[prop] = request[prop];
  235. }
  236. }
  237. return new StorableRequest(requestData);
  238. }
  239. /**
  240. * Accepts an object of request data that can be used to construct a
  241. * `Request` but can also be stored in IndexedDB.
  242. *
  243. * @param {Object} requestData An object of request data that includes the
  244. * `url` plus any relevant properties of
  245. * [requestInit]{@link https://fetch.spec.whatwg.org/#requestinit}.
  246. * @private
  247. */
  248. constructor(requestData) {
  249. {
  250. assert_mjs.assert.isType(requestData, 'object', {
  251. moduleName: 'workbox-background-sync',
  252. className: 'StorableRequest',
  253. funcName: 'constructor',
  254. paramName: 'requestData'
  255. });
  256. assert_mjs.assert.isType(requestData.url, 'string', {
  257. moduleName: 'workbox-background-sync',
  258. className: 'StorableRequest',
  259. funcName: 'constructor',
  260. paramName: 'requestData.url'
  261. });
  262. } // If the request's mode is `navigate`, convert it to `same-origin` since
  263. // navigation requests can't be constructed via script.
  264. if (requestData.mode === 'navigate') {
  265. requestData.mode = 'same-origin';
  266. }
  267. this._requestData = requestData;
  268. }
  269. /**
  270. * Returns a deep clone of the instances `_requestData` object.
  271. *
  272. * @return {Object}
  273. *
  274. * @private
  275. */
  276. toObject() {
  277. const requestData = Object.assign({}, this._requestData);
  278. requestData.headers = Object.assign({}, this._requestData.headers);
  279. if (requestData.body) {
  280. requestData.body = requestData.body.slice(0);
  281. }
  282. return requestData;
  283. }
  284. /**
  285. * Converts this instance to a Request.
  286. *
  287. * @return {Request}
  288. *
  289. * @private
  290. */
  291. toRequest() {
  292. return new Request(this._requestData.url, this._requestData);
  293. }
  294. /**
  295. * Creates and returns a deep clone of the instance.
  296. *
  297. * @return {StorableRequest}
  298. *
  299. * @private
  300. */
  301. clone() {
  302. return new StorableRequest(this.toObject());
  303. }
  304. }
  305. /*
  306. Copyright 2018 Google LLC
  307. Use of this source code is governed by an MIT-style
  308. license that can be found in the LICENSE file or at
  309. https://opensource.org/licenses/MIT.
  310. */
  311. const TAG_PREFIX = 'workbox-background-sync';
  312. const MAX_RETENTION_TIME = 60 * 24 * 7; // 7 days in minutes
  313. const queueNames = new Set();
  314. /**
  315. * A class to manage storing failed requests in IndexedDB and retrying them
  316. * later. All parts of the storing and replaying process are observable via
  317. * callbacks.
  318. *
  319. * @memberof workbox.backgroundSync
  320. */
  321. class Queue {
  322. /**
  323. * Creates an instance of Queue with the given options
  324. *
  325. * @param {string} name The unique name for this queue. This name must be
  326. * unique as it's used to register sync events and store requests
  327. * in IndexedDB specific to this instance. An error will be thrown if
  328. * a duplicate name is detected.
  329. * @param {Object} [options]
  330. * @param {Function} [options.onSync] A function that gets invoked whenever
  331. * the 'sync' event fires. The function is invoked with an object
  332. * containing the `queue` property (referencing this instance), and you
  333. * can use the callback to customize the replay behavior of the queue.
  334. * When not set the `replayRequests()` method is called.
  335. * Note: if the replay fails after a sync event, make sure you throw an
  336. * error, so the browser knows to retry the sync event later.
  337. * @param {number} [options.maxRetentionTime=7 days] The amount of time (in
  338. * minutes) a request may be retried. After this amount of time has
  339. * passed, the request will be deleted from the queue.
  340. */
  341. constructor(name, {
  342. onSync,
  343. maxRetentionTime
  344. } = {}) {
  345. // Ensure the store name is not already being used
  346. if (queueNames.has(name)) {
  347. throw new WorkboxError_mjs.WorkboxError('duplicate-queue-name', {
  348. name
  349. });
  350. } else {
  351. queueNames.add(name);
  352. }
  353. this._name = name;
  354. this._onSync = onSync || this.replayRequests;
  355. this._maxRetentionTime = maxRetentionTime || MAX_RETENTION_TIME;
  356. this._queueStore = new QueueStore(this._name);
  357. this._addSyncListener();
  358. }
  359. /**
  360. * @return {string}
  361. */
  362. get name() {
  363. return this._name;
  364. }
  365. /**
  366. * Stores the passed request in IndexedDB (with its timestamp and any
  367. * metadata) at the end of the queue.
  368. *
  369. * @param {Object} entry
  370. * @param {Request} entry.request The request to store in the queue.
  371. * @param {Object} [entry.metadata] Any metadata you want associated with the
  372. * stored request. When requests are replayed you'll have access to this
  373. * metadata object in case you need to modify the request beforehand.
  374. * @param {number} [entry.timestamp] The timestamp (Epoch time in
  375. * milliseconds) when the request was first added to the queue. This is
  376. * used along with `maxRetentionTime` to remove outdated requests. In
  377. * general you don't need to set this value, as it's automatically set
  378. * for you (defaulting to `Date.now()`), but you can update it if you
  379. * don't want particular requests to expire.
  380. */
  381. async pushRequest(entry) {
  382. {
  383. assert_mjs.assert.isType(entry, 'object', {
  384. moduleName: 'workbox-background-sync',
  385. className: 'Queue',
  386. funcName: 'pushRequest',
  387. paramName: 'entry'
  388. });
  389. assert_mjs.assert.isInstance(entry.request, Request, {
  390. moduleName: 'workbox-background-sync',
  391. className: 'Queue',
  392. funcName: 'pushRequest',
  393. paramName: 'entry.request'
  394. });
  395. }
  396. await this._addRequest(entry, 'push');
  397. }
  398. /**
  399. * Stores the passed request in IndexedDB (with its timestamp and any
  400. * metadata) at the beginning of the queue.
  401. *
  402. * @param {Object} entry
  403. * @param {Request} entry.request The request to store in the queue.
  404. * @param {Object} [entry.metadata] Any metadata you want associated with the
  405. * stored request. When requests are replayed you'll have access to this
  406. * metadata object in case you need to modify the request beforehand.
  407. * @param {number} [entry.timestamp] The timestamp (Epoch time in
  408. * milliseconds) when the request was first added to the queue. This is
  409. * used along with `maxRetentionTime` to remove outdated requests. In
  410. * general you don't need to set this value, as it's automatically set
  411. * for you (defaulting to `Date.now()`), but you can update it if you
  412. * don't want particular requests to expire.
  413. */
  414. async unshiftRequest(entry) {
  415. {
  416. assert_mjs.assert.isType(entry, 'object', {
  417. moduleName: 'workbox-background-sync',
  418. className: 'Queue',
  419. funcName: 'unshiftRequest',
  420. paramName: 'entry'
  421. });
  422. assert_mjs.assert.isInstance(entry.request, Request, {
  423. moduleName: 'workbox-background-sync',
  424. className: 'Queue',
  425. funcName: 'unshiftRequest',
  426. paramName: 'entry.request'
  427. });
  428. }
  429. await this._addRequest(entry, 'unshift');
  430. }
  431. /**
  432. * Removes and returns the last request in the queue (along with its
  433. * timestamp and any metadata). The returned object takes the form:
  434. * `{request, timestamp, metadata}`.
  435. *
  436. * @return {Promise<Object>}
  437. */
  438. async popRequest() {
  439. return this._removeRequest('pop');
  440. }
  441. /**
  442. * Removes and returns the first request in the queue (along with its
  443. * timestamp and any metadata). The returned object takes the form:
  444. * `{request, timestamp, metadata}`.
  445. *
  446. * @return {Promise<Object>}
  447. */
  448. async shiftRequest() {
  449. return this._removeRequest('shift');
  450. }
  451. /**
  452. * Returns all the entries that have not expired (per `maxRetentionTime`).
  453. * Any expired entries are removed from the queue.
  454. *
  455. * @return {Promise<Array<Object>>}
  456. */
  457. async getAll() {
  458. const allEntries = await this._queueStore.getAll();
  459. const now = Date.now();
  460. const unexpiredEntries = [];
  461. for (const entry of allEntries) {
  462. // Ignore requests older than maxRetentionTime. Call this function
  463. // recursively until an unexpired request is found.
  464. const maxRetentionTimeInMs = this._maxRetentionTime * 60 * 1000;
  465. if (now - entry.timestamp > maxRetentionTimeInMs) {
  466. await this._queueStore.deleteEntry(entry.id);
  467. } else {
  468. unexpiredEntries.push(convertEntry(entry));
  469. }
  470. }
  471. return unexpiredEntries;
  472. }
  473. /**
  474. * Adds the entry to the QueueStore and registers for a sync event.
  475. *
  476. * @param {Object} entry
  477. * @param {Request} entry.request
  478. * @param {Object} [entry.metadata]
  479. * @param {number} [entry.timestamp=Date.now()]
  480. * @param {string} operation ('push' or 'unshift')
  481. * @private
  482. */
  483. async _addRequest({
  484. request,
  485. metadata,
  486. timestamp = Date.now()
  487. }, operation) {
  488. const storableRequest = await StorableRequest.fromRequest(request.clone());
  489. const entry = {
  490. requestData: storableRequest.toObject(),
  491. timestamp
  492. }; // Only include metadata if it's present.
  493. if (metadata) {
  494. entry.metadata = metadata;
  495. }
  496. await this._queueStore[`${operation}Entry`](entry);
  497. {
  498. logger_mjs.logger.log(`Request for '${getFriendlyURL_mjs.getFriendlyURL(request.url)}' has ` + `been added to background sync queue '${this._name}'.`);
  499. } // Don't register for a sync if we're in the middle of a sync. Instead,
  500. // we wait until the sync is complete and call register if
  501. // `this._requestsAddedDuringSync` is true.
  502. if (this._syncInProgress) {
  503. this._requestsAddedDuringSync = true;
  504. } else {
  505. await this.registerSync();
  506. }
  507. }
  508. /**
  509. * Removes and returns the first or last (depending on `operation`) entry
  510. * from the QueueStore that's not older than the `maxRetentionTime`.
  511. *
  512. * @param {string} operation ('pop' or 'shift')
  513. * @return {Object|undefined}
  514. * @private
  515. */
  516. async _removeRequest(operation) {
  517. const now = Date.now();
  518. const entry = await this._queueStore[`${operation}Entry`]();
  519. if (entry) {
  520. // Ignore requests older than maxRetentionTime. Call this function
  521. // recursively until an unexpired request is found.
  522. const maxRetentionTimeInMs = this._maxRetentionTime * 60 * 1000;
  523. if (now - entry.timestamp > maxRetentionTimeInMs) {
  524. return this._removeRequest(operation);
  525. }
  526. return convertEntry(entry);
  527. }
  528. }
  529. /**
  530. * Loops through each request in the queue and attempts to re-fetch it.
  531. * If any request fails to re-fetch, it's put back in the same position in
  532. * the queue (which registers a retry for the next sync event).
  533. */
  534. async replayRequests() {
  535. let entry;
  536. while (entry = await this.shiftRequest()) {
  537. try {
  538. await fetch(entry.request.clone());
  539. {
  540. logger_mjs.logger.log(`Request for '${getFriendlyURL_mjs.getFriendlyURL(entry.request.url)}'` + `has been replayed in queue '${this._name}'`);
  541. }
  542. } catch (error) {
  543. await this.unshiftRequest(entry);
  544. {
  545. logger_mjs.logger.log(`Request for '${getFriendlyURL_mjs.getFriendlyURL(entry.request.url)}'` + `failed to replay, putting it back in queue '${this._name}'`);
  546. }
  547. throw new WorkboxError_mjs.WorkboxError('queue-replay-failed', {
  548. name: this._name
  549. });
  550. }
  551. }
  552. {
  553. logger_mjs.logger.log(`All requests in queue '${this.name}' have successfully ` + `replayed; the queue is now empty!`);
  554. }
  555. }
  556. /**
  557. * Registers a sync event with a tag unique to this instance.
  558. */
  559. async registerSync() {
  560. if ('sync' in registration) {
  561. try {
  562. await registration.sync.register(`${TAG_PREFIX}:${this._name}`);
  563. } catch (err) {
  564. // This means the registration failed for some reason, possibly due to
  565. // the user disabling it.
  566. {
  567. logger_mjs.logger.warn(`Unable to register sync event for '${this._name}'.`, err);
  568. }
  569. }
  570. }
  571. }
  572. /**
  573. * In sync-supporting browsers, this adds a listener for the sync event.
  574. * In non-sync-supporting browsers, this will retry the queue on service
  575. * worker startup.
  576. *
  577. * @private
  578. */
  579. _addSyncListener() {
  580. if ('sync' in registration) {
  581. self.addEventListener('sync', event => {
  582. if (event.tag === `${TAG_PREFIX}:${this._name}`) {
  583. {
  584. logger_mjs.logger.log(`Background sync for tag '${event.tag}'` + `has been received`);
  585. }
  586. const syncComplete = async () => {
  587. this._syncInProgress = true;
  588. let syncError;
  589. try {
  590. await this._onSync({
  591. queue: this
  592. });
  593. } catch (error) {
  594. syncError = error; // Rethrow the error. Note: the logic in the finally clause
  595. // will run before this gets rethrown.
  596. throw syncError;
  597. } finally {
  598. // New items may have been added to the queue during the sync,
  599. // so we need to register for a new sync if that's happened...
  600. // Unless there was an error during the sync, in which
  601. // case the browser will automatically retry later, as long
  602. // as `event.lastChance` is not true.
  603. if (this._requestsAddedDuringSync && !(syncError && !event.lastChance)) {
  604. await this.registerSync();
  605. }
  606. this._syncInProgress = false;
  607. this._requestsAddedDuringSync = false;
  608. }
  609. };
  610. event.waitUntil(syncComplete());
  611. }
  612. });
  613. } else {
  614. {
  615. logger_mjs.logger.log(`Background sync replaying without background sync event`);
  616. } // If the browser doesn't support background sync, retry
  617. // every time the service worker starts up as a fallback.
  618. this._onSync({
  619. queue: this
  620. });
  621. }
  622. }
  623. /**
  624. * Returns the set of queue names. This is primarily used to reset the list
  625. * of queue names in tests.
  626. *
  627. * @return {Set}
  628. *
  629. * @private
  630. */
  631. static get _queueNames() {
  632. return queueNames;
  633. }
  634. }
  635. /**
  636. * Converts a QueueStore entry into the format exposed by Queue. This entails
  637. * converting the request data into a real request and omitting the `id` and
  638. * `queueName` properties.
  639. *
  640. * @param {Object} queueStoreEntry
  641. * @return {Object}
  642. * @private
  643. */
  644. const convertEntry = queueStoreEntry => {
  645. const queueEntry = {
  646. request: new StorableRequest(queueStoreEntry.requestData).toRequest(),
  647. timestamp: queueStoreEntry.timestamp
  648. };
  649. if (queueStoreEntry.metadata) {
  650. queueEntry.metadata = queueStoreEntry.metadata;
  651. }
  652. return queueEntry;
  653. };
  654. /*
  655. Copyright 2018 Google LLC
  656. Use of this source code is governed by an MIT-style
  657. license that can be found in the LICENSE file or at
  658. https://opensource.org/licenses/MIT.
  659. */
  660. /**
  661. * A class implementing the `fetchDidFail` lifecycle callback. This makes it
  662. * easier to add failed requests to a background sync Queue.
  663. *
  664. * @memberof workbox.backgroundSync
  665. */
  666. class Plugin {
  667. /**
  668. * @param {...*} queueArgs Args to forward to the composed Queue instance.
  669. * See the [Queue]{@link workbox.backgroundSync.Queue} documentation for
  670. * parameter details.
  671. */
  672. constructor(...queueArgs) {
  673. this._queue = new Queue(...queueArgs);
  674. this.fetchDidFail = this.fetchDidFail.bind(this);
  675. }
  676. /**
  677. * @param {Object} options
  678. * @param {Request} options.request
  679. * @private
  680. */
  681. async fetchDidFail({
  682. request
  683. }) {
  684. await this._queue.pushRequest({
  685. request
  686. });
  687. }
  688. }
  689. /*
  690. Copyright 2018 Google LLC
  691. Use of this source code is governed by an MIT-style
  692. license that can be found in the LICENSE file or at
  693. https://opensource.org/licenses/MIT.
  694. */
  695. exports.Queue = Queue;
  696. exports.Plugin = Plugin;
  697. return exports;
  698. }({}, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private));
  699. //# sourceMappingURL=workbox-background-sync.dev.js.map