@angular/service-worker 20.2.0-next.0 → 20.2.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/config/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v20.2.0-next.0
2
+ * @license Angular v20.2.0-next.1
3
3
  * (c) 2010-2025 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v20.2.0-next.0
2
+ * @license Angular v20.2.0-next.1
3
3
  * (c) 2010-2025 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v20.2.0-next.0
2
+ * @license Angular v20.2.0-next.1
3
3
  * (c) 2010-2025 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -344,10 +344,10 @@ class SwPush {
344
344
  decodeBase64(input) {
345
345
  return atob(input);
346
346
  }
347
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.0", ngImport: i0, type: SwPush, deps: [{ token: NgswCommChannel }], target: i0.ɵɵFactoryTarget.Injectable });
348
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.2.0-next.0", ngImport: i0, type: SwPush });
347
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.1", ngImport: i0, type: SwPush, deps: [{ token: NgswCommChannel }], target: i0.ɵɵFactoryTarget.Injectable });
348
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.2.0-next.1", ngImport: i0, type: SwPush });
349
349
  }
350
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.0", ngImport: i0, type: SwPush, decorators: [{
350
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.1", ngImport: i0, type: SwPush, decorators: [{
351
351
  type: Injectable
352
352
  }], ctorParameters: () => [{ type: NgswCommChannel }] });
353
353
 
@@ -455,10 +455,10 @@ class SwUpdate {
455
455
  const nonce = this.sw.generateNonce();
456
456
  return this.sw.postMessageWithOperation('ACTIVATE_UPDATE', { nonce }, nonce);
457
457
  }
458
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.0", ngImport: i0, type: SwUpdate, deps: [{ token: NgswCommChannel }], target: i0.ɵɵFactoryTarget.Injectable });
459
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.2.0-next.0", ngImport: i0, type: SwUpdate });
458
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.1", ngImport: i0, type: SwUpdate, deps: [{ token: NgswCommChannel }], target: i0.ɵɵFactoryTarget.Injectable });
459
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.2.0-next.1", ngImport: i0, type: SwUpdate });
460
460
  }
461
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.0", ngImport: i0, type: SwUpdate, decorators: [{
461
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.1", ngImport: i0, type: SwUpdate, decorators: [{
462
462
  type: Injectable
463
463
  }], ctorParameters: () => [{ type: NgswCommChannel }] });
464
464
 
@@ -649,11 +649,11 @@ class ServiceWorkerModule {
649
649
  providers: [provideServiceWorker(script, options)],
650
650
  };
651
651
  }
652
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.0", ngImport: i0, type: ServiceWorkerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
653
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.2.0-next.0", ngImport: i0, type: ServiceWorkerModule });
654
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.2.0-next.0", ngImport: i0, type: ServiceWorkerModule, providers: [SwPush, SwUpdate] });
652
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0-next.1", ngImport: i0, type: ServiceWorkerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
653
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.2.0-next.1", ngImport: i0, type: ServiceWorkerModule });
654
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.2.0-next.1", ngImport: i0, type: ServiceWorkerModule, providers: [SwPush, SwUpdate] });
655
655
  }
656
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.0", ngImport: i0, type: ServiceWorkerModule, decorators: [{
656
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0-next.1", ngImport: i0, type: ServiceWorkerModule, decorators: [{
657
657
  type: NgModule,
658
658
  args: [{ providers: [SwPush, SwUpdate] }]
659
659
  }] });
package/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v20.2.0-next.0
2
+ * @license Angular v20.2.0-next.1
3
3
  * (c) 2010-2025 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
package/ngsw-config.js CHANGED
@@ -4,7 +4,7 @@
4
4
  const require = __cjsCompatRequire(import.meta.url);
5
5
 
6
6
 
7
- // bazel-out/k8-fastbuild/bin/packages/service-worker/config/src/duration.js
7
+ // packages/service-worker/config/src/duration.js
8
8
  var PARSE_TO_PAIRS = /([0-9]+[^0-9]+)/g;
9
9
  var PAIR_SPLIT = /^([0-9]+)([dhmsu]+)$/;
10
10
  function parseDurationToMs(duration) {
@@ -42,7 +42,7 @@ function parseDurationToMs(duration) {
42
42
  }).reduce((total, value) => total + value, 0);
43
43
  }
44
44
 
45
- // bazel-out/k8-fastbuild/bin/packages/service-worker/config/src/glob.js
45
+ // packages/service-worker/config/src/glob.js
46
46
  var QUESTION_MARK = "[^/]";
47
47
  var WILD_SINGLE = "[^/]*";
48
48
  var WILD_OPEN = "(?:.+\\/)?";
@@ -76,12 +76,16 @@ function globToRegex(glob, literalQuestionMark = false) {
76
76
  return regex;
77
77
  }
78
78
 
79
- // bazel-out/k8-fastbuild/bin/packages/service-worker/config/src/generator.js
79
+ // packages/service-worker/config/src/generator.js
80
80
  var DEFAULT_NAVIGATION_URLS = [
81
81
  "/**",
82
+ // Include all URLs.
82
83
  "!/**/*.*",
84
+ // Exclude URLs to files (containing a file extension in the last segment).
83
85
  "!/**/*__*",
86
+ // Exclude URLs containing `__` in the last segment.
84
87
  "!/**/*__*/**"
88
+ // Exclude URLs containing `__` in any other segment.
85
89
  ];
