PageSourceSearch

https://waitwhile-app.firebaseapp.com/ngsw-worker.js

js waitwhile-app.firebaseapp.com collected 2026-10-03 14:08:56 UTC 84,828 bytes, 2,289 lines download raw bytes

1(() => {
2  var __defProp = Object.defineProperty;
3  var __defProps = Object.defineProperties;
4  var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
5  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
6  var __hasOwnProp = Object.prototype.hasOwnProperty;
7  var __propIsEnum = Object.prototype.propertyIsEnumerable;
8  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9  var __spreadValues = (a, b) => {
10    for (var prop in b || (b = {}))
11      if (__hasOwnProp.call(b, prop))
12        __defNormalProp(a, prop, b[prop]);
13    if (__getOwnPropSymbols)
14      for (var prop of __getOwnPropSymbols(b)) {
15        if (__propIsEnum.call(b, prop))
16          __defNormalProp(a, prop, b[prop]);
17      }
18    return a;
19  };
20  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
21  var __publicField = (obj, key, value) => {
22    __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
23    return value;
24  };
25
26  
26// packages/service-worker/worker/src/named-cache-storage.js
27  var NamedCacheStorage = class {
28    constructor(original, cacheNamePrefix) {
29      __publicField(this, "original");
30      __publicField(this, "cacheNamePrefix");
31      this.original = original;
32      this.cacheNamePrefix = cacheNamePrefix;
33    }
34    delete(cacheName) {
35      return this.original.delete(`${this.cacheNamePrefix}:${cacheName}`);
36    }
37    has(cacheName) {
38      return this.original.has(`${this.cacheNamePrefix}:${cacheName}`);
39    }
40    async keys() {
41      const prefix = `${this.cacheNamePrefix}:`;
42      const allCacheNames = await this.original.keys();
43      const ownCacheNames = allCacheNames.filter((name) => name.startsWith(prefix));
44      return ownCacheNames.map((name) => name.slice(prefix.length));
45    }
46    match(request, options) {
47      return this.original.match(request, options);
48    }
49    async open(cacheName) {
50      const cache = await this.original.open(`${this.cacheNamePrefix}:${cacheName}`);
51      return Object.assign(cache, { name: cacheName });
52    }
53  };
54
55  
55// packages/service-worker/worker/src/adapter.js
56  var Adapter = class {
57    constructor(scopeUrl, caches) {
58      __publicField(this, "scopeUrl");
59      __publicField(this, "caches");
60      __publicField(this, "origin");
61      this.scopeUrl = scopeUrl;
62      const parsedScopeUrl = this.parseUrl(this.scopeUrl);
63      this.origin = parsedScopeUrl.origin;
64      this.caches = new NamedCacheStorage(caches, `ngsw:${parsedScopeUrl.path}`);
65    }
66    /**
67     * Wrapper around the `Request` constructor.
68     */
69    newRequest(input, init) {
70      return new Request(input, init);
71    }
72    /**
73     * Wrapper around the `Response` constructor.
74     */
75    newResponse(body, init) {
76      return new Response(body, init);
77    }
78    /**
79     * Wrapper around the `Headers` constructor.
80     */
81    newHeaders(headers) {
82      return new Headers(headers);
83    }
84    /**
85     * Test if a given object is an instance of `Client`.
86     */
87    isClient(source) {
88      return source instanceof Client;
89    }
90    /**
91     * Read the current UNIX time in milliseconds.
92     */
93    get time() {
94      return Date.now();
95    }
96    /**
97     * Get a normalized representation of a URL such as those found in the ServiceWorker's `ngsw.json`
98     * configuration.
99     *
100     * More specifically:
101     * 1. Resolve the URL relative to the ServiceWorker's scope.
102     * 2. If the URL is relative to the ServiceWorker's own origin, then only return the path part.
103     *    Otherwise, return the full URL.
104     *
105     * @param url The raw request URL.
106     * @return A normalized representation of the URL.
107     */
108    normalizeUrl(url) {
109      const parsed = this.parseUrl(url, this.scopeUrl);
110      return parsed.origin === this.origin ? parsed.path : url;
111    }
112    /**
113     * Parse a URL into its different parts, such as `origin`, `path` and `search`.
114     */
115    parseUrl(url, relativeTo) {
116      const parsed = !relativeTo ? new URL(url) : new URL(url, relativeTo);
117      return { origin: parsed.origin, path: parsed.pathname, search: parsed.search };
118    }
119    /**
120     * Wait for a given amount of time before completing a Promise.
121     */
122    timeout(ms) {
123      return new Promise((resolve) => {
124        setTimeout(() => resolve(), ms);
125      });
126    }
127  };
128
129  
129// packages/service-worker/worker/src/database.js
130  var NotFound = class {
131    constructor(table, key) {
132      __publicField(this, "table");
133      __publicField(this, "key");
134      this.table = table;
135      this.key = key;
136    }
137  };
138
139  
139// packages/service-worker/worker/src/db-cache.js
140  var CacheDatabase = class {
141    constructor(adapter2) {
142      __publicField(this, "adapter");
143      __publicField(this, "cacheNamePrefix", "db");
144      __publicField(this, "tables", /* @__PURE__ */ new Map());
145      this.adapter = adapter2;
146    }
147    "delete"(name) {
148      if (this.tables.has(name)) {
149        this.tables.delete(name);
150      }
151      return this.adapter.caches.delete(`${this.cacheNamePrefix}:${name}`);
152    }
153    async list() {
154      const prefix = `${this.cacheNamePrefix}:`;
155      const allCacheNames = await this.adapter.caches.keys();
156      const dbCacheNames = allCacheNames.filter((name) => name.startsWith(prefix));
157      return dbCacheNames.map((name) => name.slice(prefix.length));
158    }
159    async open(name, cacheQueryOptions) {
160      if (!this.tables.has(name)) {
161        const cache = await this.adapter.caches.open(`${this.cacheNamePrefix}:${name}`);
162        const table = new CacheTable(name, cache, this.adapter, cacheQueryOptions);
163        this.tables.set(name, table);
164      }
165      return this.tables.get(name);
166    }
167  };
168  var CacheTable = class {
169    constructor(name, cache, adapter2, cacheQueryOptions) {
170      __publicField(this, "name");
171      __publicField(this, "cache");
172      __publicField(this, "adapter");
173      __publicField(this, "cacheQueryOptions");
174      __publicField(this, "cacheName");
175      this.name = name;
176      this.cache = cache;
177      this.adapter = adapter2;
178      this.cacheQueryOptions = cacheQueryOptions;
179      this.cacheName = this.cache.name;
180    }
181    request(key) {
182      return this.adapter.newRequest("/" + key);
183    }
184    "delete"(key) {
185      return this.cache.delete(this.request(key), this.cacheQueryOptions);
186    }
187    keys() {
188      return this.cache.keys().then((requests) => requests.map((req) => req.url.slice(1)));
189    }
190    read(key) {
191      return this.cache.match(this.request(key), this.cacheQueryOptions).then((res) => {
192        if (res === void 0) {
193          return Promise.reject(new NotFound(this.name, key));
194        }
195        return res.json();
196      });
197    }
198    write(key, value) {
199      return this.cache.put(this.request(key), this.adapter.newResponse(JSON.stringify(value)));
200    }
201  };
202
203  
203// packages/service-worker/worker/src/api.js
204  var UpdateCacheStatus;
205  (function(UpdateCacheStatus2) {
206    UpdateCacheStatus2[UpdateCacheStatus2["NOT_CACHED"] = 0] = "NOT_CACHED";
207    UpdateCacheStatus2[UpdateCacheStatus2["CACHED_BUT_UNUSED"] = 1] = "CACHED_BUT_UNUSED";
208    UpdateCacheStatus2[UpdateCacheStatus2["CACHED"] = 2] = "CACHED";
209  })(UpdateCacheStatus || (UpdateCacheStatus = {}));
210
211  
211// packages/service-worker/worker/src/error.js
212  var SwCriticalError = class extends Error {
213    constructor() {
214      super(...arguments);
215      __publicField(this, "isCritical", true);
216    }
217  };
218  function errorToString(error) {
219    if (error instanceof Error) {
220      return `${error.message}
221${error.stack}`;
222    } else {
223      return `${error}`;
224    }
225  }
226  var SwUnrecoverableStateError = class extends SwCriticalError {
227    constructor() {
228      super(...arguments);
229      __publicField(this, "isUnrecoverableState", true);
230    }
231  };
232
233  
233// packages/service-worker/worker/src/sha1.js
234  function sha1(str) {
235    const utf8 = str;
236    const words32 = stringToWords32(utf8, Endian.Big);
237    return _sha1(words32, utf8.length * 8);
238  }
239  function sha1Binary(buffer) {
240    const words32 = arrayBufferToWords32(buffer, Endian.Big);
241    return _sha1(words32, buffer.byteLength * 8);
242  }
243  function _sha1(words32, len) {
244    const w = [];
245    let [a, b, c, d, e] = [1732584193, 4023233417, 2562383102, 271733878, 3285377520];
246    words32[len >> 5] |= 128 << 24 - len % 32;
247    words32[(len + 64 >> 9 << 4) + 15] = len;
248    for (let i = 0; i < words32.length; i += 16) {
249      const [h0, h1, h2, h3, h4] = [a, b, c, d, e];
250      for (let j = 0; j < 80; j++) {
251        if (j < 16) {
252          w[j] = words32[i + j];
253        } else {
254          w[j] = rol32(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
255        }
256        const [f, k] = fk(j, b, c, d);
257        const temp = [rol32(a, 5), f, e, k, w[j]].reduce(add32);
258        [e, d, c, b, a] = [d, c, rol32(b, 30), a, temp];
259      }
260      [a, b, c, d, e] = [add32(a, h0), add32(b, h1), add32(c, h2), add32(d, h3), add32(e, h4)];
261    }
262    return byteStringToHexString(words32ToByteString([a, b, c, d, e]));
263  }
264  function add32(a, b) {
265    return add32to64(a, b)[1];
266  }
267  function add32to64(a, b) {
268    const low = (a & 65535) + (b & 65535);
269    const high = (a >>> 16) + (b >>> 16) + (low >>> 16);
270    return [high >>> 16, high << 16 | low & 65535];
271  }
272  function rol32(a, count) {
273    return a << count | a >>> 32 - count;
274  }
275  var Endian;
276  (function(Endian2) {
277    Endian2[Endian2["Little"] = 0] = "Little";
278    Endian2[Endian2["Big"] = 1] = "Big";
279  })(Endian || (Endian = {}));
280  function fk(index, b, c, d) {
281    if (index < 20) {
282      return [b & c | ~b & d, 1518500249];
283    }
284    if (index < 40) {
285      return [b ^ c ^ d, 1859775393];
286    }
287    if (index < 60) {
288      return [b & c | b & d | c & d, 2400959708];
289    }
290    return [b ^ c ^ d, 3395469782];
291  }
292  function stringToWords32(str, endian) {
293    const size = str.length + 3 >>> 2;
294    const words32 = [];
295    for (let i = 0; i < size; i++) {
296      words32[i] = wordAt(str, i * 4, endian);
297    }
298    return words32;
299  }
300  function arrayBufferToWords32(buffer, endian) {
301    const size = buffer.byteLength + 3 >>> 2;
302    const words32 = [];
303    const view = new Uint8Array(buffer);
304    for (let i = 0; i < size; i++) {
305      words32[i] = wordAt(view, i * 4, endian);
306    }
307    return words32;
308  }
309  function byteAt(str, index) {
310    if (typeof str === "string") {
311      return index >= str.length ? 0 : str.charCodeAt(index) & 255;
312    } else {
313      return index >= str.byteLength ? 0 : str[index] & 255;
314    }
315  }
316  function wordAt(str, index, endian) {
317    let word = 0;
318    if (endian === Endian.Big) {
319      for (let i = 0; i < 4; i++) {
320        word += byteAt(str, index + i) << 24 - 8 * i;
321      }
322    } else {
323      for (let i = 0; i < 4; i++) {
324        word += byteAt(str, index + i) << 8 * i;
325      }
326    }
327    return word;
328  }
329  function words32ToByteString(words32) {
330    return words32.reduce((str, word) => str + word32ToByteString(word), "");
331  }
332  function word32ToByteString(word) {
333    let str = "";
334    for (let i = 0; i < 4; i++) {
335      str += String.fromCharCode(word >>> 8 * (3 - i) & 255);
336    }
337    return str;
338  }
339  function byteStringToHexString(str) {
340    let hex = "";
341    for (let i = 0; i < str.length; i++) {
342      const b = byteAt(str, i);
343      hex += (b >>> 4).toString(16) + (b & 15).toString(16);
344    }
345    return hex.toLowerCase();
346  }
347
348  
348// packages/service-worker/worker/src/assets.js
349  var AssetGroup = class {
350    constructor(scope2, adapter2, idle, config, hashes, db, cacheNamePrefix) {
351      __publicField(this, "scope");
352      __publicField(this, "adapter");
353      __publicField(this, "idle");
354      __publicField(this, "config");
355      __publicField(this, "hashes");
356      __publicField(this, "db");
357      /**
358       * A deduplication cache, to make sure the SW never makes two network requests
359       * for the same resource at once. Managed by `fetchAndCacheOnce`.
360       */
361      __publicField(this, "inFlightRequests", /* @__PURE__ */ new Map());
362      /**
363       * Normalized resource URLs.
364       */
365      __publicField(this, "urls", []);
366      /**
367       * Regular expression patterns.
368       */
369      __publicField(this, "patterns", []);
370      /**
371       * A Promise which resolves to the `Cache` used to back this asset group. This
372       * is opened from the constructor.
373       */
374      __publicField(this, "cache");
375      /**
376       * Group name from the configuration.
377       */
378      __publicField(this, "name");
379      /**
380       * Metadata associated with specific cache entries.
381       */
382      __publicField(this, "metadata");
383      this.scope = scope2;
384      this.adapter = adapter2;
385      this.idle = idle;
386      this.config = config;
387      this.hashes = hashes;
388      this.db = db;
389      this.name = config.name;
390      this.urls = config.urls.map((url) => adapter2.normalizeUrl(url));
391      this.patterns = config.patterns.map((pattern) => new RegExp(pattern));
392      this.cache = adapter2.caches.open(`${cacheNamePrefix}:${config.name}:cache`);
393      this.metadata = this.db.open(`${cacheNamePrefix}:${config.name}:meta`, config.cacheQueryOptions);
394    }
395    async cacheStatus(url) {
396      const cache = await this.cache;
397      const meta = await this.metadata;
398      const req = this.adapter.newRequest(url);
399      const res = await cache.match(req, this.config.cacheQueryOptions);
400      if (res === void 0) {
401        return UpdateCacheStatus.NOT_CACHED;
402      }
403      try {
404        const data = await meta.read(req.url);
405        if (!data.used) {
406          return UpdateCacheStatus.CACHED_BUT_UNUSED;
407        }
408      } catch (_) {
409      }
410      return UpdateCacheStatus.CACHED;
411    }
412    /**
413     * Return a list of the names of all caches used by this group.
414     */
415    async getCacheNames() {
416      const [cache, metadata] = await Promise.all([this.cache, this.metadata]);
417      return [cache.name, metadata.cacheName];
418    }
419    /**
420     * Process a request for a given resource and return it, or return null if it's not available.
421     */
422    async handleFetch(req, _event) {
423      const url = this.adapter.normalizeUrl(req.url);
424      if (this.urls.indexOf(url) !== -1 || this.patterns.some((pattern) => pattern.test(url))) {
425        const cache = await this.cache;
426        let cachedResponse;
427        try {
428          cachedResponse = await cache.match(req, this.config.cacheQueryOptions);
429        } catch (error) {
430          throw new SwCriticalError(`Cache is throwing while looking for a match: ${error}`);
431        }
432        if (cachedResponse !== void 0) {
433          if (this.hashes.has(url)) {
434            return cachedResponse;
435          } else {
436            if (await this.needToRevalidate(req, cachedResponse)) {
437              this.idle.schedule(`revalidate(${cache.name}): ${req.url}`, async () => {
438                await this.fetchAndCacheOnce(req);
439              });
440            }
441            return cachedResponse;
442          }
443        }
444        const res = await this.fetchAndCacheOnce(this.newRequestWithMetadata(req.url, req));
445        return res.clone();
446      } else {
447        return null;
448      }
449    }
450    /**
451     * Some resources are cached without a hash, meaning that their expiration is controlled
452     * by HTTP caching headers. Check whether the given request/response pair is still valid
453     * per the caching headers.
454     */
455    async needToRevalidate(req, res) {
456      if (res.headers.has("Cache-Control")) {
457        const cacheControl = res.headers.get("Cache-Control");
458        const cacheDirectives = cacheControl.split(",").map((v) => v.trim()).map((v) => v.split("="));
459        cacheDirectives.forEach((v) => v[0] = v[0].toLowerCase());
460        const maxAgeDirective = cacheDirectives.find((v) => v[0] === "max-age");
461        const cacheAge = maxAgeDirective ? maxAgeDirective[1] : void 0;
462        if (!cacheAge) {
463          return true;
464        }
465        try {
466          const maxAge = 1e3 * parseInt(cacheAge);
467          let ts;
468          try {
469            const metaTable = await this.metadata;
470            ts = (await metaTable.read(req.url)).ts;
471          } catch (e) {
472            const date = res.headers.get("Date");
473            if (date === null) {
474              return true;
475            }
476            ts = Date.parse(date);
477          }
478          const age = this.adapter.time - ts;
479          return age < 0 || age > maxAge;
480        } catch (e) {
481          return true;
482        }
483      } else if (res.headers.has("Expires")) {
484        const expiresStr = res.headers.get("Expires");
485        try {
486          return this.adapter.time > Date.parse(expiresStr);
487        } catch (e) {
488          return true;
489        }
490      } else {
491        return true;
492      }
493    }
494    /**
495     * Fetch the complete state of a cached resource, or return null if it's not found.
496     */
497    async fetchFromCacheOnly(url) {
498      const cache = await this.cache;
499      const metaTable = await this.metadata;
500      const request = this.adapter.newRequest(url);
501      const response = await cache.match(request, this.config.cacheQueryOptions);
502      if (response === void 0) {
503        return null;
504      }
505      let metadata = void 0;
506      try {
507        metadata = await metaTable.read(request.url);
508      } catch (e) {
509      }
510      return { response, metadata };
511    }
512    /**
513     * Lookup all resources currently stored in the cache which have no associated hash.
514     */
515    async unhashedResources() {
516      const cache = await this.cache;
517      return (await cache.keys()).map((request) => this.adapter.normalizeUrl(request.url)).filter((url) => !this.hashes.has(url));
518    }
519    /**
520     * Fetch the given resource from the network, and cache it if able.
521     */
522    async fetchAndCacheOnce(req, used = true) {
523      if (this.inFlightRequests.has(req.url)) {
524        return this.inFlightRequests.get(req.url);
525      }
526      const fetchOp = this.fetchFromNetwork(req);
527      this.inFlightRequests.set(req.url, fetchOp);
528      try {
529        const res = await fetchOp;
530        if (!res.ok) {
531          throw new Error(`Response not Ok (fetchAndCacheOnce): request for ${req.url} returned response ${res.status} ${res.statusText}`);
532        }
533        try {
534          const cache = await this.cache;
535          await cache.put(req, res.clone());
536          if (!this.hashes.has(this.adapter.normalizeUrl(req.url))) {
537            const meta = { ts: this.adapter.time, used };
538            const metaTable = await this.metadata;
539            await metaTable.write(req.url, meta);
540          }
541          return res;
542        } catch (err) {
543          throw new SwCriticalError(`Failed to update the caches for request to '${req.url}' (fetchAndCacheOnce): ${errorToString(err)}`);
544        }
545      } finally {
546        this.inFlightRequests.delete(req.url);
547      }
548    }
549    async fetchFromNetwork(req, redirectLimit = 3) {
550      const res = await this.cacheBustedFetchFromNetwork(req);
551      if (res["redirected"] && !!res.url) {
552        if (redirectLimit === 0) {
553          throw new SwCriticalError(`Response hit redirect limit (fetchFromNetwork): request redirected too many times, next is ${res.url}`);
554        }
555        return this.fetchFromNetwork(this.newRequestWithMetadata(res.url, req), redirectLimit - 1);
556      }
557      return res;
558    }
559    /**
560     * Load a particular asset from the network, accounting for hash validation.
561     */
562    async cacheBustedFetchFromNetwork(req) {
563      const url = this.adapter.normalizeUrl(req.url);
564      if (this.hashes.has(url)) {
565        const canonicalHash = this.hashes.get(url);
566        let response = await this.safeFetch(req);
567        let makeCacheBustedRequest = response.ok;
568        if (makeCacheBustedRequest) {
569          const fetchedHash = sha1Binary(await response.clone().arrayBuffer());
570          makeCacheBustedRequest = fetchedHash !== canonicalHash;
571        }
572        if (makeCacheBustedRequest) {
573          const cacheBustReq = this.newRequestWithMetadata(this.cacheBust(req.url), req);
574          response = await this.safeFetch(cacheBustReq);
575          if (response.ok) {
576            const cacheBustedHash = sha1Binary(await response.clone().arrayBuffer());
577            if (canonicalHash !== cacheBustedHash) {
578              throw new SwCriticalError(`Hash mismatch (cacheBustedFetchFromNetwork): ${req.url}: expected ${canonicalHash}, got ${cacheBustedHash} (after cache busting)`);
579            }
580          }
581        }
582        if (!response.ok && response.status === 404) {
583          throw new SwUnrecoverableStateError(`Failed to retrieve hashed resource from the server. (AssetGroup: ${this.config.name} | URL: ${url})`);
584        }
585        return response;
586      } else {
587        return this.safeFetch(req);
588      }
589    }
590    /**
591     * Possibly update a resource, if it's expired and needs to be updated. A no-op otherwise.
592     */
593    async maybeUpdate(updateFrom, req, cache) {
594      const url = this.adapter.normalizeUrl(req.url);
595      if (this.hashes.has(url)) {
596        const hash = this.hashes.get(url);
597        const res = await updateFrom.lookupResourceWithHash(url, hash);
598        if (res !== null) {
599          await cache.put(req, res);
600          return true;
601        }
602      }
603      return false;
604    }
605    /**
606     * Create a new `Request` based on the specified URL and `RequestInit` options, preserving only
607     * metadata that are known to be safe.
608     *
609     * Currently, headers, referrer, referrer policy, redirect policy, an explicit
610     * `credentials: 'omit'`, and the HTTP cache mode are preserved. On cross-origin redirects,
611     * sensitive headers are removed. This includes `Authorization`, as required by the Fetch redirect
612     * algorithm, and forbidden request headers that could contain credentials.
613     *
614     * NOTE:
615     *   `credentials: 'same-origin'` and `credentials: 'include'` are intentionally not preserved.
616     *   Forwarding `'include'` could leak cookies to cross-origin asset hosts, and forwarding
617     *   `'same-origin'` matches the default `fetch()` behavior so there is nothing to preserve.
618     *   Requests with `cache: 'only-if-cached'` and `mode !== 'same-origin'` are short-circuited
619     *   earlier in `Driver.onFetch()` (they are a known Chrome DevTools quirk), so no special
620     *   handling for that combination is needed here.
621     * TODO(gkalpak):
622     *   Investigate preserving more metadata. See, also, discussion on preserving `mode`:
623     *   https://github.com/angular/angular/issues/41931#issuecomment-1227601347.
624     */
625    newRequestWithMetadata(url, options) {
626      let headers = options.headers;
627      const parsedUrl = this.adapter.parseUrl(url, this.adapter.origin);
628      const hasHeaders = headers.keys().next().done !== true;
629      if (hasHeaders && parsedUrl.origin !== this.adapter.origin) {
630        headers = this.adapter.newHeaders(options.headers);
631        headers.delete("Authorization");
632        headers.delete("Proxy-Authorization");
633        headers.delete("Cookie");
634      }
635      const init = {
636        headers,
637        referrer: options.referrer,
638        referrerPolicy: options.referrerPolicy,
639        redirect: options.redirect
640      };
641      if (options.credentials === "omit") {
642        init.credentials = "omit";
643      }
644      if (options.cache !== void 0) {
645        init.cache = options.cache;
646      }
647      return this.adapter.newRequest(url, init);
648    }
649    /**
650     * Construct a cache-busting URL for a given URL.
651     */
652    cacheBust(url) {
653      return url + (url.indexOf("?") === -1 ? "?" : "&") + "ngsw-cache-bust=" + Math.random();
654    }
655    async safeFetch(req) {
656      try {
657        return await this.scope.fetch(req);
658      } catch (e) {
659        return this.adapter.newResponse("", {
660          status: 504,
661          statusText: "Gateway Timeout"
662        });
663      }
664    }
665  };
666  var PrefetchAssetGroup = class extends AssetGroup {
667    async initializeFully(updateFrom) {
668      const cache = await this.cache;
669      await this.urls.reduce(async (previous, url) => {
670        await previous;
671        const req = this.adapter.newRequest(url);
672        let alreadyCached = false;
673        try {
674          alreadyCached = await cache.match(req, this.config.cacheQueryOptions) !== void 0;
675        } catch (error) {
676          throw new SwCriticalError(`Cache is throwing while looking for a match in a PrefetchAssetGroup: ${error}`);
677        }
678        if (alreadyCached) {
679          return;
680        }
681        if (updateFrom !== void 0 && await this.maybeUpdate(updateFrom, req, cache)) {
682          return;
683        }
684        await this.fetchAndCacheOnce(req, false);
685      }, Promise.resolve());
686      if (updateFrom !== void 0) {
687        const metaTable = await this.metadata;
688        await (await updateFrom.previouslyCachedResources()).filter((url) => this.urls.indexOf(url) !== -1 || this.patterns.some((pattern) => pattern.test(url))).reduce(async (previous, url) => {
689          await previous;
690          const req = this.adapter.newRequest(url);
691          const alreadyCached = await cache.match(req, this.config.cacheQueryOptions) !== void 0;
692          if (alreadyCached) {
693            return;
694          }
695          const res = await updateFrom.lookupResourceWithoutHash(url);
696          if (res === null || res.metadata === void 0) {
697            return;
698          }
699          await cache.put(req, res.response);
700          await metaTable.write(req.url, __spreadProps(__spreadValues({}, res.metadata), { used: false }));
701        }, Promise.resolve());
702      }
703    }
704  };
705  var LazyAssetGroup = class extends AssetGroup {
706    async initializeFully(updateFrom) {
707      if (updateFrom === void 0) {
708        return;
709      }
710      const cache = await this.cache;
711      await this.urls.reduce(async (previous, url) => {
712        await previous;
713        const req = this.adapter.newRequest(url);
714        let alreadyCached = false;
715        try {
716          alreadyCached = await cache.match(req, this.config.cacheQueryOptions) !== void 0;
717        } catch (error) {
718          throw new SwCriticalError(`Cache is throwing while looking for a match in a LazyAssetGroup: ${error}`);
719        }
720        if (alreadyCached) {
721          return;
722        }
723        const updated = await this.maybeUpdate(updateFrom, req, cache);
724        if (this.config.updateMode === "prefetch" && !updated) {
725          const cacheStatus = await updateFrom.recentCacheStatus(url);
726          if (cacheStatus !== UpdateCacheStatus.CACHED) {
727            return;
728          }
729          await this.fetchAndCacheOnce(req, false);
730        }
731      }, Promise.resolve());
732    }
733  };
734
735  
735// packages/service-worker/worker/src/data.js
736  var LruList = class {
737    constructor(state) {
738      __publicField(this, "state");
739      if (state === void 0) {
740        state = {
741          head: null,
742          tail: null,
743          map: {},
744          count: 0
745        };
746      }
747      this.state = state;
748    }
749    /**
750     * The current count of URLs in the list.
751     */
752    get size() {
753      return this.state.count;
754    }
755    /**
756     * Remove the tail.
757     */
758    pop() {
759      if (this.state.tail === null) {
760        return null;
761      }
762      const url = this.state.tail;
763      this.remove(url);
764      return url;
765    }
766    remove(url) {
767      const node = this.state.map[url];
768      if (node === void 0) {
769        return false;
770      }
771      if (this.state.head === url) {
772        if (node.next === null) {
773          this.state.head = null;
774          this.state.tail = null;
775          this.state.map = {};
776          this.state.count = 0;
777          return true;
778        }
779        const next = this.state.map[node.next];
780        next.previous = null;
781        this.state.head = next.url;
782        node.next = null;
783        delete this.state.map[url];
784        this.state.count--;
785        return true;
786      }
787      const previous = this.state.map[node.previous];
788      previous.next = node.next;
789      if (node.next !== null) {
790        this.state.map[node.next].previous = node.previous;
791      } else {
792        this.state.tail = node.previous;
793      }
794      node.next = null;
795      node.previous = null;
796      delete this.state.map[url];
797      this.state.count--;
798      return true;
799    }
800    accessed(url) {
801      if (this.state.head === url) {
802        return;
803      }
804      const node = this.state.map[url] || { url, next: null, previous: null };
805      if (this.state.map[url] !== void 0) {
806        this.remove(url);
807      }
808      if (this.state.head !== null) {
809        this.state.map[this.state.head].previous = url;
810      }
811      node.next = this.state.head;
812      this.state.head = url;
813      if (this.state.tail === null) {
814        this.state.tail = url;
815      }
816      this.state.map[url] = node;
817      this.state.count++;
818    }
819  };
820  var DataGroup = class {
821    constructor(scope2, adapter2, config, db, debugHandler, cacheNamePrefix) {
822      __publicField(this, "scope");
823      __publicField(this, "adapter");
824      __publicField(this, "config");
825      __publicField(this, "db");
826      __publicField(this, "debugHandler");
827      /**
828       * Compiled regular expression set used to determine which resources fall under the purview
829       * of this group.
830       */
831      __publicField(this, "patterns");
832      /**
833       * The `Cache` instance in which resources belonging to this group are cached.
834       */
835      __publicField(this, "cache");
836      /**
837       * Tracks the LRU state of resources in this cache.
838       */
839      __publicField(this, "_lru", null);
840      /**
841       * Database table used to store the state of the LRU cache.
842       */
843      __publicField(this, "lruTable");
844      /**
845       * Database table used to store metadata for resources in the cache.
846       */
847      __publicField(this, "ageTable");
848      this.scope = scope2;
849      this.adapter = adapter2;
850      this.config = config;
851      this.db = db;
852      this.debugHandler = debugHandler;
853      this.patterns = config.patterns.map((pattern) => new RegExp(pattern));
854      this.cache = adapter2.caches.open(`${cacheNamePrefix}:${config.name}:cache`);
855      this.lruTable = this.db.open(`${cacheNamePrefix}:${config.name}:lru`, config.cacheQueryOptions);
856      this.ageTable = this.db.open(`${cacheNamePrefix}:${config.name}:age`, config.cacheQueryOptions);
857    }
858    /**
859     * Lazily initialize/load the LRU chain.
860     */
861    async lru() {
862      if (this._lru === null) {
863        const table = await this.lruTable;
864        try {
865          this._lru = new LruList(await table.read("lru"));
866        } catch (e) {
867          this._lru = new LruList();
868        }
869      }
870      return this._lru;
871    }
872    /**
873     * Sync the LRU chain to non-volatile storage.
874     */
875    async syncLru() {
876      if (this._lru === null) {
877        return;
878      }
879      const table = await this.lruTable;
880      try {
881        return table.write("lru", this._lru.state);
882      } catch (err) {
883        this.debugHandler.log(err, `DataGroup(${this.config.name}@${this.config.version}).syncLru()`);
884        await this.detectStorageFull();
885      }
886    }
887    /**
888     * Process a fetch event and return a `Response` if the resource is covered by this group,
889     * or `null` otherwise.
890     */
891    async handleFetch(req, event) {
892      if (!this.patterns.some((pattern) => pattern.test(req.url))) {
893        return null;
894      }
895      const lru = await this.lru();
896      switch (req.method) {
897        case "OPTIONS":
898          return null;
899        case "GET":
900        case "HEAD":
901          switch (this.config.strategy) {
902            case "freshness":
903              return this.handleFetchWithFreshness(req, event, lru);
904            case "performance":
905              return this.handleFetchWithPerformance(req, event, lru);
906            default:
907              throw new Error(`Unknown strategy: ${this.config.strategy}`);
908          }
909        default:
910          const wasCached = lru.remove(req.url);
911          if (wasCached) {
912            await this.clearCacheForUrl(req.url);
913          }
914          await this.syncLru();
915          return this.safeFetch(req);
916      }
917    }
918    async handleFetchWithPerformance(req, event, lru) {
919      var _a;
920      const okToCacheOpaque = (_a = this.config.cacheOpaqueResponses) != null ? _a : false;
921      let res = null;
922      const fromCache = await this.loadFromCache(req, lru);
923      if (fromCache !== null) {
924        res = fromCache.res;
925        if (this.config.refreshAheadMs !== void 0 && fromCache.age >= this.config.refreshAheadMs) {
926          event.waitUntil(this.safeCacheResponse(req, this.safeFetch(req), lru, okToCacheOpaque));
927        }
928      }
929      if (res !== null) {
930        return res;
931      }
932      const [timeoutFetch, networkFetch] = this.networkFetchWithTimeout(req);
933      res = await timeoutFetch;
934      if (res === void 0) {
935        res = this.adapter.newResponse(null, { status: 504, statusText: "Gateway Timeout" });
936        event.waitUntil(this.safeCacheResponse(req, networkFetch, lru, okToCacheOpaque));
937      } else {
938        await this.safeCacheResponse(req, res, lru, okToCacheOpaque);
939      }
940      return res;
941    }
942    async handleFetchWithFreshness(req, event, lru) {
943      var _a;
944      const okToCacheOpaque = (_a = this.config.cacheOpaqueResponses) != null ? _a : true;
945      const [timeoutFetch, networkFetch] = this.networkFetchWithTimeout(req);
946      let res;
947      try {
948        res = await timeoutFetch;
949      } catch (e) {
950        res = void 0;
951      }
952      if (res === void 0) {
953        event.waitUntil(this.safeCacheResponse(req, networkFetch, lru, okToCacheOpaque));
954        const fromCache = await this.loadFromCache(req, lru);
955        res = fromCache !== null ? fromCache.res : null;
956      } else {
957        await this.safeCacheResponse(req, res, lru, okToCacheOpaque);
958      }
959      if (res !== null) {
960        return res;
961      }
962      return networkFetch;
963    }
964    networkFetchWithTimeout(req) {
965      if (this.config.timeoutMs !== void 0) {
966        const networkFetch = this.scope.fetch(req);
967        const safeNetworkFetch = (async () => {
968          try {
969            return await networkFetch;
970          } catch (e) {
971            return this.adapter.newResponse(null, {
972              status: 504,
973              statusText: "Gateway Timeout"
974            });
975          }
976        })();
977        const networkFetchUndefinedError = (async () => {
978          try {
979            return await networkFetch;
980          } catch (e) {
981            return void 0;
982          }
983        })();
984        const timeout = this.adapter.timeout(this.config.timeoutMs);
985        return [Promise.race([networkFetchUndefinedError, timeout]), safeNetworkFetch];
986      } else {
987        const networkFetch = this.safeFetch(req);
988        return [networkFetch, networkFetch];
989      }
990    }
991    async safeCacheResponse(req, resOrPromise, lru, okToCacheOpaque) {
992      try {
993        const res = await resOrPromise;
994        try {
995          await this.cacheResponse(req, res, lru, okToCacheOpaque);
996        } catch (err) {
997          this.debugHandler.log(err, `DataGroup(${this.config.name}@${this.config.version}).safeCacheResponse(${req.url}, status: ${res.status})`);
998          await this.detectStorageFull();
999        }
1000      } catch (e) {
1001      }
1002    }
1003    async loadFromCache(req, lru) {
1004      const cache = await this.cache;
1005      let res = await cache.match(req, this.config.cacheQueryOptions);
1006      if (res !== void 0) {
1007        try {
1008          const ageTable = await this.ageTable;
1009          const age = this.adapter.time - (await ageTable.read(req.url)).age;
1010          if (age <= this.config.maxAge) {
1011            lru.accessed(req.url);
1012            return { res, age };
1013          }
1014        } catch (e) {
1015        }
1016        lru.remove(req.url);
1017        await this.clearCacheForUrl(req.url);
1018        await this.syncLru();
1019      }
1020      return null;
1021    }
1022    /**
1023     * Operation for caching the response from the server. This has to happen all
1024     * at once, so that the cache and LRU tracking remain in sync. If the network request
1025     * completes before the timeout, this logic will be run inline with the response flow.
1026     * If the request times out on the server, an error will be returned but the real network
1027     * request will still be running in the background, to be cached when it completes.
1028     */
1029    async cacheResponse(req, res, lru, okToCacheOpaque = false) {
1030      if (!(res.ok || okToCacheOpaque && res.type === "opaque")) {
1031        return;
1032      }
1033      if (lru.size >= this.config.maxSize) {
1034        const evictedUrl = lru.pop();
1035        if (evictedUrl !== null) {
1036          await this.clearCacheForUrl(evictedUrl);
1037        }
1038      }
1039      lru.accessed(req.url);
1040      await (await this.cache).put(req, res.clone());
1041      const ageTable = await this.ageTable;
1042      await ageTable.write(req.url, { age: this.adapter.time });
1043      await this.syncLru();
1044    }
1045    /**
1046     * Delete all of the saved state which this group uses to track resources.
1047     */
1048    async cleanup() {
1049      await Promise.all([
1050        this.cache.then((cache) => this.adapter.caches.delete(cache.name)),
1051        this.ageTable.then((table) => this.db.delete(table.name)),
1052        this.lruTable.then((table) => this.db.delete(table.name))
1053      ]);
1054    }
1055    /**
1056     * Return a list of the names of all caches used by this group.
1057     */
1058    async getCacheNames() {
1059      const [cache, ageTable, lruTable] = await Promise.all([
1060        this.cache,
1061        this.ageTable,
1062        this.lruTable
1063      ]);
1064      return [cache.name, ageTable.cacheName, lruTable.cacheName];
1065    }
1066    /**
1067     * Clear the state of the cache for a particular resource.
1068     *
1069     * This doesn't remove the resource from the LRU table, that is assumed to have
1070     * been done already. This clears the GET and HEAD versions of the request from
1071     * the cache itself, as well as the metadata stored in the age table.
1072     */
1073    async clearCacheForUrl(url) {
1074      const [cache, ageTable] = await Promise.all([this.cache, this.ageTable]);
1075      await Promise.all([
1076        cache.delete(this.adapter.newRequest(url, { method: "GET" }), this.config.cacheQueryOptions),
1077        cache.delete(this.adapter.newRequest(url, { method: "HEAD" }), this.config.cacheQueryOptions),
1078        ageTable.delete(url)
1079      ]);
1080    }
1081    async safeFetch(req) {
1082      try {
1083        return this.scope.fetch(req);
1084      } catch (e) {
1085        return this.adapter.newResponse(null, {
1086          status: 504,
1087          statusText: "Gateway Timeout"
1088        });
1089      }
1090    }
1091    /**
1092     * Detect if storage is full or approaching capacity.
1093     * Returns true if storage is at or near capacity.
1094     */
1095    async detectStorageFull() {
1096      try {
1097        const estimate = await navigator.storage.estimate();
1098        const { quota, usage } = estimate;
1099        if (typeof quota !== "number" || typeof usage !== "number") {
1100          return;
1101        }
1102        const usagePercentage = usage / quota * 100;
1103        const isStorageFull = usagePercentage >= 95;
1104        if (isStorageFull) {
1105          this.debugHandler.log("Storage is full or nearly full", `DataGroup(${this.config.name}@${this.config.version}).detectStorageFull()`);
1106        }
1107      } catch (e) {
1108      }
1109    }
1110  };
1111
1112  
1112// packages/service-worker/worker/src/app-version.js
1113  var AppVersion = class {
1114    constructor(scope2, adapter2, database, idle, debugHandler, manifest, manifestHash) {
1115      __publicField(this, "scope");
1116      __publicField(this, "adapter");
1117      __publicField(this, "database");
1118      __publicField(this, "debugHandler");
1119      __publicField(this, "manifest");
1120      __publicField(this, "manifestHash");
1121      /**
1122       * A Map of absolute URL paths (`/foo.txt`) to the known hash of their contents (if available).
1123       */
1124      __publicField(this, "hashTable", /* @__PURE__ */ new Map());
1125      /**
1126       * All of the asset groups active in this version of the app.
1127       */
1128      __publicField(this, "assetGroups");
1129      /**
1130       * All of the data groups active in this version of the app.
1131       */
1132      __publicField(this, "dataGroups");
1133      /**
1134       * Requests to URLs that match any of the `include` RegExps and none of the `exclude` RegExps
1135       * are considered navigation requests and handled accordingly.
1136       */
1137      __publicField(this, "navigationUrls");
1138      /**
1139       * The normalized URL to the file that serves as the index page to satisfy navigation requests.
1140       * Usually this is `/index.html`.
1141       */
1142      __publicField(this, "indexUrl");
1143      /**
1144       * Tracks whether the manifest has encountered any inconsistencies.
1145       */
1146      __publicField(this, "_okay", true);
1147      this.scope = scope2;
1148      this.adapter = adapter2;
1149      this.database = database;
1150      this.debugHandler = debugHandler;
1151      this.manifest = manifest;
1152      this.manifestHash = manifestHash;
1153      this.indexUrl = this.adapter.normalizeUrl(this.manifest.index);
1154      Object.keys(manifest.hashTable).forEach((url) => {
1155        this.hashTable.set(adapter2.normalizeUrl(url), manifest.hashTable[url]);
1156      });
1157      const assetCacheNamePrefix = `${manifestHash}:assets`;
1158      this.assetGroups = (manifest.assetGroups || []).map((config) => {
1159        switch (config.installMode) {
1160          case "prefetch":
1161            return new PrefetchAssetGroup(scope2, adapter2, idle, config, this.hashTable, database, assetCacheNamePrefix);
1162          case "lazy":
1163            return new LazyAssetGroup(scope2, adapter2, idle, config, this.hashTable, database, assetCacheNamePrefix);
1164        }
1165      });
1166      this.dataGroups = (manifest.dataGroups || []).map((config) => new DataGroup(scope2, adapter2, config, database, debugHandler, `${config.version}:data`));
1167      const includeUrls = manifest.navigationUrls.filter((spec) => spec.positive);
1168      const excludeUrls = manifest.navigationUrls.filter((spec) => !spec.positive);
1169      this.navigationUrls = {
1170        include: includeUrls.map((spec) => new RegExp(spec.regex)),
1171        exclude: excludeUrls.map((spec) => new RegExp(spec.regex))
1172      };
1173    }
1174    get okay() {
1175      return this._okay;
1176    }
1177    /**
1178     * Fully initialize this version of the application. If this Promise resolves successfully, all
1179     * required
1180     * data has been safely downloaded.
1181     */
1182    async initializeFully(updateFrom) {
1183      try {
1184        await this.assetGroups.reduce(async (previous, group) => {
1185          await previous;
1186          return group.initializeFully(updateFrom);
1187        }, Promise.resolve());
1188      } catch (err) {
1189        this._okay = false;
1190        throw err;
1191      }
1192    }
1193    async handleFetch(req, event) {
1194      const asset = await this.assetGroups.reduce(async (potentialResponse, group) => {
1195        const resp = await potentialResponse;
1196        if (resp !== null) {
1197          return resp;
1198        }
1199        return group.handleFetch(req, event);
1200      }, Promise.resolve(null));
1201      if (asset !== null) {
1202        return asset;
1203      }
1204      const data = await this.dataGroups.reduce(async (potentialResponse, group) => {
1205        const resp = await potentialResponse;
1206        if (resp !== null) {
1207          return resp;
1208        }
1209        return group.handleFetch(req, event);
1210      }, Promise.resolve(null));
1211      if (data !== null) {
1212        return data;
1213      }
1214      if (this.adapter.normalizeUrl(req.url) !== this.indexUrl && this.isNavigationRequest(req)) {
1215        if (this.manifest.navigationRequestStrategy === "freshness") {
1216          try {
1217            return await this.scope.fetch(req);
1218          } catch (e) {
1219          }
1220        }
1221        return this.handleFetch(this.adapter.newRequest(this.indexUrl), event);
1222      }
1223      return null;
1224    }
1225    /**
1226     * Determine whether the request is a navigation request.
1227     * Takes into account: Request method and mode, `Accept` header, `navigationUrls` patterns.
1228     */
1229    isNavigationRequest(req) {
1230      if (req.method !== "GET" || req.mode !== "navigate") {
1231        return false;
1232      }
1233      if (!this.acceptsTextHtml(req)) {
1234        return false;
1235      }
1236      const urlPrefix = this.scope.registration.scope.replace(/\/$/, "");
1237      const url = req.url.startsWith(urlPrefix) ? req.url.slice(urlPrefix.length) : req.url;
1238      const urlWithoutQueryOrHash = url.replace(/[?#].*$/, "");
1239      return this.navigationUrls.include.some((regex) => regex.test(urlWithoutQueryOrHash)) && !this.navigationUrls.exclude.some((regex) => regex.test(urlWithoutQueryOrHash));
1240    }
1241    /**
1242     * Check this version for a given resource with a particular hash.
1243     */
1244    async lookupResourceWithHash(url, hash) {
1245      if (!this.hashTable.has(url)) {
1246        return null;
1247      }
1248      if (this.hashTable.get(url) !== hash) {
1249        return null;
1250      }
1251      const cacheState = await this.lookupResourceWithoutHash(url);
1252      return cacheState && cacheState.response;
1253    }
1254    /**
1255     * Check this version for a given resource regardless of its hash.
1256     */
1257    lookupResourceWithoutHash(url) {
1258      return this.assetGroups.reduce(async (potentialResponse, group) => {
1259        const resp = await potentialResponse;
1260        if (resp !== null) {
1261          return resp;
1262        }
1263        return group.fetchFromCacheOnly(url);
1264      }, Promise.resolve(null));
1265    }
1266    /**
1267     * List all unhashed resources from all asset groups.
1268     */
1269    previouslyCachedResources() {
1270      return this.assetGroups.reduce(async (resources, group) => (await resources).concat(await group.unhashedResources()), Promise.resolve([]));
1271    }
1272    async recentCacheStatus(url) {
1273      return this.assetGroups.reduce(async (current, group) => {
1274        const status = await current;
1275        if (status === UpdateCacheStatus.CACHED) {
1276          return status;
1277        }
1278        const groupStatus = await group.cacheStatus(url);
1279        if (groupStatus === UpdateCacheStatus.NOT_CACHED) {
1280          return status;
1281        }
1282        return groupStatus;
1283      }, Promise.resolve(UpdateCacheStatus.NOT_CACHED));
1284    }
1285    /**
1286     * Return a list of the names of all caches used by this version.
1287     */
1288    async getCacheNames() {
1289      const allGroupCacheNames = await Promise.all([
1290        ...this.assetGroups.map((group) => group.getCacheNames()),
1291        ...this.dataGroups.map((group) => group.getCacheNames())
1292      ]);
1293      return [].concat(...allGroupCacheNames);
1294    }
1295    /**
1296     * Get the opaque application data which was provided with the manifest.
1297     */
1298    get appData() {
1299      return this.manifest.appData || null;
1300    }
1301    /**
1302     * Check whether a request accepts `text/html` (based on the `Accept` header).
1303     */
1304    acceptsTextHtml(req) {
1305      const accept = req.headers.get("Accept");
1306      if (accept === null) {
1307        return false;
1308      }
1309      const values = accept.split(",");
1310      return values.some((value) => value.trim().toLowerCase() === "text/html");
1311    }
1312  };
1313
1314  
1314// packages/service-worker/worker/src/debug.js
1315  var SW_VERSION = "21.2.21";
1316  var DEBUG_LOG_BUFFER_SIZE = 100;
1317  var DebugHandler = class {
1318    constructor(driver, adapter2) {
1319      __publicField(this, "driver");
1320      __publicField(this, "adapter");
1321      // There are two debug log message arrays. debugLogA records new debugging messages.
1322      // Once it reaches DEBUG_LOG_BUFFER_SIZE, the array is moved to debugLogB and a new
1323      // array is assigned to debugLogA. This ensures that insertion to the debug log is
1324      // always O(1) no matter the number of logged messages, and that the total number
1325      // of messages in the log never exceeds 2 * DEBUG_LOG_BUFFER_SIZE.
1326      __publicField(this, "debugLogA", []);
1327      __publicField(this, "debugLogB", []);
1328      this.driver = driver;
1329      this.adapter = adapter2;
1330    }
1331    async handleFetch(req) {
1332      const [state, versions, idle] = await Promise.all([
1333        this.driver.debugState(),
1334        this.driver.debugVersions(),
1335        this.driver.debugIdleState()
1336      ]);
1337      const msgState = `NGSW Debug Info:
1338
1339Driver version: ${SW_VERSION}
1340Driver state: ${state.state} (${state.why})
1341Latest manifest hash: ${state.latestHash || "none"}
1342Last update check: ${this.since(state.lastUpdateCheck)}`;
1343      const msgVersions = versions.map((version) => `=== Version ${version.hash} ===
1344
1345Clients: ${version.clients.join(", ")}`).join("\n\n");
1346      const msgIdle = `=== Idle Task Queue ===
1347Last update tick: ${this.since(idle.lastTrigger)}
1348Last update run: ${this.since(idle.lastRun)}
1349Task queue:
1350${idle.queue.map((v) => " * " + v).join("\n")}
1351
1352Debug log:
1353${this.formatDebugLog(this.debugLogB)}
1354${this.formatDebugLog(this.debugLogA)}
1355`;
1356      return this.adapter.newResponse(`${msgState}
1357
1358${msgVersions}
1359
1360${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }) });
1361    }
1362    since(time) {
1363      if (time === null) {
1364        return "never";
1365      }
1366      let age = this.adapter.time - time;
1367      const days = Math.floor(age / 864e5);
1368      age = age % 864e5;
1369      const hours = Math.floor(age / 36e5);
1370      age = age % 36e5;
1371      const minutes = Math.floor(age / 6e4);
1372      age = age % 6e4;
1373      const seconds = Math.floor(age / 1e3);
1374      const millis = age % 1e3;
1375      return (days > 0 ? `${days}d` : "") + (hours > 0 ? `${hours}h` : "") + (minutes > 0 ? `${minutes}m` : "") + (seconds > 0 ? `${seconds}s` : "") + (millis > 0 ? `${millis}u` : "");
1376    }
1377    log(value, context = "") {
1378      if (this.debugLogA.length === DEBUG_LOG_BUFFER_SIZE) {
1379        this.debugLogB = this.debugLogA;
1380        this.debugLogA = [];
1381      }
1382      if (typeof value !== "string") {
1383        value = this.errorToString(value);
1384      }
1385      this.debugLogA.push({ value, time: this.adapter.time, context });
1386    }
1387    errorToString(err) {
1388      return `${err.name}(${err.message}, ${err.stack})`;
1389    }
1390    formatDebugLog(log) {
1391      return log.map((entry) => `[${this.since(entry.time)}] ${entry.value} ${entry.context}`).join("\n");
1392    }
1393  };
1394
1395  
1395// packages/service-worker/worker/src/idle.js
1396  var IdleScheduler = class {
1397    constructor(adapter2, delay, maxDelay, debug) {
1398      __publicField(this, "adapter");
1399      __publicField(this, "delay");
1400      __publicField(this, "maxDelay");
1401      __publicField(this, "debug");
1402      __publicField(this, "queue", []);
1403      __publicField(this, "scheduled", null);
1404      __publicField(this, "empty", Promise.resolve());
1405      __publicField(this, "emptyResolve", null);
1406      __publicField(this, "lastTrigger", null);
1407      __publicField(this, "lastRun", null);
1408      __publicField(this, "oldestScheduledAt", null);
1409      this.adapter = adapter2;
1410      this.delay = delay;
1411      this.maxDelay = maxDelay;
1412      this.debug = debug;
1413    }
1414    async trigger() {
1415      var _a;
1416      this.lastTrigger = this.adapter.time;
1417      if (this.queue.length === 0) {
1418        return;
1419      }
1420      if (this.scheduled !== null) {
1421        this.scheduled.cancel = true;
1422      }
1423      const scheduled = {
1424        cancel: false
1425      };
1426      this.scheduled = scheduled;
1427      const now = this.adapter.time;
1428      const maxDelay = Math.max(0, ((_a = this.oldestScheduledAt) != null ? _a : now) + this.maxDelay - now);
1429      const delay = Math.min(maxDelay, this.delay);
1430      await this.adapter.timeout(delay);
1431      if (scheduled.cancel) {
1432        return;
1433      }
1434      this.scheduled = null;
1435      await this.execute();
1436    }
1437    async execute() {
1438      this.lastRun = this.adapter.time;
1439      while (this.queue.length > 0) {
1440        const queue = this.queue;
1441        this.queue = [];
1442        await queue.reduce(async (previous, task) => {
1443          await previous;
1444          try {
1445            await task.run();
1446          } catch (err) {
1447            this.debug.log(err, `while running idle task ${task.desc}`);
1448          }
1449        }, Promise.resolve());
1450      }
1451      if (this.emptyResolve !== null) {
1452        this.emptyResolve();
1453        this.emptyResolve = null;
1454      }
1455      this.empty = Promise.resolve();
1456      this.oldestScheduledAt = null;
1457    }
1458    schedule(desc, run) {
1459      this.queue.push({ desc, run });
1460      if (this.emptyResolve === null) {
1461        this.empty = new Promise((resolve) => {
1462          this.emptyResolve = resolve;
1463        });
1464      }
1465      if (this.oldestScheduledAt === null) {
1466        this.oldestScheduledAt = this.adapter.time;
1467      }
1468    }
1469    get size() {
1470      return this.queue.length;
1471    }
1472    get taskDescriptions() {
1473      return this.queue.map((task) => task.desc);
1474    }
1475  };
1476
1477  
1477// packages/service-worker/worker/src/manifest.js
1478  function hashManifest(manifest) {
1479    return sha1(JSON.stringify(manifest));
1480  }
1481
1482  
1482// packages/service-worker/worker/src/msg.js
1483  function isMsgCheckForUpdates(msg) {
1484    return msg.action === "CHECK_FOR_UPDATES";
1485  }
1486  function isMsgActivateUpdate(msg) {
1487    return msg.action === "ACTIVATE_UPDATE";
1488  }
1489
1490  
1490// packages/service-worker/worker/src/driver.js
1491  var IDLE_DELAY = 5e3;
1492  var MAX_IDLE_DELAY = 3e4;
1493  var SUPPORTED_CONFIG_VERSION = 1;
1494  var NOTIFICATION_OPTION_NAMES = [
1495    "actions",
1496    "badge",
1497    "body",
1498    "data",
1499    "dir",
1500    "icon",
1501    "image",
1502    "lang",
1503    "renotify",
1504    "requireInteraction",
1505    "silent",
1506    "tag",
1507    "timestamp",
1508    "title",
1509    "vibrate"
1510  ];
1511  function isLocalhost(scope2) {
1512    return /(?:^https?:\/\/)?(?:(?:^|[^\w.])localhost|\[::1\]|127(?:\.\d{1,3}){3})(?::\d+)?(?:\/.*)?$/.test(scope2);
1513  }
1514  var DriverReadyState;
1515  (function(DriverReadyState2) {
1516    DriverReadyState2[DriverReadyState2["NORMAL"] = 0] = "NORMAL";
1517    DriverReadyState2[DriverReadyState2["EXISTING_CLIENTS_ONLY"] = 1] = "EXISTING_CLIENTS_ONLY";
1518    DriverReadyState2[DriverReadyState2["SAFE_MODE"] = 2] = "SAFE_MODE";
1519  })(DriverReadyState || (DriverReadyState = {}));
1520  var Driver = class {
1521    constructor(scope2, adapter2, db) {
1522      __publicField(this, "scope");
1523      __publicField(this, "adapter");
1524      __publicField(this, "db");
1525      /**
1526       * Tracks the current readiness condition under which the SW is operating. This controls
1527       * whether the SW attempts to respond to some or all requests.
1528       */
1529      __publicField(this, "state", DriverReadyState.NORMAL);
1530      __publicField(this, "stateMessage", "(nominal)");
1531      /**
1532       * Tracks whether the SW is in an initialized state or not. Before initialization,
1533       * it's not legal to respond to requests.
1534       */
1535      __publicField(this, "initialized", null);
1536      /**
1537       * Maps client IDs to the manifest hash of the application version being used to serve
1538       * them. If a client ID is not present here, it has not yet been assigned a version.
1539       *
1540       * If a ManifestHash appears here, it is also present in the `versions` map below.
1541       */
1542      __publicField(this, "clientVersionMap", /* @__PURE__ */ new Map());
1543      /**
1544       * Maps manifest hashes to instances of `AppVersion` for those manifests.
1545       */
1546      __publicField(this, "versions", /* @__PURE__ */ new Map());
1547      /**
1548       * The latest version fetched from the server.
1549       *
1550       * Valid after initialization has completed.
1551       */
1552      __publicField(this, "latestHash", null);
1553      __publicField(this, "lastUpdateCheck", null);
1554      /**
1555       * Whether there is a check for updates currently scheduled due to navigation.
1556       */
1557      __publicField(this, "scheduledNavUpdateCheck", false);
1558      /**
1559       * Keep track of whether we have logged an invalid `only-if-cached` request.
1560       * (See `.onFetch()` for details.)
1561       */
1562      __publicField(this, "loggedInvalidOnlyIfCachedRequest", false);
1563      __publicField(this, "ngswStatePath");
1564      /**
1565       * A scheduler which manages a queue of tasks that need to be executed when the SW is
1566       * not doing any other work (not processing any other requests).
1567       */
1568      __publicField(this, "idle");
1569      __publicField(this, "debugger");
1570      // A promise resolving to the control DB table.
1571      __publicField(this, "controlTable");
1572      this.scope = scope2;
1573      this.adapter = adapter2;
1574      this.db = db;
1575      this.controlTable = this.db.open("control");
1576      this.ngswStatePath = this.adapter.parseUrl("ngsw/state", this.scope.registration.scope).path;
1577      this.scope.addEventListener("install", (event) => {
1578        event.waitUntil(this.scope.skipWaiting());
1579      });
1580      this.scope.addEventListener("activate", (event) => {
1581        event.waitUntil((async () => {
1582          await this.scope.clients.claim();
1583        })());
1584        if (this.scope.registration.active !== null) {
1585          this.scope.registration.active.postMessage({ action: "INITIALIZE" });
1586        }
1587      });
1588      this.scope.addEventListener("fetch", (event) => this.onFetch(event));
1589      this.scope.addEventListener("message", (event) => this.onMessage(event));
1590      this.scope.addEventListener("push", (event) => this.onPush(event));
1591      this.scope.addEventListener("notificationclick", (event) => this.onClick(event));
1592      this.scope.addEventListener("notificationclose", (event) => this.onClose(event));
1593      this.scope.addEventListener("pushsubscriptionchange", (event) => (
1594        // This is a bug in TypeScript, where they removed `PushSub
1594scriptionChangeEvent`
1595        // based on the incorrect assumption that browsers don't support it.
1596        this.onPushSubscriptionChange(event)
1597      ));
1598      this.scope.addEventListener("messageerror", (event) => this.onMessageError(event));
1599      this.scope.addEventListener("unhandledrejection", (event) => this.onUnhandledRejection(event));
1600      this.debugger = new DebugHandler(this, this.adapter);
1601      this.idle = new IdleScheduler(this.adapter, IDLE_DELAY, MAX_IDLE_DELAY, this.debugger);
1602    }
1603    /**
1604     * The handler for fetch events.
1605     *
1606     * This is the transition point between the synchronous event handler and the
1607     * asynchronous execution that eventually resolves for respondWith() and waitUntil().
1608     */
1609    onFetch(event) {
1610      const req = event.request;
1611      const scopeUrl = this.scope.registration.scope;
1612      const requestUrlObj = this.adapter.parseUrl(req.url, scopeUrl);
1613      if (req.headers.has("ngsw-bypass") || /[?&]ngsw-bypass(?:[=&]|$)/i.test(requestUrlObj.search)) {
1614        return;
1615      }
1616      if (requestUrlObj.path === this.ngswStatePath) {
1617        event.respondWith(this.debugger.handleFetch(req));
1618        return;
1619      }
1620      if (this.state === DriverReadyState.SAFE_MODE) {
1621        event.waitUntil(this.idle.trigger());
1622        return;
1623      }
1624      if (requestUrlObj.origin.startsWith("http:") && scopeUrl.startsWith("https:")) {
1625        this.debugger.log(`Ignoring passive mixed content request: Driver.fetch(${req.url})`);
1626        return;
1627      }
1628      if (req.cache === "only-if-cached" && req.mode !== "same-origin") {
1629        if (!this.loggedInvalidOnlyIfCachedRequest) {
1630          this.loggedInvalidOnlyIfCachedRequest = true;
1631          this.debugger.log(`Ignoring invalid request: 'only-if-cached' can be set only with 'same-origin' mode`, `Driver.fetch(${req.url}, cache: ${req.cache}, mode: ${req.mode})`);
1632        }
1633        return;
1634      }
1635      event.respondWith(this.handleFetch(event));
1636    }
1637    /**
1638     * The handler for message events.
1639     */
1640    onMessage(event) {
1641      if (this.state === DriverReadyState.SAFE_MODE) {
1642        return;
1643      }
1644      const data = event.data;
1645      if (!data || !data.action) {
1646        return;
1647      }
1648      event.waitUntil((async () => {
1649        if (data.action === "INITIALIZE") {
1650          return this.ensureInitialized(event);
1651        }
1652        if (!this.adapter.isClient(event.source)) {
1653          return;
1654        }
1655        await this.ensureInitialized(event);
1656        await this.handleMessage(data, event.source);
1657      })());
1658    }
1659    onPush(msg) {
1660      if (!msg.data) {
1661        return;
1662      }
1663      msg.waitUntil(this.handlePush(msg.data.json()));
1664    }
1665    onClick(event) {
1666      event.waitUntil(this.handleClick(event.notification, event.action));
1667    }
1668    onClose(event) {
1669      event.waitUntil(this.handleClose(event.notification, event.action));
1670    }
1671    onPushSubscriptionChange(event) {
1672      event.waitUntil(this.handlePushSubscriptionChange(event));
1673    }
1674    onMessageError(event) {
1675      this.debugger.log(`Message error occurred - data could not be deserialized`, `Driver.onMessageError(origin: ${event.origin})`);
1676    }
1677    onUnhandledRejection(event) {
1678      this.debugger.log(`Unhandled promise rejection occurred`, `Driver.onUnhandledRejection(reason: ${event.reason})`);
1679    }
1680    async ensureInitialized(event) {
1681      if (this.initialized !== null) {
1682        return this.initialized;
1683      }
1684      try {
1685        this.initialized = this.initialize();
1686        await this.initialized;
1687      } catch (error) {
1688        this.state = DriverReadyState.SAFE_MODE;
1689        this.stateMessage = `Initialization failed due to error: ${errorToString(error)}`;
1690        throw error;
1691      } finally {
1692        event.waitUntil(this.idle.trigger());
1693      }
1694    }
1695    async handleMessage(msg, from) {
1696      if (isMsgCheckForUpdates(msg)) {
1697        const action = this.checkForUpdate();
1698        await this.completeOperation(from, action, msg.nonce);
1699      } else if (isMsgActivateUpdate(msg)) {
1700        const action = this.updateClient(from);
1701        await this.completeOperation(from, action, msg.nonce);
1702      }
1703    }
1704    async handlePush(data) {
1705      await this.broadcast({
1706        type: "PUSH",
1707        data
1708      });
1709      if (!data.notification || !data.notification.title) {
1710        return;
1711      }
1712      const desc = data.notification;
1713      let options = {};
1714      NOTIFICATION_OPTION_NAMES.filter((name) =>
1714 desc.hasOwnProperty(name)).forEach((name) => options[name] = desc[name]);
1715      await this.scope.registration.showNotification(desc["title"], options);
1716    }
1717    async handleClick(notification, action) {
1718      var _a, _b, _c;
1719      notification.close();
1720      const options = {};
1721      NOTIFICATION_OPTION_NAMES.filter((name) => name in notification).forEach((name) => options[name] = notification[name]);
1722      const notificationAction = action === "" || action === void 0 ? "default" : action;
1723      const onActionClick = (_b = (_a = notification == null ? void 0 : notification.data) == null ? void 0 : _a.onActionClick) == null ? void 0 : _b[notificationAction];
1724      const urlToOpen = new URL((_c = onActionClick == null ? void 0 : onActionClick.url) != null ? _c : "", this.scope.registration.scope).href;
1725      switch (onActionClick == null ? void 0 : onActionClick.operation) {
1726        case "openWindow":
1727          await this.scope.clients.openWindow(urlToOpen);
1728          break;
1729        case "focusLastFocusedOrOpen": {
1730          let matchingClient = await this.getLastFocusedMatchingClient(this.scope);
1731          if (matchingClient) {
1732            await (matchingClient == null ? void 0 : matchingClient.focus());
1733          } else {
1734            await this.scope.clients.openWindow(urlToOpen);
1735          }
1736          break;
1737        }
1738        case "navigateLastFocusedOrOpen": {
1739          let matchingClient = await this.getLastFocusedMatchingClient(this.scope);
1740          if (matchingClient) {
1741            matchingClient = await matchingClient.navigate(urlToOpen);
1742            await (matchingClient == null ? void 0 : matchingClient.focus());
1743          } else {
1744            await this.scope.clients.openWindow(urlToOpen);
1745          }
1746          break;
1747        }
1748        case "sendRequest": {
1749          await this.scope.fetch(urlToOpen);
1750          break;
1751        }
1752        default:
1753          break;
1754      }
1755      await this.broadcast({
1756        type: "NOTIFICATION_CLICK",
1757        data: { action, notification: options }
1758      });
1759    }
1760    /**
1761     * Handles the closing of a notification by extracting its options and
1762     * broadcasting a `NOTIFICATION_CLOSE` message.
1763     *
1764     * This is typically called when a notification is dismissed by the user
1765     * or closed programmatically, and it relays that information to clients
1766     * listening for service worker events.
1767     *
1768     * @param notification - The original `Notification` object that was closed.
1769     * @param action - The action string associated with the close event, if any (usually an empty string).
1770     */
1771    async handleClose(notification, action) {
1772      const options = {};
1773      NOTIFICATION_OPTION_NAMES.filter((name) => name in notification).forEach((name) => options[name] = notification[name]);
1774      await this.broadcast({
1775        type: "NOTIFICATION_CLOSE",
1776        data: { action, notification: options }
1777      });
1778    }
1779    /**
1780     * Handles changes to the push subscription by capturing the old and new
1781     * subscription details and broadcasting a `PUSH_SUBSCRIPTION_CHANGE` message.
1782     *
1783     * This method is triggered when the browser invalidates an existing push
1784     * subscription and creates a new one, which can happen without user interaction.
1785     * It ensures that clients listening for service worker events are informed
1786     * of the subscription update.
1787     *
1788     * @param event - The `PushSubscriptionChangeEvent` containing the old and new subscriptions.
1789     */
1790    async handlePushSubscriptionChange(event) {
1791      const { oldSubscription, newSubscription } = event;
1792      await this.broadcast({
1793        type: "PUSH_SUBSCRIPTION_CHANGE",
1794        data: { oldSubscription, newSubscription }
1795      });
1796    }
1797    async getLastFocusedMatchingClient(scope2) {
1798      const windowClients = await scope2.clients.matchAll({ type: "window" });
1799      return windowClients[0];
1800    }
1801    async completeOperation(client, promise, nonce) {
1802      const response = { type: "OPERATION_COMPLETED", nonce };
1803      try {
1804        client.postMessage(__spreadProps(__spreadValues({}, response), {
1805          result: await promise
1806        }));
1807      } catch (e) {
1808        client.postMessage(__spreadProps(__spreadValues({}, response), {
1809          error: e.toString()
1810        }));
1811      }
1812    }
1813    async updateClient(client) {
1814      const existing = this.clientVersionMap.get(client.id);
1815      if (existing === this.latestHash) {
1816        return false;
1817      }
1818      let previous = void 0;
1819      if (existing !== void 0) {
1820        const existingVersion = this.versions.get(existing);
1821        previous = this.mergeHashWithAppData(existingVersion.manifest, existing);
1822      }
1823      this.clientVersionMap.set(client.id, this.latestHash);
1824      await this.sync();
1825      const current = this.versions.get(this.latestHash);
1826      return true;
1827    }
1828    async handleFetch(event) {
1829      try {
1830        await this.ensureInitialized(event);
1831      } catch (e) {
1832        return this.safeFetch(event.request);
1833      }
1834      if (event.request.mode === "navigate" && !this.scheduledNavUpdateCheck) {
1835        this.scheduledNavUpdateCheck = true;
1836        this.idle.schedule("check-updates-on-navigation", async () => {
1837          this.scheduledNavUpdateCheck = false;
1838          await this.checkForUpdate();
1839        });
1840      }
1841      const appVersion = await this.assignVersion(event);
1842      const isVersionWithinMaxAge = (appVersion == null ? void 0 : appVersion.manifest.applicationMaxAge) === void 0 || this.adapter.time - appVersion.manifest.timestamp < appVersion.manifest.applicationMaxAge;
1843      let res = null;
1844      try {
1845        if (appVersion !== null && isVersionWithinMaxAge) {
1846          try {
1847            res = await appVersion.handleFetch(event.request, event);
1848          } catch (err) {
1849            if (err.isUnrecoverableState) {
1850              await this.notifyClientsAboutUnrecoverableState(appVersion, err.message);
1851            }
1852            if (err.isCritical) {
1853              this.debugger.log(err, `Driver.handleFetch(version: ${appVersion.manifestHash})`);
1854              await this.versionFailed(appVersion, err);
1855              return this.safeFetch(event.request);
1856            }
1857            throw err;
1858          }
1859        }
1860        if (res === null) {
1861          return this.safeFetch(event.request);
1862        }
1863        return res;
1864      } finally {
1865        event.waitUntil(this.idle.trigger());
1866      }
1867    }
1868    /**
1869     * Attempt to quickly reach a state where it's safe to serve responses.
1870     */
1871    async initialize() {
1872      const table = await this.controlTable;
1873      let manifests, assignments, latest;
1874      try {
1875        [manifests, assignments, latest] = await Promise.all([
1876          table.read("manifests"),
1877          table.read("assignments"),
1878          table.read("latest")
1879        ]);
1880        if (!this.versions.has(latest.latest) && !manifests.hasOwnProperty(latest.latest)) {
1881          this.debugger.log(`Missing manifest for latest version hash ${latest.latest}`, "initialize: read from DB");
1882          throw new Error(`Missing manifest for latest hash ${latest.latest}`);
1883        }
1884        this.idle.schedule("init post-load (update)", async () => {
1885          await this.checkForUpdate();
1886        });
1887      } catch (_) {
1888        const manifest = await this.fetchLatestManifest();
1889        const hash = hashManifest(manifest);
1890        manifests = { [hash]: manifest };
1891        assignments = {};
1892        latest = { latest: hash };
1893        await Promise.all([
1894          table.write("manifests", manifests),
1895          table.write("assignments", assignments),
1896          table.write("latest", latest)
1897        ]);
1898      }
1899      this.idle.schedule("init post-load (cleanup)", async () => {
1900        await this.cleanupCaches();
1901      });
1902      Object.keys(manifests).forEach((hash) => {
1903        const manifest = manifests[hash];
1904        if (!this.versions.has(hash)) {
1905          this.versions.set(hash, new AppVersion(this.scope, this.adapter, this.db, this.idle, this.debugger, manifest, hash));
1906        }
1907      });
1908      Object.keys(assignments).forEach((clientId) => {
1909        const hash = assignments[clientId];
1910        if (this.versions.has(hash)) {
1911          this.clientVersionMap.set(clientId, hash);
1912        } else {
1913          this.clientVersionMap.set(clientId, latest.latest);
1914          this.debugger.log(`Unknown version ${hash} mapped for client ${clientId}, using latest instead`, `initialize: map assignments`);
1915        }
1916      });
1917      this.latestHash = latest.latest;
1918      if (!this.versions.has(latest.latest)) {
1919        throw new Error(`Invariant violated (initialize): latest hash ${latest.latest} has no known manifest`);
1920      }
1921      await Promise.all(Object.keys(manifests).map(async (hash) => {
1922        try {
1923          await this.scheduleInitialization(this.versions.get(hash));
1924        } catch (err) {
1925          this.debugger.log(err, `initialize: schedule init of ${hash}`);
1926        }
1927      }));
1928    }
1929    lookupVersionByHash(hash, debugName = "lookupVersionByHash") {
1930      if (!this.versions.has(hash)) {
1931        throw new Error(`Invariant violated (${debugName}): want AppVersion for ${hash} but not loaded`);
1932      }
1933      return this.versions.get(hash);
1934    }
1935    /**
1936     * Decide which version of the manifest to use for the event.
1937     */
1938    async assignVersion(event) {
1939      const isWorkerScriptRequest = event.request.destination === "worker" && event.resultingClientId && event.clientId;
1940      const clientId = isWorkerScriptRequest ? event.clientId : event.resultingClientId || event.clientId;
1941      if (clientId) {
1942        if (this.clientVersionMap.has(clientId)) {
1943          const hash = this.clientVersionMap.get(clientId);
1944          let appVersion = this.lookupVersionByHash(hash, "assignVersion");
1945          if (this.state === DriverReadyState.NORMAL && hash !== this.latestHash && appVersion.isNavigationRequest(event.request)) {
1946            if (this.latestHash === null) {
1947              throw new Error(`Invariant violated (assignVersion): latestHash was null`);
1948            }
1949            const client = await this.scope.clients.get(clientId);
1950            if (client) {
1951              await this.updateClient(client);
1952            }
1953            appVersion = this.lookupVersionByHash(this.latestHash, "assignVersion");
1954          }
1955          if (isWorkerScriptRequest) {
1956            if (!this.clientVersionMap.has(event.resultingClientId)) {
1957              this.clientVersionMap.set(event.resultingClientId, hash);
1958              await this.sync();
1959            } else if (this.clientVersionMap.get(event.resultingClientId) !== hash) {
1960              throw new Error(`Version mismatch between worker client ${event.resultingClientId} and requesting client ${clientId}`);
1961            }
1962          }
1963          return appVersion;
1964        } else {
1965          if (this.state !== DriverReadyState.NORMAL) {
1966            return null;
1967          }
1968          if (this.latestHash === null) {
1969            throw new Error(`Invariant violated (assignVersion): latestHash was null`);
1970          }
1971          if (isWorkerScriptRequest) {
1972            if (!this.clientVersionMap.has(event.resultingClientId)) {
1973              this.clientVersionMap.set(event.resultingClientId, this.latestHash);
1974            } else if (this.clientVersionMap.get(event.resultingClientId) !== this.latestHash) {
1975              throw new Error(`Version mismatch between worker client ${event.resultingClientId} and requesting client ${clientId}`);
1976            }
1977          }
1978          this.clientVersionMap.set(clientId, this.latestHash);
1979          await this.sync();
1980          return this.lookupVersionByHash(this.latestHash, "assignVersion");
1981        }
1982      } else {
1983        if (this.state !== DriverReadyState.NORMAL) {
1984          return null;
1985        }
1986        if (this.latestHash === null) {
1987          throw new Error(`Invariant violated (assignVersion): latestHash was null`);
1988        }
1989        return this.lookupVersionByHash(this.latestHash, "assignVersion");
1990      }
1991    }
1992    async fetchLatestManifest(ignoreOfflineError = false) {
1993      const res = await this.safeFetch(this.adapter.newRequest("ngsw.json?ngsw-cache-bust=" + Math.random()));
1994      if (!res.ok) {
1995        if (res.status === 404) {
1996          await this.deleteAllCaches();
1997          await this.scope.registration.unregister();
1998        } else if ((res.status === 503 || res.status === 504) && ignoreOfflineError) {
1999          return null;
2000        }
2001        throw new Error(`Manifest fetch failed! (status: ${res.status})`);
2002      }
2003      this.lastUpdateCheck = this.adapter.time;
2004      return res.json();
2005    }
2006    async deleteAllCaches() {
2007      const cacheNames = await this.adapter.caches.keys();
2008      await Promise.all(cacheNames.map((name) => this.adapter.caches.delete(name)));
2009    }
2010    /**
2011     * Schedule the SW's attempt to reach a fully prefetched state for the given AppVersion
2012     * when the SW is not busy and has connectivity. This returns a Promise which must be
2013     * awaited, as under some conditions the AppVersion might be initialized immediately.
2014     */
2015    async scheduleInitialization(appVersion) {
2016      const initialize = async () => {
2017        try {
2018          await appVersion.initializeFully();
2019        } catch (err) {
2020          this.debugger.log(err, `initializeFully for ${appVersion.manifestHash}`);
2021          await this.versionFailed(appVersion, err);
2022        }
2023      };
2024      if (isLocalhost(this.scope.registration.scope)) {
2025        return initialize();
2026      }
2027      this.idle.schedule(`initialization(${appVersion.manifestHash})`, initialize);
2028    }
2029    async versionFailed(appVersion, err) {
2030      const broken = Array.from(this.versions.entries()).find(([hash, version]
2030) => version === appVersion);
2031      if (broken === void 0) {
2032        return;
2033      }
2034      const brokenHash = broken[0];
2035      if (this.latestHash === brokenHash) {
2036        this.state = DriverReadyState.EXISTING_CLIENTS_ONLY;
2037        this.stateMessage = `Degraded due to: ${errorToString(err)}`;
2038      }
2039    }
2040    async setupUpdate(manifest, hash) {
2041      try {
2042        const newVersion = new AppVersion(this.scope, this.adapter, this.db, this.idle, this.debugger, manifest, hash);
2043        if (manifest.configVersion !== SUPPORTED_CONFIG_VERSION) {
2044          await this.deleteAllCaches();
2045          await this.scope.registration.unregister();
2046          throw new Error(`Invalid config version: expected ${SUPPORTED_CONFIG_VERSION}, got ${manifest.configVersion}.`);
2047        }
2048        await newVersion.initializeFully(this);
2049        this.versions.set(hash, newVersion);
2050        this.latestHash = hash;
2051        if (this.state === DriverReadyState.EXISTING_CLIENTS_ONLY) {
2052          this.state = DriverReadyState.NORMAL;
2053          this.stateMessage = "(nominal)";
2054        }
2055        await this.sync();
2056        await this.notifyClientsAboutVersionReady(manifest, hash);
2057      } catch (e) {
2058        await this.notifyClientsAboutVersionInstallationFailed(manifest, hash, e);
2059        throw e;
2060      }
2061    }
2062    async checkForUpdate() {
2063      let hash = "(unknown)";
2064      try {
2065        const manifest = await this.fetchLatestManifest(true);
2066        if (manifest === null) {
2067          this.debugger.log("Check for update aborted. (Client or server offline.)");
2068          return false;
2069        }
2070        hash = hashManifest(manifest);
2071        if (this.versions.has(hash)) {
2072          await this.notifyClientsAboutNoNewVersionDetected(manifest, hash);
2073          return false;
2074        }
2075        await this.notifyClientsAboutVersionDetected(manifest, hash);
2076        await this.setupUpdate(manifest, hash);
2077        return true;
2078      } catch (err) {
2079        this.debugger.log(err, `Error occurred while updating to manifest ${hash}`);
2080        this.state = DriverReadyState.EXISTING_CLIENTS_ONLY;
2081        this.stateMessage = `Degraded due to failed initialization: ${errorToString(err)}`;
2082        return false;
2083      }
2084    }
2085    /**
2086     * Synchronize the existing state to the underlying database.
2087     */
2088    async sync() {
2089      const table = await this.controlTable;
2090      const manifests = {};
2091      this.versions.forEach((version, hash) => {
2092        manifests[hash] = version.manifest;
2093      });
2094      const assignments = {};
2095      this.clientVersionMap.forEach((hash, clientId) => {
2096        assignments[clientId] = hash;
2097      });
2098      const latest = {
2099        latest: this.latestHash
2100      };
2101      await Promise.all([
2102        table.write("manifests", manifests),
2103        table.write("assignments", assignments),
2104        table.write("latest", latest)
2105      ]);
2106    }
2107    async cleanupCaches() {
2108      try {
2109        const activeClients = new Set((await this.scope.clients.matchAll()).map((client) => client.id));
2110        const knownClients = Array.from(this.clientVersionMap.keys());
2111        const obsoleteClients = knownClients.filter((id) => !activeClients.has(id));
2112        obsoleteClients.forEach((id) => this.clientVersionMap.delete(id));
2113        const usedVersions = new Set(this.clientVersionMap.values());
2114        const obsoleteVersions = Array.from(this.versions.keys()).filter((version) => !usedVersions.has(version) && version !== this.latestHash);
2115        obsoleteVersions.forEach((version) => this.versions.delete(version));
2116        await this.sync();
2117        const allCaches = await this.adapter.caches.keys();
2118        const usedCaches = new Set(await this.getCacheNames());
2119        const cachesToDelete = allCaches.filter((name) => !usedCaches.has(name));
2120        await Promise.all(cachesToDelete.map((name) => this.adapter.caches.delete(name)));
2121      } catch (err) {
2122        this.debugger.log(err, "cleanupCaches");
2123      }
2124    }
2125    /**
2126     * Determine if a specific version of the given resource is cached anywhere within the SW,
2127     * and fetch it if so.
2128     */
2129    lookupResourceWithHash(url, hash) {
2130      return Array.from(this.versions.values()).reduce(async (prev, version) => {
2131        if (await prev !== null) {
2132          return prev;
2133        }
2134        return version.lookupResourceWithHash(url, hash);
2135      }, Promise.resolve(null));
2136    }
2137    async lookupResourceWithoutHash(url) {
2138      await this.initialized;
2139      const version = this.versions.get(this.latestHash);
2140      return version ? version.lookupResourceWithoutHash(url) : null;
2141    }
2142    async previouslyCachedResources() {
2143      await this.initialized;
2144      const version = this.versions.get(this.latestHash);
2145      return version ? version.previouslyCachedResources() : [];
2146    }
2147    async recentCacheStatus(url) {
2148      const version = this.versions.get(this.latestHash);
2149      return version ? version.recentCacheStatus(url) : UpdateCacheStatus.NOT_CACHED;
2150    }
2151    mergeHashWithAppData(manifest, hash) {
2152      return {
2153        hash,
2154        appData: manifest.appData
2155      };
2156    }
2157    async notifyClientsAboutUnrecoverableState(appVersion, reason) {
2158      const broken = Array.from(this.versions.entries()).find(([hash, version]) => version === appVersion);
2159      if (broken === void 0) {
2160        return;
2161      }
2162      const brokenHash = broken[0];
2163      const affectedClients = Array.from(this.clientVersionMap.entries()).filter(([clientId, hash]) => hash === brokenHash).map(([clientId]) => clientId);
2164      await Promise.all(affectedClients.map(async (clientId) => {
2165        const client = await this.scope.clients.get(clientId);
2166        if (client) {
2167          client.postMessage({ type: "UNRECOVERABLE_STATE", reason });
2168        }
2169      }));
2170    }
2171    async notifyClientsAboutVersionInstallationFailed(manifest, hash, error) {
2172      await this.initialized;
2173      const clients = await this.scope.clients.matchAll();
2174      await Promise.all(clients.map(async (client) => {
2175        client.postMessage({
2176          type: "VERSION_INSTALLATION_FAILED",
2177          version: this.mergeHashWithAppData(manifest, hash),
2178          error: errorToString(error)
2179        });
2180      }));
2181    }
2182    async notifyClientsAboutNoNewVersionDetected(manifest, hash) {
2183      await this.initialized;
2184      const clients = await this.scope.clients.matchAll();
2185      await Promise.all(clients.map(async (client) => {
2186        client.postMessage({
2187          type: "NO_NEW_VERSION_DETECTED",
2188          version: this.mergeHashWithAppData(manifest, hash)
2189        });
2190      }));
2191    }
2192    async notifyClientsAboutVersionDetected(manifest, hash) {
2193      await this.initialized;
2194      const clients = await this.scope.clients.matchAll();
2195      await Promise.all(clients.map(async (client) => {
2196        const version = this.clientVersionMap.get(client.id);
2197        if (version === void 0) {
2198          return;
2199        }
2200        client.postMessage({
2201          type: "VERSION_DETECTED",
2202          version: this.mergeHashWithAppData(manifest, hash)
2203        });
2204      }));
2205    }
2206    async notifyClientsAboutVersionReady(manifest, hash) {
2207      await this.initialized;
2208      const clients = await this.scope.clients.matchAll();
2209      await Promise.all(clients.map(async (client) => {
2210        const version = this.clientVersionMap.get(client.id);
2211        if (version === void 0) {
2212          return;
2213        }
2214        if (version === this.latestHash) {
2215          return;
2216        }
2217        const current = this.versions.get(version);
2218        const notice = {
2219          type: "VERSION_READY",
2220          currentVersion: this.mergeHashWithAppData(current.manifest, version),
2221          latestVersion: this.mergeHashWithAppData(manifest, hash)
2222        };
2223        client.postMessage(notice);
2224      }));
2225    }
2226    async broadcast(msg) {
2227      const clients = await this.scope.clients.matchAll();
2228      clients.forEach((client) => {
2229        client.postMessage(msg);
2230      });
2231    }
2232    async debugState() {
2233      return {
2234        state: DriverReadyState[this.state],
2235        why: this.stateMessage,
2236        latestHash: this.latestHash,
2237        lastUpdateCheck: this.lastUpdateCheck
2238      };
2239    }
2240    async debugVersions() {
2241      return Array.from(this.versions.keys()).map((hash) => {
2242        const version = this.versions.get(hash);
2243        const clients = Array.from(this.clientVersionMap.entries()).filter(([clientId, version2]) => version2 === hash).map(([clientId, version2]) => clientId);
2244        return {
2245          hash,
2246          manifest: version.manifest,
2247          clients,
2248          status: ""
2249        };
2250      });
2251    }
2252    async debugIdleState() {
2253      return {
2254        queue: this.idle.taskDescriptions,
2255        lastTrigger: this.idle.lastTrigger,
2256        lastRun: this.idle.lastRun
2257      };
2258    }
2259    async safeFetch(req) {
2260      try {
2261        return await this.scope.fetch(req);
2262      } catch (err) {
2263        this.debugger.log(err, `Driver.fetch(${req.url})`);
2264        return this.adapter.newResponse(null, {
2265          status: 504,
2266          statusText: "Gateway Timeout"
2267        });
2268      }
2269    }
2270    async getCacheNames() {
2271      const controlTable = await this.controlTable;
2272      const appVersions = Array.from(this.versions.values());
2273      const appVersionCacheNames = await Promise.all(appVersions.map((version) => version.getCacheNames()));
2274      return [controlTable.cacheName].concat(...appVersionCacheNames);
2275    }
2276  };
2277
2278  
2278// packages/service-worker/worker/main.ts
2279  var scope = self;
2280  var adapter = new Adapter(scope.registration.scope, self.caches);
2281  new Driver(scope, adapter, new CacheDatabase(adapter));
2282})();
2283/**
2284 * @license
2285 * Copyright Google LLC All Rights Reserved.
2286 *
2287 * Use of this source code is governed by an MIT-style license that can be
2288 * found in the LICENSE file at https://angular.dev/license
2289 */

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.