86
90
  var Generator = class {
87
91
  fs;
@@ -215,15 +219,15 @@ function buildCacheQueryOptions(inOptions) {
215
219
  };
216
220
  }
217
221
 
218
- // bazel-out/k8-fastbuild/bin/packages/service-worker/cli/main.js
222
+ // packages/service-worker/cli/main.ts
219
223
  import * as fs2 from "fs";
220
224
  import * as path2 from "path";
221
225
 
222
- // bazel-out/k8-fastbuild/bin/packages/service-worker/cli/filesystem.js
226
+ // packages/service-worker/cli/filesystem.js
223
227
  import * as fs from "fs";
224
228
  import * as path from "path";
225
229
 
226
- // bazel-out/k8-fastbuild/bin/packages/service-worker/cli/sha1.js
230
+ // packages/service-worker/cli/sha1.js
227
231
  function sha1Binary(buffer) {
228
232
  const words32 = arrayBufferToWords32(buffer, Endian.Big);
229
233
  return _sha1(words32, buffer.byteLength * 8);
@@ -325,7 +329,7 @@ function byteStringToHexString(str) {
325
329
  return hex.toLowerCase();
326
330
  }
327
331
 
328
- // bazel-out/k8-fastbuild/bin/packages/service-worker/cli/filesystem.js
332
+ // packages/service-worker/cli/filesystem.js
329
333
  var NodeFilesystem = class {
330
334
  base;
331
335
  constructor(base) {
@@ -355,7 +359,7 @@ var NodeFilesystem = class {
355
359
  }
356
360
  };
357
361
 
358
- // bazel-out/k8-fastbuild/bin/packages/service-worker/cli/main.js
362
+ // packages/service-worker/cli/main.ts
359
363
  var cwd = process.cwd();
360
364
  var distDir = path2.join(cwd, process.argv[2]);
361
365
  var config = path2.join(cwd, process.argv[3]);
package/ngsw-worker.js CHANGED
@@ -18,12 +18,9 @@
18
18
  return a;
19
19
  };
20
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
- };
21
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
25
22
 
26
- // bazel-out/k8-fastbuild/bin/packages/service-worker/worker/src/named-cache-storage.js
23
+ // packages/service-worker/worker/src/named-cache-storage.js
27
24
  var NamedCacheStorage = class {
28
25
  constructor(original, cacheNamePrefix) {
29
26
  __publicField(this, "original");
@@ -52,7 +49,7 @@
52
49
  }
53
50
  };
54
51
 
55
- // bazel-out/k8-fastbuild/bin/packages/service-worker/worker/src/adapter.js
52
+ // packages/service-worker/worker/src/adapter.js
56
53
  var Adapter = class {
57
54
  constructor(scopeUrl, caches) {
58
55
  __publicField(this, "scopeUrl");
@@ -63,29 +60,62 @@
63
60
  this.origin = parsedScopeUrl.origin;
64
61
  this.caches = new NamedCacheStorage(caches, `ngsw:${parsedScopeUrl.path}`);
65
62
  }
63
+ /**
64
+ * Wrapper around the `Request` constructor.
65
+ */
66
66
  newRequest(input, init) {
67
67
  return new Request(input, init);
68
68
  }
69
+ /**
70
+ * Wrapper around the `Response` constructor.
71
+ */
69
72
  newResponse(body, init) {
70
73
  return new Response(body, init);
71
74
  }
75
+ /**
76
+ * Wrapper around the `Headers` constructor.
77
+ */
72
78
  newHeaders(headers) {
73
79
  return new Headers(headers);
74
80
  }
81
+ /**
82
+ * Test if a given object is an instance of `Client`.
83
+ */
75
84
  isClient(source) {
76
85
  return source instanceof Client;
77
86
  }
87
+ /**
88
+ * Read the current UNIX time in milliseconds.
89
+ */
78
90
  get time() {
79
91
  return Date.now();
80
92
  }
93
+ /**
94
+ * Get a normalized representation of a URL such as those found in the ServiceWorker's `ngsw.json`
95
+ * configuration.
96
+ *
97
+ * More specifically:
98
+ * 1. Resolve the URL relative to the ServiceWorker's scope.
99
+ * 2. If the URL is relative to the ServiceWorker's own origin, then only return the path part.
100
+ * Otherwise, return the full URL.
101
+ *
102
+ * @param url The raw request URL.
103
+ * @return A normalized representation of the URL.
104
+ */
81
105
  normalizeUrl(url) {
82
106
  const parsed = this.parseUrl(url, this.scopeUrl);
83
107
  return parsed.origin === this.origin ? parsed.path : url;
84
108
  }
109
+ /**
110
+ * Parse a URL into its different parts, such as `origin`, `path` and `search`.
111
+ */
85
112
  parseUrl(url, relativeTo) {
86
113
  const parsed = !relativeTo ? new URL(url) : new URL(url, relativeTo);
87
114
  return { origin: parsed.origin, path: parsed.pathname, search: parsed.search };
88
115
  }
116
+ /**
117
+ * Wait for a given amount of time before completing a Promise.
118
+ */
89
119
  timeout(ms) {
90
120
  return new Promise((resolve) => {
91
121
  setTimeout(() => resolve(), ms);
@@ -93,7 +123,7 @@
93
123
  }
94
124
  };
95
125
 
96
- // bazel-out/k8-fastbuild/bin/packages/service-worker/worker/src/database.js
126
+ // packages/service-worker/worker/src/database.js
97
127
  var NotFound = class {
98
128
  constructor(table, key) {
99
129
  __publicField(this, "table");
@@ -103,7 +133,7 @@
103
133
  }
104
134
  };
105
135
 
106
- // bazel-out/k8-fastbuild/bin/packages/service-worker/worker/src/db-cache.js
136
+ // packages/service-worker/worker/src/db-cache.js
107
137
  var CacheDatabase = class {
108
138
  constructor(adapter2) {
109
139
  __publicField(this, "adapter");
@@ -167,7 +197,7 @@
167
197
  }
168
198
  };
169
199
 
170
- // bazel-out/k8-fastbuild/bin/packages/service-worker/worker/src/api.js
200
+ // packages/service-worker/worker/src/api.js
171
201
  var UpdateCacheStatus;
172
202
  (function(UpdateCacheStatus2) {
173
203
  UpdateCacheStatus2[UpdateCacheStatus2["NOT_CACHED"] = 0] = "NOT_CACHED";
@@ -175,7 +205,7 @@
175
205
  UpdateCacheStatus2[UpdateCacheStatus2["CACHED"] = 2] = "CACHED";
176
206
  })(UpdateCacheStatus || (UpdateCacheStatus = {}));
177
207
 
178
- // bazel-out/k8-fastbuild/bin/packages/service-worker/worker/src/error.js
208
+ // packages/service-worker/worker/src/error.js
179
209
  var SwCriticalError = class extends Error {
180
210
  constructor() {
181
211
  super(...arguments);
@@ -197,7 +227,7 @@ ${error.stack}`;
197
227
  }
198
228
  };
199
229
 
200
- // bazel-out/k8-fastbuild/bin/packages/service-worker/worker/src/sha1.js
230
+ // packages/service-worker/worker/src/sha1.js
201
231
  function sha1(str) {
202
232
  const utf8 = str;
203
233
  const words32 = stringToWords32(utf8, Endian.Big);
@@ -312,7 +342,7 @@ ${error.stack}`;
312
342
  return hex.toLowerCase();
313
343
  }
314
344
 
315
- // bazel-out/k8-fastbuild/bin/packages/service-worker/worker/src/assets.js
345
+ // packages/service-worker/worker/src/assets.js
316
346
  var AssetGroup = class {
317
347
  constructor(scope2, adapter2, idle, config, hashes, db, cacheNamePrefix) {
318
348
  __publicField(this, "scope");
@@ -321,11 +351,31 @@ ${error.stack}`;
321
351
  __publicField(this, "config");
322
352
  __publicField(this, "hashes");
323
353
  __publicField(this, "db");
354
+ /**
355
+ * A deduplication cache, to make sure the SW never makes two network requests
356
+ * for the same resource at once. Managed by `fetchAndCacheOnce`.
357
+ */
324
358
  __publicField(this, "inFlightRequests", /* @__PURE__ */ new Map());
359
+ /**
360
+ * Normalized resource URLs.
361
+ */
325
362
  __publicField(this, "urls", []);
363
+ /**
364
+ * Regular expression patterns.
365
+ */
326
366
  __publicField(this, "patterns", []);
367
+ /**
368
+ * A Promise which resolves to the `Cache` used to back this asset group. This
369
+ * is opened from the constructor.
370
+ */
327
371
  __publicField(this, "cache");
372
+ /**
373
+ * Group name from the configuration.
374
+ */
328
375
  __publicField(this, "name");
376
+ /**
377
+ * Metadata associated with specific cache entries.
378
+ */
329
379
  __publicField(this, "metadata");
330
380
  this.scope = scope2;
331
381
  this.adapter = adapter2;
@@ -356,10 +406,16 @@ ${error.stack}`;
356
406
  }
357
407
  return UpdateCacheStatus.CACHED;
358
408
  }
409
+ /**
410
+ * Return a list of the names of all caches used by this group.
411
+ */
359
412
  async getCacheNames() {
360
413
  const [cache, metadata] = await Promise.all([this.cache, this.metadata]);
361
414
  return [cache.name, metadata.cacheName];
362
415
  }
416
+ /**
417
+ * Process a request for a given resource and return it, or return null if it's not available.
418
+ */
363
419
  async handleFetch(req, _event) {
364
420
  const url = this.adapter.normalizeUrl(req.url);
365
421
  if (this.urls.indexOf(url) !== -1 || this.patterns.some((pattern) => pattern.test(url))) {
@@ -388,6 +444,11 @@ ${error.stack}`;
388
444
  return null;
389
445
  }
390
446
  }
447
+ /**
448
+ * Some resources are cached without a hash, meaning that their expiration is controlled
449
+ * by HTTP caching headers. Check whether the given request/response pair is still valid
450
+ * per the caching headers.
451
+ */
391
452
  async needToRevalidate(req, res) {
392
453
  if (res.headers.has("Cache-Control")) {
393
454
  const cacheControl = res.headers.get("Cache-Control");
@@ -427,6 +488,9 @@ ${error.stack}`;
427
488
  return true;
428
489
  }
429
490
  }
491
+ /**
492
+ * Fetch the complete state of a cached resource, or return null if it's not found.
493
+ */
430
494
  async fetchFromCacheOnly(url) {
431
495
  const cache = await this.cache;
432
496
  const metaTable = await this.metadata;
@@ -442,10 +506,16 @@ ${error.stack}`;
442
506
  }
443
507
  return { response, metadata };
444
508
  }
509
+ /**
510
+ * Lookup all resources currently stored in the cache which have no associated hash.
511
+ */
445
512
  async unhashedResources() {
446
513
  const cache = await this.cache;
447
514
  return (await cache.keys()).map((request) => this.adapter.normalizeUrl(request.url)).filter((url) => !this.hashes.has(url));
448
515
  }
516
+ /**
517
+ * Fetch the given resource from the network, and cache it if able.
518
+ */
449
519
  async fetchAndCacheOnce(req, used = true) {
450
520
  if (this.inFlightRequests.has(req.url)) {
451
521
  return this.inFlightRequests.get(req.url);
@@ -483,6 +553,9 @@ ${error.stack}`;
483
553
  }
484
554
  return res;
485
555
  }
556
+ /**
557
+ * Load a particular asset from the network, accounting for hash validation.
558
+ */
486
559
  async cacheBustedFetchFromNetwork(req) {
487
560
  const url = this.adapter.normalizeUrl(req.url);
488
561
  if (this.hashes.has(url)) {
@@ -511,6 +584,9 @@ ${error.stack}`;
511
584
  return this.safeFetch(req);
512
585
  }
513
586
  }
587
+ /**
588
+ * Possibly update a resource, if it's expired and needs to be updated. A no-op otherwise.
589
+ */
514
590
  async maybeUpdate(updateFrom, req, cache) {
515
591
  const url = this.adapter.normalizeUrl(req.url);
516
592
  if (this.hashes.has(url)) {
@@ -523,9 +599,26 @@ ${error.stack}`;
523
599
  }
524
600
  return false;
525
601
  }
602
+ /**
603
+ * Create a new `Request` based on the specified URL and `RequestInit` options, preserving only
604
+ * metadata that are known to be safe.
605
+ *
606
+ * Currently, only headers are preserved.
607
+ *
608
+ * NOTE:
609
+ * Things like credential inclusion are intentionally omitted to avoid issues with opaque
610
+ * responses.
611
+ *
612
+ * TODO(gkalpak):
613
+ * Investigate preserving more metadata. See, also, discussion on preserving `mode`:
614
+ * https://github.com/angular/angular/issues/41931#issuecomment-1227601347
615
+ */
526
616
  newRequestWithMetadata(url, options) {
527
617
  return this.adapter.newRequest(url, { headers: options.headers });
528
618
  }
619
+ /**
620
+ * Construct a cache-busting URL for a given URL.
621
+ */
529
622
  cacheBust(url) {
530
623
  return url + (url.indexOf("?") === -1 ? "?" : "&") + "ngsw-cache-bust=" + Math.random();
531
624
  }
@@ -609,7 +702,7 @@ ${error.stack}`;
609
702
  }
610
703
  };
611
704
 
612
- // bazel-out/k8-fastbuild/bin/packages/service-worker/worker/src/data.js
705
+ // packages/service-worker/worker/src/data.js
613
706
  var LruList = class {
614
707
  constructor(state) {
615
708
  __publicField(this, "state");
@@ -623,9 +716,15 @@ ${error.stack}`;
623
716
  }
624
717
  this.state = state;
625
718
  }
719
+ /**
720
+ * The current count of URLs in the list.
721
+ */
626
722
  get size() {
627
723
  return this.state.count;
628
724
  }
725
+ /**
726
+ * Remove the tail.
727
+ */
629
728
  pop() {
630
729
  if (this.state.tail === null) {
631
730
  return null;
@@ -695,10 +794,26 @@ ${error.stack}`;
695
794
  __publicField(this, "config");
696
795
  __publicField(this, "db");
697
796
  __publicField(this, "debugHandler");
797
+ /**
798
+ * Compiled regular expression set used to determine which resources fall under the purview
799
+ * of this group.
800
+ */
698
801
  __publicField(this, "patterns");
802
+ /**
803
+ * The `Cache` instance in which resources belonging to this group are cached.
804
+ */
699
805
  __publicField(this, "cache");
806
+ /**
807
+ * Tracks the LRU state of resources in this cache.
808
+ */
700
809
  __publicField(this, "_lru", null);
810
+ /**
811
+ * Database table used to store the state of the LRU cache.
812
+ */
701
813
  __publicField(this, "lruTable");
814
+ /**
815
+ * Database table used to store metadata for resources in the cache.
816
+ */
702
817
  __publicField(this, "ageTable");
703
818
  this.scope = scope2;
704
819
  this.adapter = adapter2;
@@ -710,6 +825,9 @@ ${error.stack}`;
710
825
  this.lruTable = this.db.open(`${cacheNamePrefix}:${config.name}:lru`, config.cacheQueryOptions);
711
826
  this.ageTable = this.db.open(`${cacheNamePrefix}:${config.name}:age`, config.cacheQueryOptions);
712
827
  }
828
+ /**
829
+ * Lazily initialize/load the LRU chain.
830
+ */
713
831
  async lru() {
714
832
  if (this._lru === null) {
715
833
  const table = await this.lruTable;
@@ -721,6 +839,9 @@ ${error.stack}`;
721
839
  }
722
840
  return this._lru;
723
841
  }
842
+ /**
843
+ * Sync the LRU chain to non-volatile storage.
844
+ */
724
845
  async syncLru() {
725
846
  if (this._lru === null) {
726
847
  return;
@@ -732,6 +853,10 @@ ${error.stack}`;
732
853
  this.debugHandler.log(err, `DataGroup(${this.config.name}@${this.config.version}).syncLru()`);
733
854
  }
734
855
  }
856
+ /**
857
+ * Process a fetch event and return a `Response` if the resource is covered by this group,
858
+ * or `null` otherwise.
859
+ */
735
860
  async handleFetch(req, event) {
736
861
  if (!this.patterns.some((pattern) => pattern.test(req.url))) {
737
862
  return null;
@@ -862,6 +987,13 @@ ${error.stack}`;
862
987
  }
863
988
  return null;
864
989
  }
990
+ /**
991
+ * Operation for caching the response from the server. This has to happen all
992
+ * at once, so that the cache and LRU tracking remain in sync. If the network request
993
+ * completes before the timeout, this logic will be run inline with the response flow.
994
+ * If the request times out on the server, an error will be returned but the real network
995
+ * request will still be running in the background, to be cached when it completes.
996
+ */
865
997
  async cacheResponse(req, res, lru, okToCacheOpaque = false) {
866
998
  if (!(res.ok || okToCacheOpaque && res.type === "opaque")) {
867
999
  return;
@@ -878,6 +1010,9 @@ ${error.stack}`;
878
1010
  await ageTable.write(req.url, { age: this.adapter.time });
879
1011
  await this.syncLru();
880
1012
  }
1013
+ /**
1014
+ * Delete all of the saved state which this group uses to track resources.
1015
+ */
881
1016
  async cleanup() {
882
1017
  await Promise.all([
883
1018
  this.cache.then((cache) => this.adapter.caches.delete(cache.name)),
@@ -885,6 +1020,9 @@ ${error.stack}`;
885
1020
  this.lruTable.then((table) => this.db.delete(table.name))
886
1021
  ]);
887
1022
  }
1023
+ /**
1024
+ * Return a list of the names of all caches used by this group.
1025
+ */
888
1026
  async getCacheNames() {
889
1027
  const [cache, ageTable, lruTable] = await Promise.all([
890
1028
  this.cache,
@@ -893,6 +1031,13 @@ ${error.stack}`;
893
1031
  ]);
894
1032
  return [cache.name, ageTable.cacheName, lruTable.cacheName];
895
1033
  }
1034
+ /**
1035
+ * Clear the state of the cache for a particular resource.
1036
+ *
1037
+ * This doesn't remove the resource from the LRU table, that is assumed to have
1038
+ * been done already. This clears the GET and HEAD versions of the request from
1039
+ * the cache itself, as well as the metadata stored in the age table.
1040
+ */
896
1041
  async clearCacheForUrl(url) {
897
1042
  const [cache, ageTable] = await Promise.all([this.cache, this.ageTable]);
898
1043
  await Promise.all([
@@ -913,7 +1058,7 @@ ${error.stack}`;
913
1058
  }
914
1059
  };
915
1060
 
916
- // bazel-out/k8-fastbuild/bin/packages/service-worker/worker/src/app-version.js
1061
+ // packages/service-worker/worker/src/app-version.js
917
1062
  var AppVersion = class {
918
1063
  constructor(scope2, adapter2, database, idle, debugHandler, manifest, manifestHash) {
919
1064
  __publicField(this, "scope");
@@ -922,11 +1067,31 @@ ${error.stack}`;
922
1067
  __publicField(this, "debugHandler");
923
1068
  __publicField(this, "manifest");
924
1069
  __publicField(this, "manifestHash");
1070
+ /**
1071
+ * A Map of absolute URL paths (`/foo.txt`) to the known hash of their contents (if available).
1072
+ */
925
1073
  __publicField(this, "hashTable", /* @__PURE__ */ new Map());
1074
+ /**
1075
+ * All of the asset groups active in this version of the app.
1076
+ */
926
1077
  __publicField(this, "assetGroups");
1078
+ /**
1079
+ * All of the data groups active in this version of the app.
1080
+ */
927
1081
  __publicField(this, "dataGroups");
1082
+ /**
1083
+ * Requests to URLs that match any of the `include` RegExps and none of the `exclude` RegExps
1084
+ * are considered navigation requests and handled accordingly.
1085
+ */
928
1086
  __publicField(this, "navigationUrls");
1087
+ /**
1088
+ * The normalized URL to the file that serves as the index page to satisfy navigation requests.
1089
+ * Usually this is `/index.html`.
1090
+ */
929
1091
  __publicField(this, "indexUrl");
1092
+ /**
1093
+ * Tracks whether the manifest has encountered any inconsistencies.
1094
+ */
930
1095
  __publicField(this, "_okay", true);
931
1096
  this.scope = scope2;
932
1097
  this.adapter = adapter2;
@@ -958,6 +1123,11 @@ ${error.stack}`;
958
1123
  get okay() {
959
1124
  return this._okay;
960
1125
  }
1126
+ /**
1127
+ * Fully initialize this version of the application. If this Promise resolves successfully, all
1128
+ * required
1129
+ * data has been safely downloaded.
1130
+ */
961
1131
  async initializeFully(updateFrom) {
962
1132
  try {
963
1133
  await this.assetGroups.reduce(async (previous, group) => {
@@ -1001,6 +1171,10 @@ ${error.stack}`;
1001
1171
  }
1002
1172
  return null;
1003
1173
  }
1174
+ /**
1175
+ * Determine whether the request is a navigation request.
1176
+ * Takes into account: Request method and mode, `Accept` header, `navigationUrls` patterns.
1177
+ */
1004
1178
  isNavigationRequest(req) {
1005
1179
  if (req.method !== "GET" || req.mode !== "navigate") {
1006
1180
  return false;
@@ -1013,6 +1187,9 @@ ${error.stack}`;
1013
1187
  const urlWithoutQueryOrHash = url.replace(/[?#].*$/, "");
1014
1188
  return this.navigationUrls.include.some((regex) => regex.test(urlWithoutQueryOrHash)) && !this.navigationUrls.exclude.some((regex) => regex.test(urlWithoutQueryOrHash));
1015
1189
  }
1190
+ /**
1191
+ * Check this version for a given resource with a particular hash.
1192
+ */
1016
1193
  async lookupResourceWithHash(url, hash) {
1017
1194
  if (!this.hashTable.has(url)) {
1018
1195
  return null;
@@ -1023,6 +1200,9 @@ ${error.stack}`;
1023
1200
  const cacheState = await this.lookupResourceWithoutHash(url);
1024
1201
  return cacheState && cacheState.response;
1025
1202
  }
1203
+ /**
1204
+ * Check this version for a given resource regardless of its hash.
1205
+ */
1026
1206
  lookupResourceWithoutHash(url) {
1027
1207
  return this.assetGroups.reduce(async (potentialResponse, group) => {
1028
1208
  const resp = await potentialResponse;
@@ -1032,6 +1212,9 @@ ${error.stack}`;
1032
1212
  return group.fetchFromCacheOnly(url);
1033
1213
  }, Promise.resolve(null));
1034
1214
  }
1215
+ /**
1216
+ * List all unhashed resources from all asset groups.
1217
+ */
1035
1218
  previouslyCachedResources() {
1036
1219
  return this.assetGroups.reduce(async (resources, group) => (await resources).concat(await group.unhashedResources()), Promise.resolve([]));
1037
1220
  }
@@ -1048,6 +1231,9 @@ ${error.stack}`;
1048
1231
  return groupStatus;
1049
1232
  }, Promise.resolve(UpdateCacheStatus.NOT_CACHED));
1050
1233
  }
1234
+ /**
1235
+ * Return a list of the names of all caches used by this version.
1236
+ */
1051
1237
  async getCacheNames() {
1052
1238
  const allGroupCacheNames = await Promise.all([
1053
1239
  ...this.assetGroups.map((group) => group.getCacheNames()),
@@ -1055,9 +1241,15 @@ ${error.stack}`;
1055
1241
  ]);
1056
1242
  return [].concat(...allGroupCacheNames);
1057
1243
  }
1244
+ /**
1245
+ * Get the opaque application data which was provided with the manifest.
1246
+ */
1058
1247
  get appData() {
1059
1248
  return this.manifest.appData || null;
1060
1249
  }
1250
+ /**
1251
+ * Check whether a request accepts `text/html` (based on the `Accept` header).
1252
+ */
1061
1253
  acceptsTextHtml(req) {
1062
1254
  const accept = req.headers.get("Accept");
1063
1255
  if (accept === null) {
@@ -1068,13 +1260,18 @@ ${error.stack}`;
1068
1260
  }
1069
1261
  };
1070
1262
 
1071
- // bazel-out/k8-fastbuild/bin/packages/service-worker/worker/src/debug.js
1072
- var SW_VERSION = "20.2.0-next.0";
1263
+ // packages/service-worker/worker/src/debug.js
1264
+ var SW_VERSION = "20.2.0-next.1";
1073
1265
  var DEBUG_LOG_BUFFER_SIZE = 100;
1074
1266
  var DebugHandler = class {
1075
1267
  constructor(driver, adapter2) {
1076
1268
  __publicField(this, "driver");
1077
1269
  __publicField(this, "adapter");
1270
+ // There are two debug log message arrays. debugLogA records new debugging messages.
1271
+ // Once it reaches DEBUG_LOG_BUFFER_SIZE, the array is moved to debugLogB and a new
1272
+ // array is assigned to debugLogA. This ensures that insertion to the debug log is
1273
+ // always O(1) no matter the number of logged messages, and that the total number
1274
+ // of messages in the log never exceeds 2 * DEBUG_LOG_BUFFER_SIZE.
1078
1275
  __publicField(this, "debugLogA", []);
1079
1276
  __publicField(this, "debugLogB", []);
1080
1277
  this.driver = driver;
@@ -1144,7 +1341,7 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
1144
1341
  }
1145
1342
  };
1146
1343
 
1147
- // bazel-out/k8-fastbuild/bin/packages/service-worker/worker/src/idle.js
1344
+ // packages/service-worker/worker/src/idle.js
1148
1345
  var IdleScheduler = class {
1149
1346
  constructor(adapter2, delay, maxDelay, debug) {
1150
1347
  __publicField(this, "adapter");
@@ -1226,12 +1423,12 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
1226
1423
  }
1227
1424
  };
1228
1425
 
1229
- // bazel-out/k8-fastbuild/bin/packages/service-worker/worker/src/manifest.js
1426
+ // packages/service-worker/worker/src/manifest.js
1230
1427
  function hashManifest(manifest) {
1231
1428
  return sha1(JSON.stringify(manifest));
1232
1429
  }
1233
1430
 
1234
- // bazel-out/k8-fastbuild/bin/packages/service-worker/worker/src/msg.js
1431
+ // packages/service-worker/worker/src/msg.js
1235
1432
  function isMsgCheckForUpdates(msg) {
1236
1433
  return msg.action === "CHECK_FOR_UPDATES";
1237
1434
  }
@@ -1239,7 +1436,7 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
1239
1436
  return msg.action === "ACTIVATE_UPDATE";
1240
1437
  }
1241
1438
 
1242
- // bazel-out/k8-fastbuild/bin/packages/service-worker/worker/src/driver.js
1439
+ // packages/service-worker/worker/src/driver.js
1243
1440
  var IDLE_DELAY = 5e3;
1244
1441
  var MAX_IDLE_DELAY = 3e4;
1245
1442
  var SUPPORTED_CONFIG_VERSION = 1;
@@ -1271,18 +1468,52 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
1271
1468
  __publicField(this, "scope");
1272
1469
  __publicField(this, "adapter");
1273
1470
  __publicField(this, "db");
1471
+ /**
1472
+ * Tracks the current readiness condition under which the SW is operating. This controls
1473
+ * whether the SW attempts to respond to some or all requests.
1474
+ */
1274
1475
  __publicField(this, "state", DriverReadyState.NORMAL);
1275
1476
  __publicField(this, "stateMessage", "(nominal)");
1477
+ /**
1478
+ * Tracks whether the SW is in an initialized state or not. Before initialization,
1479
+ * it's not legal to respond to requests.
1480
+ */
1276
1481
  __publicField(this, "initialized", null);
1482
+ /**
1483
+ * Maps client IDs to the manifest hash of the application version being used to serve
1484
+ * them. If a client ID is not present here, it has not yet been assigned a version.
1485
+ *
1486
+ * If a ManifestHash appears here, it is also present in the `versions` map below.
1487
+ */
1277
1488
  __publicField(this, "clientVersionMap", /* @__PURE__ */ new Map());
1489
+ /**
1490
+ * Maps manifest hashes to instances of `AppVersion` for those manifests.
1491
+ */
1278
1492
  __publicField(this, "versions", /* @__PURE__ */ new Map());
1493
+ /**
1494
+ * The latest version fetched from the server.
1495
+ *
1496
+ * Valid after initialization has completed.
1497
+ */
1279
1498
  __publicField(this, "latestHash", null);
1280
1499
  __publicField(this, "lastUpdateCheck", null);
1500
+ /**
1501
+ * Whether there is a check for updates currently scheduled due to navigation.
1502
+ */
1281
1503
  __publicField(this, "scheduledNavUpdateCheck", false);
1504
+ /**
1505
+ * Keep track of whether we have logged an invalid `only-if-cached` request.
1506
+ * (See `.onFetch()` for details.)
1507
+ */
1282
1508
  __publicField(this, "loggedInvalidOnlyIfCachedRequest", false);
1283
1509
  __publicField(this, "ngswStatePath");
1510
+ /**
1511
+ * A scheduler which manages a queue of tasks that need to be executed when the SW is
1512
+ * not doing any other work (not processing any other requests).
1513
+ */
1284
1514
  __publicField(this, "idle");
1285
1515
  __publicField(this, "debugger");
1516
+ // A promise resolving to the control DB table.
1286
1517
  __publicField(this, "controlTable");
1287
1518
  this.scope = scope2;
1288
1519
  this.adapter = adapter2;
@@ -1305,10 +1536,20 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
1305
1536
  this.scope.addEventListener("push", (event) => this.onPush(event));
1306
1537
  this.scope.addEventListener("notificationclick", (event) => this.onClick(event));
1307
1538
  this.scope.addEventListener("notificationclose", (event) => this.onClose(event));
1308
- this.scope.addEventListener("pushsubscriptionchange", (event) => this.onPushSubscriptionChange(event));
1539
+ this.scope.addEventListener("pushsubscriptionchange", (event) => (
1540
+ // This is a bug in TypeScript, where they removed `PushSubscriptionChangeEvent`
1541
+ // based on the incorrect assumption that browsers don't support it.
1542
+ this.onPushSubscriptionChange(event)
1543
+ ));
1309
1544
  this.debugger = new DebugHandler(this, this.adapter);
1310
1545
  this.idle = new IdleScheduler(this.adapter, IDLE_DELAY, MAX_IDLE_DELAY, this.debugger);
1311
1546
  }
1547
+ /**
1548
+ * The handler for fetch events.
1549
+ *
1550
+ * This is the transition point between the synchronous event handler and the
1551
+ * asynchronous execution that eventually resolves for respondWith() and waitUntil().
1552
+ */
1312
1553
  onFetch(event) {
1313
1554
  const req = event.request;
1314
1555
  const scopeUrl = this.scope.registration.scope;
@@ -1337,6 +1578,9 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
1337
1578
  }
1338
1579
  event.respondWith(this.handleFetch(event));
1339
1580
  }
1581
+ /**
1582
+ * The handler for message events.
1583
+ */
1340
1584
  onMessage(event) {
1341
1585
  if (this.state === DriverReadyState.SAFE_MODE) {
1342
1586
  return;
@@ -1451,6 +1695,17 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
1451
1695
  data: { action, notification: options }
1452
1696
  });
1453
1697
  }
1698
+ /**
1699
+ * Handles the closing of a notification by extracting its options and
1700
+ * broadcasting a `NOTIFICATION_CLOSE` message.
1701
+ *
1702
+ * This is typically called when a notification is dismissed by the user
1703
+ * or closed programmatically, and it relays that information to clients
1704
+ * listening for service worker events.
1705
+ *
1706
+ * @param notification - The original `Notification` object that was closed.
1707
+ * @param action - The action string associated with the close event, if any (usually an empty string).
1708
+ */
1454
1709
  async handleClose(notification, action) {
1455
1710
  const options = {};
1456
1711
  NOTIFICATION_OPTION_NAMES.filter((name) => name in notification).forEach((name) => options[name] = notification[name]);
@@ -1459,6 +1714,17 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
1459
1714
  data: { action, notification: options }
1460
1715
  });
1461
1716
  }
1717
+ /**
1718
+ * Handles changes to the push subscription by capturing the old and new
1719
+ * subscription details and broadcasting a `PUSH_SUBSCRIPTION_CHANGE` message.
1720
+ *
1721
+ * This method is triggered when the browser invalidates an existing push
1722
+ * subscription and creates a new one, which can happen without user interaction.
1723
+ * It ensures that clients listening for service worker events are informed
1724
+ * of the subscription update.
1725
+ *
1726
+ * @param event - The `PushSubscriptionChangeEvent` containing the old and new subscriptions.
1727
+ */
1462
1728
  async handlePushSubscriptionChange(event) {
1463
1729
  const { oldSubscription, newSubscription } = event;
1464
1730
  await this.broadcast({
@@ -1537,6 +1803,9 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
1537
1803
  event.waitUntil(this.idle.trigger());
1538
1804
  }
1539
1805
  }
1806
+ /**
1807
+ * Attempt to quickly reach a state where it's safe to serve responses.
1808
+ */
1540
1809
  async initialize() {
1541
1810
  const table = await this.controlTable;
1542
1811
  let manifests, assignments, latest;
@@ -1601,6 +1870,9 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
1601
1870
  }
1602
1871
  return this.versions.get(hash);
1603
1872
  }
1873
+ /**
1874
+ * Decide which version of the manifest to use for the event.
1875
+ */
1604
1876
  async assignVersion(event) {
1605
1877
  const isWorkerScriptRequest = event.request.destination === "worker" && event.resultingClientId && event.clientId;
1606
1878
  const clientId = isWorkerScriptRequest ? event.clientId : event.resultingClientId || event.clientId;
@@ -1673,6 +1945,11 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
1673
1945
  const cacheNames = await this.adapter.caches.keys();
1674
1946
  await Promise.all(cacheNames.map((name) => this.adapter.caches.delete(name)));
1675
1947
  }
1948
+ /**
1949
+ * Schedule the SW's attempt to reach a fully prefetched state for the given AppVersion
1950
+ * when the SW is not busy and has connectivity. This returns a Promise which must be
1951
+ * awaited, as under some conditions the AppVersion might be initialized immediately.
1952
+ */
1676
1953
  async scheduleInitialization(appVersion) {
1677
1954
  const initialize = async () => {
1678
1955
  try {
@@ -1743,6 +2020,9 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
1743
2020
  return false;
1744
2021
  }
1745
2022
  }
2023
+ /**
2024
+ * Synchronize the existing state to the underlying database.
2025
+ */
1746
2026
  async sync() {
1747
2027
  const table = await this.controlTable;
1748
2028
  const manifests = {};
@@ -1780,6 +2060,10 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
1780
2060
  this.debugger.log(err, "cleanupCaches");
1781
2061
  }
1782
2062
  }
2063
+ /**
2064
+ * Determine if a specific version of the given resource is cached anywhere within the SW,
2065
+ * and fetch it if so.
2066
+ */
1783
2067
  lookupResourceWithHash(url, hash) {
1784
2068
  return Array.from(this.versions.values()).reduce(async (prev, version) => {
1785
2069
  if (await prev !== null) {
@@ -1929,7 +2213,7 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
1929
2213
  }
1930
2214
  };
1931
2215
 
1932
- // bazel-out/k8-fastbuild/bin/packages/service-worker/worker/main.js
2216
+ // packages/service-worker/worker/main.ts
1933
2217
  var scope = self;
1934
2218
  var adapter = new Adapter(scope.registration.scope, self.caches);
1935
2219
  new Driver(scope, adapter, new CacheDatabase(adapter));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular/service-worker",
3
- "version": "20.2.0-next.0",
3
+ "version": "20.2.0-next.1",
4
4
  "description": "Angular - service worker tooling!",
5
5
  "author": "angular",
6
6
  "license": "MIT",
@@ -33,7 +33,7 @@
33
33
  "tslib": "^2.3.0"
34
34
  },
35
35
  "peerDependencies": {
36
- "@angular/core": "20.2.0-next.0",
36
+ "@angular/core": "20.2.0-next.1",
37
37
  "rxjs": "^6.5.3 || ^7.4.0"
38
38
  },
39
39
  "repository": {