dealposbarcode 25.50.0 → 26.1.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/assets/scss/style.scss +28 -3
- package/chunk-3KPLVT7B.js +2 -0
- package/chunk-5KWDVSO6.js +194 -0
- package/chunk-6RPDTK47.js +1 -0
- package/chunk-7PT4SS5X.js +1127 -0
- package/chunk-7RSU6VFI.js +1 -0
- package/chunk-EIGRX3SO.js +1 -0
- package/chunk-IKSROKD5.css +1 -0
- package/chunk-JCQ56J6G.js +4 -0
- package/chunk-JMQFG4UA.js +1 -0
- package/{chunk-UBR4JEV7.js → chunk-KKCOUAI7.js} +1 -1
- package/chunk-PE35XIHQ.js +27 -0
- package/chunk-PN5S3LIV.js +1 -0
- package/chunk-Z3B3WOTF.js +18 -0
- package/chunk-Z7JGEKOM.js +1 -0
- package/chunk-ZQPG32YM.js +1848 -0
- package/index.html +3 -3
- package/main-4BFS7RVV.css +1 -0
- package/main-7SA3MAWH.js +248 -0
- package/ngsw-worker.js +469 -70
- package/ngsw.json +40 -52
- package/package.json +1 -1
- package/polyfills-DHHU6LMO.js +2 -0
- package/styles-XWKQSHJN.css +1 -0
- package/chunk-377TROCD.js +0 -1
- package/chunk-4CITKGGL.js +0 -1
- package/chunk-7V3KH6IR.js +0 -394
- package/chunk-CARY4E7O.js +0 -1
- package/chunk-D67JO2HG.css +0 -1
- package/chunk-G2JXUY7S.js +0 -2
- package/chunk-G4LJCV6B.js +0 -1
- package/chunk-HHB3BUIC.js +0 -1
- package/chunk-I535BP2A.js +0 -1
- package/chunk-JYD2NJXU.js +0 -1
- package/chunk-L2JD4R6O.js +0 -1
- package/chunk-LTVGOJEF.js +0 -2
- package/chunk-RH3ZV23S.js +0 -4
- package/chunk-SCXFN4EA.js +0 -1
- package/chunk-UE2JJIFL.js +0 -7
- package/chunk-WBD3XQRN.js +0 -1
- package/chunk-X4PZGB4F.js +0 -2
- package/main-J35CSAIS.css +0 -1
- package/main-SNJDWW52.js +0 -605
- package/media/data-table-2IZ2Q4SK.woff +0 -0
- package/media/data-table-AKMZFM4M.svg +0 -26
- package/media/data-table-DGQ4LQQR.eot +0 -0
- package/media/data-table-J6MZE774.ttf +0 -0
- package/polyfills-Q6W4YVDR.js +0 -2
- package/styles-7YJ7GGGE.css +0 -1
package/ngsw-worker.js
CHANGED
|
@@ -18,10 +18,16 @@
|
|
|
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
25
|
|
|
22
|
-
//
|
|
26
|
+
// packages/service-worker/worker/src/named-cache-storage.js
|
|
23
27
|
var NamedCacheStorage = class {
|
|
24
28
|
constructor(original, cacheNamePrefix) {
|
|
29
|
+
__publicField(this, "original");
|
|
30
|
+
__publicField(this, "cacheNamePrefix");
|
|
25
31
|
this.original = original;
|
|
26
32
|
this.cacheNamePrefix = cacheNamePrefix;
|
|
27
33
|
}
|
|
@@ -46,37 +52,73 @@
|
|
|
46
52
|
}
|
|
47
53
|
};
|
|
48
54
|
|
|
49
|
-
//
|
|
55
|
+
// packages/service-worker/worker/src/adapter.js
|
|
50
56
|
var Adapter = class {
|
|
51
57
|
constructor(scopeUrl, caches) {
|
|
58
|
+
__publicField(this, "scopeUrl");
|
|
59
|
+
__publicField(this, "caches");
|
|
60
|
+
__publicField(this, "origin");
|
|
52
61
|
this.scopeUrl = scopeUrl;
|
|
53
62
|
const parsedScopeUrl = this.parseUrl(this.scopeUrl);
|
|
54
63
|
this.origin = parsedScopeUrl.origin;
|
|
55
64
|
this.caches = new NamedCacheStorage(caches, `ngsw:${parsedScopeUrl.path}`);
|
|
56
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Wrapper around the `Request` constructor.
|
|
68
|
+
*/
|
|
57
69
|
newRequest(input, init) {
|
|
58
70
|
return new Request(input, init);
|
|
59
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Wrapper around the `Response` constructor.
|
|
74
|
+
*/
|
|
60
75
|
newResponse(body, init) {
|
|
61
76
|
return new Response(body, init);
|
|
62
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Wrapper around the `Headers` constructor.
|
|
80
|
+
*/
|
|
63
81
|
newHeaders(headers) {
|
|
64
82
|
return new Headers(headers);
|
|
65
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Test if a given object is an instance of `Client`.
|
|
86
|
+
*/
|
|
66
87
|
isClient(source) {
|
|
67
88
|
return source instanceof Client;
|
|
68
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Read the current UNIX time in milliseconds.
|
|
92
|
+
*/
|
|
69
93
|
get time() {
|
|
70
94
|
return Date.now();
|
|
71
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
|
+
*/
|
|
72
108
|
normalizeUrl(url) {
|
|
73
109
|
const parsed = this.parseUrl(url, this.scopeUrl);
|
|
74
110
|
return parsed.origin === this.origin ? parsed.path : url;
|
|
75
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Parse a URL into its different parts, such as `origin`, `path` and `search`.
|
|
114
|
+
*/
|
|
76
115
|
parseUrl(url, relativeTo) {
|
|
77
116
|
const parsed = !relativeTo ? new URL(url) : new URL(url, relativeTo);
|
|
78
117
|
return { origin: parsed.origin, path: parsed.pathname, search: parsed.search };
|
|
79
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Wait for a given amount of time before completing a Promise.
|
|
121
|
+
*/
|
|
80
122
|
timeout(ms) {
|
|
81
123
|
return new Promise((resolve) => {
|
|
82
124
|
setTimeout(() => resolve(), ms);
|
|
@@ -84,20 +126,23 @@
|
|
|
84
126
|
}
|
|
85
127
|
};
|
|
86
128
|
|
|
87
|
-
//
|
|
129
|
+
// packages/service-worker/worker/src/database.js
|
|
88
130
|
var NotFound = class {
|
|
89
131
|
constructor(table, key) {
|
|
132
|
+
__publicField(this, "table");
|
|
133
|
+
__publicField(this, "key");
|
|
90
134
|
this.table = table;
|
|
91
135
|
this.key = key;
|
|
92
136
|
}
|
|
93
137
|
};
|
|
94
138
|
|
|
95
|
-
//
|
|
139
|
+
// packages/service-worker/worker/src/db-cache.js
|
|
96
140
|
var CacheDatabase = class {
|
|
97
141
|
constructor(adapter2) {
|
|
142
|
+
__publicField(this, "adapter");
|
|
143
|
+
__publicField(this, "cacheNamePrefix", "db");
|
|
144
|
+
__publicField(this, "tables", /* @__PURE__ */ new Map());
|
|
98
145
|
this.adapter = adapter2;
|
|
99
|
-
this.cacheNamePrefix = "db";
|
|
100
|
-
this.tables = /* @__PURE__ */ new Map();
|
|
101
146
|
}
|
|
102
147
|
"delete"(name) {
|
|
103
148
|
if (this.tables.has(name)) {
|
|
@@ -122,6 +167,11 @@
|
|
|
122
167
|
};
|
|
123
168
|
var CacheTable = class {
|
|
124
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");
|
|
125
175
|
this.name = name;
|
|
126
176
|
this.cache = cache;
|
|
127
177
|
this.adapter = adapter2;
|
|
@@ -150,7 +200,7 @@
|
|
|
150
200
|
}
|
|
151
201
|
};
|
|
152
202
|
|
|
153
|
-
//
|
|
203
|
+
// packages/service-worker/worker/src/api.js
|
|
154
204
|
var UpdateCacheStatus;
|
|
155
205
|
(function(UpdateCacheStatus2) {
|
|
156
206
|
UpdateCacheStatus2[UpdateCacheStatus2["NOT_CACHED"] = 0] = "NOT_CACHED";
|
|
@@ -158,11 +208,11 @@
|
|
|
158
208
|
UpdateCacheStatus2[UpdateCacheStatus2["CACHED"] = 2] = "CACHED";
|
|
159
209
|
})(UpdateCacheStatus || (UpdateCacheStatus = {}));
|
|
160
210
|
|
|
161
|
-
//
|
|
211
|
+
// packages/service-worker/worker/src/error.js
|
|
162
212
|
var SwCriticalError = class extends Error {
|
|
163
213
|
constructor() {
|
|
164
214
|
super(...arguments);
|
|
165
|
-
this
|
|
215
|
+
__publicField(this, "isCritical", true);
|
|
166
216
|
}
|
|
167
217
|
};
|
|
168
218
|
function errorToString(error) {
|
|
@@ -176,11 +226,11 @@ ${error.stack}`;
|
|
|
176
226
|
var SwUnrecoverableStateError = class extends SwCriticalError {
|
|
177
227
|
constructor() {
|
|
178
228
|
super(...arguments);
|
|
179
|
-
this
|
|
229
|
+
__publicField(this, "isUnrecoverableState", true);
|
|
180
230
|
}
|
|
181
231
|
};
|
|
182
232
|
|
|
183
|
-
//
|
|
233
|
+
// packages/service-worker/worker/src/sha1.js
|
|
184
234
|
function sha1(str) {
|
|
185
235
|
const utf8 = str;
|
|
186
236
|
const words32 = stringToWords32(utf8, Endian.Big);
|
|
@@ -295,18 +345,47 @@ ${error.stack}`;
|
|
|
295
345
|
return hex.toLowerCase();
|
|
296
346
|
}
|
|
297
347
|
|
|
298
|
-
//
|
|
348
|
+
// packages/service-worker/worker/src/assets.js
|
|
299
349
|
var AssetGroup = class {
|
|
300
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");
|
|
301
383
|
this.scope = scope2;
|
|
302
384
|
this.adapter = adapter2;
|
|
303
385
|
this.idle = idle;
|
|
304
386
|
this.config = config;
|
|
305
387
|
this.hashes = hashes;
|
|
306
388
|
this.db = db;
|
|
307
|
-
this.inFlightRequests = /* @__PURE__ */ new Map();
|
|
308
|
-
this.urls = [];
|
|
309
|
-
this.patterns = [];
|
|
310
389
|
this.name = config.name;
|
|
311
390
|
this.urls = config.urls.map((url) => adapter2.normalizeUrl(url));
|
|
312
391
|
this.patterns = config.patterns.map((pattern) => new RegExp(pattern));
|
|
@@ -330,10 +409,16 @@ ${error.stack}`;
|
|
|
330
409
|
}
|
|
331
410
|
return UpdateCacheStatus.CACHED;
|
|
332
411
|
}
|
|
412
|
+
/**
|
|
413
|
+
* Return a list of the names of all caches used by this group.
|
|
414
|
+
*/
|
|
333
415
|
async getCacheNames() {
|
|
334
416
|
const [cache, metadata] = await Promise.all([this.cache, this.metadata]);
|
|
335
417
|
return [cache.name, metadata.cacheName];
|
|
336
418
|
}
|
|
419
|
+
/**
|
|
420
|
+
* Process a request for a given resource and return it, or return null if it's not available.
|
|
421
|
+
*/
|
|
337
422
|
async handleFetch(req, _event) {
|
|
338
423
|
const url = this.adapter.normalizeUrl(req.url);
|
|
339
424
|
if (this.urls.indexOf(url) !== -1 || this.patterns.some((pattern) => pattern.test(url))) {
|
|
@@ -362,6 +447,11 @@ ${error.stack}`;
|
|
|
362
447
|
return null;
|
|
363
448
|
}
|
|
364
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
|
+
*/
|
|
365
455
|
async needToRevalidate(req, res) {
|
|
366
456
|
if (res.headers.has("Cache-Control")) {
|
|
367
457
|
const cacheControl = res.headers.get("Cache-Control");
|
|
@@ -401,6 +491,9 @@ ${error.stack}`;
|
|
|
401
491
|
return true;
|
|
402
492
|
}
|
|
403
493
|
}
|
|
494
|
+
/**
|
|
495
|
+
* Fetch the complete state of a cached resource, or return null if it's not found.
|
|
496
|
+
*/
|
|
404
497
|
async fetchFromCacheOnly(url) {
|
|
405
498
|
const cache = await this.cache;
|
|
406
499
|
const metaTable = await this.metadata;
|
|
@@ -416,10 +509,16 @@ ${error.stack}`;
|
|
|
416
509
|
}
|
|
417
510
|
return { response, metadata };
|
|
418
511
|
}
|
|
512
|
+
/**
|
|
513
|
+
* Lookup all resources currently stored in the cache which have no associated hash.
|
|
514
|
+
*/
|
|
419
515
|
async unhashedResources() {
|
|
420
516
|
const cache = await this.cache;
|
|
421
517
|
return (await cache.keys()).map((request) => this.adapter.normalizeUrl(request.url)).filter((url) => !this.hashes.has(url));
|
|
422
518
|
}
|
|
519
|
+
/**
|
|
520
|
+
* Fetch the given resource from the network, and cache it if able.
|
|
521
|
+
*/
|
|
423
522
|
async fetchAndCacheOnce(req, used = true) {
|
|
424
523
|
if (this.inFlightRequests.has(req.url)) {
|
|
425
524
|
return this.inFlightRequests.get(req.url);
|
|
@@ -457,6 +556,9 @@ ${error.stack}`;
|
|
|
457
556
|
}
|
|
458
557
|
return res;
|
|
459
558
|
}
|
|
559
|
+
/**
|
|
560
|
+
* Load a particular asset from the network, accounting for hash validation.
|
|
561
|
+
*/
|
|
460
562
|
async cacheBustedFetchFromNetwork(req) {
|
|
461
563
|
const url = this.adapter.normalizeUrl(req.url);
|
|
462
564
|
if (this.hashes.has(url)) {
|
|
@@ -485,6 +587,9 @@ ${error.stack}`;
|
|
|
485
587
|
return this.safeFetch(req);
|
|
486
588
|
}
|
|
487
589
|
}
|
|
590
|
+
/**
|
|
591
|
+
* Possibly update a resource, if it's expired and needs to be updated. A no-op otherwise.
|
|
592
|
+
*/
|
|
488
593
|
async maybeUpdate(updateFrom, req, cache) {
|
|
489
594
|
const url = this.adapter.normalizeUrl(req.url);
|
|
490
595
|
if (this.hashes.has(url)) {
|
|
@@ -497,9 +602,26 @@ ${error.stack}`;
|
|
|
497
602
|
}
|
|
498
603
|
return false;
|
|
499
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, only headers are preserved.
|
|
610
|
+
*
|
|
611
|
+
* NOTE:
|
|
612
|
+
* Things like credential inclusion are intentionally omitted to avoid issues with opaque
|
|
613
|
+
* responses.
|
|
614
|
+
*
|
|
615
|
+
* TODO(gkalpak):
|
|
616
|
+
* Investigate preserving more metadata. See, also, discussion on preserving `mode`:
|
|
617
|
+
* https://github.com/angular/angular/issues/41931#issuecomment-1227601347
|
|
618
|
+
*/
|
|
500
619
|
newRequestWithMetadata(url, options) {
|
|
501
620
|
return this.adapter.newRequest(url, { headers: options.headers });
|
|
502
621
|
}
|
|
622
|
+
/**
|
|
623
|
+
* Construct a cache-busting URL for a given URL.
|
|
624
|
+
*/
|
|
503
625
|
cacheBust(url) {
|
|
504
626
|
return url + (url.indexOf("?") === -1 ? "?" : "&") + "ngsw-cache-bust=" + Math.random();
|
|
505
627
|
}
|
|
@@ -583,9 +705,10 @@ ${error.stack}`;
|
|
|
583
705
|
}
|
|
584
706
|
};
|
|
585
707
|
|
|
586
|
-
//
|
|
708
|
+
// packages/service-worker/worker/src/data.js
|
|
587
709
|
var LruList = class {
|
|
588
710
|
constructor(state) {
|
|
711
|
+
__publicField(this, "state");
|
|
589
712
|
if (state === void 0) {
|
|
590
713
|
state = {
|
|
591
714
|
head: null,
|
|
@@ -596,9 +719,15 @@ ${error.stack}`;
|
|
|
596
719
|
}
|
|
597
720
|
this.state = state;
|
|
598
721
|
}
|
|
722
|
+
/**
|
|
723
|
+
* The current count of URLs in the list.
|
|
724
|
+
*/
|
|
599
725
|
get size() {
|
|
600
726
|
return this.state.count;
|
|
601
727
|
}
|
|
728
|
+
/**
|
|
729
|
+
* Remove the tail.
|
|
730
|
+
*/
|
|
602
731
|
pop() {
|
|
603
732
|
if (this.state.tail === null) {
|
|
604
733
|
return null;
|
|
@@ -663,17 +792,45 @@ ${error.stack}`;
|
|
|
663
792
|
};
|
|
664
793
|
var DataGroup = class {
|
|
665
794
|
constructor(scope2, adapter2, config, db, debugHandler, cacheNamePrefix) {
|
|
795
|
+
__publicField(this, "scope");
|
|
796
|
+
__publicField(this, "adapter");
|
|
797
|
+
__publicField(this, "config");
|
|
798
|
+
__publicField(this, "db");
|
|
799
|
+
__publicField(this, "debugHandler");
|
|
800
|
+
/**
|
|
801
|
+
* Compiled regular expression set used to determine which resources fall under the purview
|
|
802
|
+
* of this group.
|
|
803
|
+
*/
|
|
804
|
+
__publicField(this, "patterns");
|
|
805
|
+
/**
|
|
806
|
+
* The `Cache` instance in which resources belonging to this group are cached.
|
|
807
|
+
*/
|
|
808
|
+
__publicField(this, "cache");
|
|
809
|
+
/**
|
|
810
|
+
* Tracks the LRU state of resources in this cache.
|
|
811
|
+
*/
|
|
812
|
+
__publicField(this, "_lru", null);
|
|
813
|
+
/**
|
|
814
|
+
* Database table used to store the state of the LRU cache.
|
|
815
|
+
*/
|
|
816
|
+
__publicField(this, "lruTable");
|
|
817
|
+
/**
|
|
818
|
+
* Database table used to store metadata for resources in the cache.
|
|
819
|
+
*/
|
|
820
|
+
__publicField(this, "ageTable");
|
|
666
821
|
this.scope = scope2;
|
|
667
822
|
this.adapter = adapter2;
|
|
668
823
|
this.config = config;
|
|
669
824
|
this.db = db;
|
|
670
825
|
this.debugHandler = debugHandler;
|
|
671
|
-
this._lru = null;
|
|
672
826
|
this.patterns = config.patterns.map((pattern) => new RegExp(pattern));
|
|
673
827
|
this.cache = adapter2.caches.open(`${cacheNamePrefix}:${config.name}:cache`);
|
|
674
828
|
this.lruTable = this.db.open(`${cacheNamePrefix}:${config.name}:lru`, config.cacheQueryOptions);
|
|
675
829
|
this.ageTable = this.db.open(`${cacheNamePrefix}:${config.name}:age`, config.cacheQueryOptions);
|
|
676
830
|
}
|
|
831
|
+
/**
|
|
832
|
+
* Lazily initialize/load the LRU chain.
|
|
833
|
+
*/
|
|
677
834
|
async lru() {
|
|
678
835
|
if (this._lru === null) {
|
|
679
836
|
const table = await this.lruTable;
|
|
@@ -685,6 +842,9 @@ ${error.stack}`;
|
|
|
685
842
|
}
|
|
686
843
|
return this._lru;
|
|
687
844
|
}
|
|
845
|
+
/**
|
|
846
|
+
* Sync the LRU chain to non-volatile storage.
|
|
847
|
+
*/
|
|
688
848
|
async syncLru() {
|
|
689
849
|
if (this._lru === null) {
|
|
690
850
|
return;
|
|
@@ -694,8 +854,13 @@ ${error.stack}`;
|
|
|
694
854
|
return table.write("lru", this._lru.state);
|
|
695
855
|
} catch (err) {
|
|
696
856
|
this.debugHandler.log(err, `DataGroup(${this.config.name}@${this.config.version}).syncLru()`);
|
|
857
|
+
await this.detectStorageFull();
|
|
697
858
|
}
|
|
698
859
|
}
|
|
860
|
+
/**
|
|
861
|
+
* Process a fetch event and return a `Response` if the resource is covered by this group,
|
|
862
|
+
* or `null` otherwise.
|
|
863
|
+
*/
|
|
699
864
|
async handleFetch(req, event) {
|
|
700
865
|
if (!this.patterns.some((pattern) => pattern.test(req.url))) {
|
|
701
866
|
return null;
|
|
@@ -803,6 +968,7 @@ ${error.stack}`;
|
|
|
803
968
|
await this.cacheResponse(req, res, lru, okToCacheOpaque);
|
|
804
969
|
} catch (err) {
|
|
805
970
|
this.debugHandler.log(err, `DataGroup(${this.config.name}@${this.config.version}).safeCacheResponse(${req.url}, status: ${res.status})`);
|
|
971
|
+
await this.detectStorageFull();
|
|
806
972
|
}
|
|
807
973
|
} catch (e) {
|
|
808
974
|
}
|
|
@@ -826,6 +992,13 @@ ${error.stack}`;
|
|
|
826
992
|
}
|
|
827
993
|
return null;
|
|
828
994
|
}
|
|
995
|
+
/**
|
|
996
|
+
* Operation for caching the response from the server. This has to happen all
|
|
997
|
+
* at once, so that the cache and LRU tracking remain in sync. If the network request
|
|
998
|
+
* completes before the timeout, this logic will be run inline with the response flow.
|
|
999
|
+
* If the request times out on the server, an error will be returned but the real network
|
|
1000
|
+
* request will still be running in the background, to be cached when it completes.
|
|
1001
|
+
*/
|
|
829
1002
|
async cacheResponse(req, res, lru, okToCacheOpaque = false) {
|
|
830
1003
|
if (!(res.ok || okToCacheOpaque && res.type === "opaque")) {
|
|
831
1004
|
return;
|
|
@@ -842,6 +1015,9 @@ ${error.stack}`;
|
|
|
842
1015
|
await ageTable.write(req.url, { age: this.adapter.time });
|
|
843
1016
|
await this.syncLru();
|
|
844
1017
|
}
|
|
1018
|
+
/**
|
|
1019
|
+
* Delete all of the saved state which this group uses to track resources.
|
|
1020
|
+
*/
|
|
845
1021
|
async cleanup() {
|
|
846
1022
|
await Promise.all([
|
|
847
1023
|
this.cache.then((cache) => this.adapter.caches.delete(cache.name)),
|
|
@@ -849,6 +1025,9 @@ ${error.stack}`;
|
|
|
849
1025
|
this.lruTable.then((table) => this.db.delete(table.name))
|
|
850
1026
|
]);
|
|
851
1027
|
}
|
|
1028
|
+
/**
|
|
1029
|
+
* Return a list of the names of all caches used by this group.
|
|
1030
|
+
*/
|
|
852
1031
|
async getCacheNames() {
|
|
853
1032
|
const [cache, ageTable, lruTable] = await Promise.all([
|
|
854
1033
|
this.cache,
|
|
@@ -857,6 +1036,13 @@ ${error.stack}`;
|
|
|
857
1036
|
]);
|
|
858
1037
|
return [cache.name, ageTable.cacheName, lruTable.cacheName];
|
|
859
1038
|
}
|
|
1039
|
+
/**
|
|
1040
|
+
* Clear the state of the cache for a particular resource.
|
|
1041
|
+
*
|
|
1042
|
+
* This doesn't remove the resource from the LRU table, that is assumed to have
|
|
1043
|
+
* been done already. This clears the GET and HEAD versions of the request from
|
|
1044
|
+
* the cache itself, as well as the metadata stored in the age table.
|
|
1045
|
+
*/
|
|
860
1046
|
async clearCacheForUrl(url) {
|
|
861
1047
|
const [cache, ageTable] = await Promise.all([this.cache, this.ageTable]);
|
|
862
1048
|
await Promise.all([
|
|
@@ -875,27 +1061,68 @@ ${error.stack}`;
|
|
|
875
1061
|
});
|
|
876
1062
|
}
|
|
877
1063
|
}
|
|
1064
|
+
/**
|
|
1065
|
+
* Detect if storage is full or approaching capacity.
|
|
1066
|
+
* Returns true if storage is at or near capacity.
|
|
1067
|
+
*/
|
|
1068
|
+
async detectStorageFull() {
|
|
1069
|
+
try {
|
|
1070
|
+
const estimate = await navigator.storage.estimate();
|
|
1071
|
+
const { quota, usage } = estimate;
|
|
1072
|
+
if (typeof quota !== "number" || typeof usage !== "number") {
|
|
1073
|
+
return;
|
|
1074
|
+
}
|
|
1075
|
+
const usagePercentage = usage / quota * 100;
|
|
1076
|
+
const isStorageFull = usagePercentage >= 95;
|
|
1077
|
+
if (isStorageFull) {
|
|
1078
|
+
this.debugHandler.log("Storage is full or nearly full", `DataGroup(${this.config.name}@${this.config.version}).detectStorageFull()`);
|
|
1079
|
+
}
|
|
1080
|
+
} catch (e) {
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
878
1083
|
};
|
|
879
1084
|
|
|
880
|
-
//
|
|
881
|
-
var BACKWARDS_COMPATIBILITY_NAVIGATION_URLS = [
|
|
882
|
-
{ positive: true, regex: "^/.*$" },
|
|
883
|
-
{ positive: false, regex: "^/.*\\.[^/]*$" },
|
|
884
|
-
{ positive: false, regex: "^/.*__" }
|
|
885
|
-
];
|
|
1085
|
+
// packages/service-worker/worker/src/app-version.js
|
|
886
1086
|
var AppVersion = class {
|
|
887
|
-
get okay() {
|
|
888
|
-
return this._okay;
|
|
889
|
-
}
|
|
890
1087
|
constructor(scope2, adapter2, database, idle, debugHandler, manifest, manifestHash) {
|
|
1088
|
+
__publicField(this, "scope");
|
|
1089
|
+
__publicField(this, "adapter");
|
|
1090
|
+
__publicField(this, "database");
|
|
1091
|
+
__publicField(this, "debugHandler");
|
|
1092
|
+
__publicField(this, "manifest");
|
|
1093
|
+
__publicField(this, "manifestHash");
|
|
1094
|
+
/**
|
|
1095
|
+
* A Map of absolute URL paths (`/foo.txt`) to the known hash of their contents (if available).
|
|
1096
|
+
*/
|
|
1097
|
+
__publicField(this, "hashTable", /* @__PURE__ */ new Map());
|
|
1098
|
+
/**
|
|
1099
|
+
* All of the asset groups active in this version of the app.
|
|
1100
|
+
*/
|
|
1101
|
+
__publicField(this, "assetGroups");
|
|
1102
|
+
/**
|
|
1103
|
+
* All of the data groups active in this version of the app.
|
|
1104
|
+
*/
|
|
1105
|
+
__publicField(this, "dataGroups");
|
|
1106
|
+
/**
|
|
1107
|
+
* Requests to URLs that match any of the `include` RegExps and none of the `exclude` RegExps
|
|
1108
|
+
* are considered navigation requests and handled accordingly.
|
|
1109
|
+
*/
|
|
1110
|
+
__publicField(this, "navigationUrls");
|
|
1111
|
+
/**
|
|
1112
|
+
* The normalized URL to the file that serves as the index page to satisfy navigation requests.
|
|
1113
|
+
* Usually this is `/index.html`.
|
|
1114
|
+
*/
|
|
1115
|
+
__publicField(this, "indexUrl");
|
|
1116
|
+
/**
|
|
1117
|
+
* Tracks whether the manifest has encountered any inconsistencies.
|
|
1118
|
+
*/
|
|
1119
|
+
__publicField(this, "_okay", true);
|
|
891
1120
|
this.scope = scope2;
|
|
892
1121
|
this.adapter = adapter2;
|
|
893
1122
|
this.database = database;
|
|
894
1123
|
this.debugHandler = debugHandler;
|
|
895
1124
|
this.manifest = manifest;
|
|
896
1125
|
this.manifestHash = manifestHash;
|
|
897
|
-
this.hashTable = /* @__PURE__ */ new Map();
|
|
898
|
-
this._okay = true;
|
|
899
1126
|
this.indexUrl = this.adapter.normalizeUrl(this.manifest.index);
|
|
900
1127
|
Object.keys(manifest.hashTable).forEach((url) => {
|
|
901
1128
|
this.hashTable.set(adapter2.normalizeUrl(url), manifest.hashTable[url]);
|
|
@@ -910,7 +1137,6 @@ ${error.stack}`;
|
|
|
910
1137
|
}
|
|
911
1138
|
});
|
|
912
1139
|
this.dataGroups = (manifest.dataGroups || []).map((config) => new DataGroup(scope2, adapter2, config, database, debugHandler, `${config.version}:data`));
|
|
913
|
-
manifest.navigationUrls = manifest.navigationUrls || BACKWARDS_COMPATIBILITY_NAVIGATION_URLS;
|
|
914
1140
|
const includeUrls = manifest.navigationUrls.filter((spec) => spec.positive);
|
|
915
1141
|
const excludeUrls = manifest.navigationUrls.filter((spec) => !spec.positive);
|
|
916
1142
|
this.navigationUrls = {
|
|
@@ -918,6 +1144,14 @@ ${error.stack}`;
|
|
|
918
1144
|
exclude: excludeUrls.map((spec) => new RegExp(spec.regex))
|
|
919
1145
|
};
|
|
920
1146
|
}
|
|
1147
|
+
get okay() {
|
|
1148
|
+
return this._okay;
|
|
1149
|
+
}
|
|
1150
|
+
/**
|
|
1151
|
+
* Fully initialize this version of the application. If this Promise resolves successfully, all
|
|
1152
|
+
* required
|
|
1153
|
+
* data has been safely downloaded.
|
|
1154
|
+
*/
|
|
921
1155
|
async initializeFully(updateFrom) {
|
|
922
1156
|
try {
|
|
923
1157
|
await this.assetGroups.reduce(async (previous, group) => {
|
|
@@ -961,6 +1195,10 @@ ${error.stack}`;
|
|
|
961
1195
|
}
|
|
962
1196
|
return null;
|
|
963
1197
|
}
|
|
1198
|
+
/**
|
|
1199
|
+
* Determine whether the request is a navigation request.
|
|
1200
|
+
* Takes into account: Request method and mode, `Accept` header, `navigationUrls` patterns.
|
|
1201
|
+
*/
|
|
964
1202
|
isNavigationRequest(req) {
|
|
965
1203
|
if (req.method !== "GET" || req.mode !== "navigate") {
|
|
966
1204
|
return false;
|
|
@@ -973,6 +1211,9 @@ ${error.stack}`;
|
|
|
973
1211
|
const urlWithoutQueryOrHash = url.replace(/[?#].*$/, "");
|
|
974
1212
|
return this.navigationUrls.include.some((regex) => regex.test(urlWithoutQueryOrHash)) && !this.navigationUrls.exclude.some((regex) => regex.test(urlWithoutQueryOrHash));
|
|
975
1213
|
}
|
|
1214
|
+
/**
|
|
1215
|
+
* Check this version for a given resource with a particular hash.
|
|
1216
|
+
*/
|
|
976
1217
|
async lookupResourceWithHash(url, hash) {
|
|
977
1218
|
if (!this.hashTable.has(url)) {
|
|
978
1219
|
return null;
|
|
@@ -983,6 +1224,9 @@ ${error.stack}`;
|
|
|
983
1224
|
const cacheState = await this.lookupResourceWithoutHash(url);
|
|
984
1225
|
return cacheState && cacheState.response;
|
|
985
1226
|
}
|
|
1227
|
+
/**
|
|
1228
|
+
* Check this version for a given resource regardless of its hash.
|
|
1229
|
+
*/
|
|
986
1230
|
lookupResourceWithoutHash(url) {
|
|
987
1231
|
return this.assetGroups.reduce(async (potentialResponse, group) => {
|
|
988
1232
|
const resp = await potentialResponse;
|
|
@@ -992,6 +1236,9 @@ ${error.stack}`;
|
|
|
992
1236
|
return group.fetchFromCacheOnly(url);
|
|
993
1237
|
}, Promise.resolve(null));
|
|
994
1238
|
}
|
|
1239
|
+
/**
|
|
1240
|
+
* List all unhashed resources from all asset groups.
|
|
1241
|
+
*/
|
|
995
1242
|
previouslyCachedResources() {
|
|
996
1243
|
return this.assetGroups.reduce(async (resources, group) => (await resources).concat(await group.unhashedResources()), Promise.resolve([]));
|
|
997
1244
|
}
|
|
@@ -1008,6 +1255,9 @@ ${error.stack}`;
|
|
|
1008
1255
|
return groupStatus;
|
|
1009
1256
|
}, Promise.resolve(UpdateCacheStatus.NOT_CACHED));
|
|
1010
1257
|
}
|
|
1258
|
+
/**
|
|
1259
|
+
* Return a list of the names of all caches used by this version.
|
|
1260
|
+
*/
|
|
1011
1261
|
async getCacheNames() {
|
|
1012
1262
|
const allGroupCacheNames = await Promise.all([
|
|
1013
1263
|
...this.assetGroups.map((group) => group.getCacheNames()),
|
|
@@ -1015,9 +1265,15 @@ ${error.stack}`;
|
|
|
1015
1265
|
]);
|
|
1016
1266
|
return [].concat(...allGroupCacheNames);
|
|
1017
1267
|
}
|
|
1268
|
+
/**
|
|
1269
|
+
* Get the opaque application data which was provided with the manifest.
|
|
1270
|
+
*/
|
|
1018
1271
|
get appData() {
|
|
1019
1272
|
return this.manifest.appData || null;
|
|
1020
1273
|
}
|
|
1274
|
+
/**
|
|
1275
|
+
* Check whether a request accepts `text/html` (based on the `Accept` header).
|
|
1276
|
+
*/
|
|
1021
1277
|
acceptsTextHtml(req) {
|
|
1022
1278
|
const accept = req.headers.get("Accept");
|
|
1023
1279
|
if (accept === null) {
|
|
@@ -1028,15 +1284,22 @@ ${error.stack}`;
|
|
|
1028
1284
|
}
|
|
1029
1285
|
};
|
|
1030
1286
|
|
|
1031
|
-
//
|
|
1032
|
-
var SW_VERSION = "
|
|
1287
|
+
// packages/service-worker/worker/src/debug.js
|
|
1288
|
+
var SW_VERSION = "20.3.15";
|
|
1033
1289
|
var DEBUG_LOG_BUFFER_SIZE = 100;
|
|
1034
1290
|
var DebugHandler = class {
|
|
1035
1291
|
constructor(driver, adapter2) {
|
|
1292
|
+
__publicField(this, "driver");
|
|
1293
|
+
__publicField(this, "adapter");
|
|
1294
|
+
// There are two debug log message arrays. debugLogA records new debugging messages.
|
|
1295
|
+
// Once it reaches DEBUG_LOG_BUFFER_SIZE, the array is moved to debugLogB and a new
|
|
1296
|
+
// array is assigned to debugLogA. This ensures that insertion to the debug log is
|
|
1297
|
+
// always O(1) no matter the number of logged messages, and that the total number
|
|
1298
|
+
// of messages in the log never exceeds 2 * DEBUG_LOG_BUFFER_SIZE.
|
|
1299
|
+
__publicField(this, "debugLogA", []);
|
|
1300
|
+
__publicField(this, "debugLogB", []);
|
|
1036
1301
|
this.driver = driver;
|
|
1037
1302
|
this.adapter = adapter2;
|
|
1038
|
-
this.debugLogA = [];
|
|
1039
|
-
this.debugLogB = [];
|
|
1040
1303
|
}
|
|
1041
1304
|
async handleFetch(req) {
|
|
1042
1305
|
const [state, versions, idle] = await Promise.all([
|
|
@@ -1102,20 +1365,24 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
|
|
|
1102
1365
|
}
|
|
1103
1366
|
};
|
|
1104
1367
|
|
|
1105
|
-
//
|
|
1368
|
+
// packages/service-worker/worker/src/idle.js
|
|
1106
1369
|
var IdleScheduler = class {
|
|
1107
1370
|
constructor(adapter2, delay, maxDelay, debug) {
|
|
1371
|
+
__publicField(this, "adapter");
|
|
1372
|
+
__publicField(this, "delay");
|
|
1373
|
+
__publicField(this, "maxDelay");
|
|
1374
|
+
__publicField(this, "debug");
|
|
1375
|
+
__publicField(this, "queue", []);
|
|
1376
|
+
__publicField(this, "scheduled", null);
|
|
1377
|
+
__publicField(this, "empty", Promise.resolve());
|
|
1378
|
+
__publicField(this, "emptyResolve", null);
|
|
1379
|
+
__publicField(this, "lastTrigger", null);
|
|
1380
|
+
__publicField(this, "lastRun", null);
|
|
1381
|
+
__publicField(this, "oldestScheduledAt", null);
|
|
1108
1382
|
this.adapter = adapter2;
|
|
1109
1383
|
this.delay = delay;
|
|
1110
1384
|
this.maxDelay = maxDelay;
|
|
1111
1385
|
this.debug = debug;
|
|
1112
|
-
this.queue = [];
|
|
1113
|
-
this.scheduled = null;
|
|
1114
|
-
this.empty = Promise.resolve();
|
|
1115
|
-
this.emptyResolve = null;
|
|
1116
|
-
this.lastTrigger = null;
|
|
1117
|
-
this.lastRun = null;
|
|
1118
|
-
this.oldestScheduledAt = null;
|
|
1119
1386
|
}
|
|
1120
1387
|
async trigger() {
|
|
1121
1388
|
var _a;
|
|
@@ -1180,12 +1447,12 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
|
|
|
1180
1447
|
}
|
|
1181
1448
|
};
|
|
1182
1449
|
|
|
1183
|
-
//
|
|
1450
|
+
// packages/service-worker/worker/src/manifest.js
|
|
1184
1451
|
function hashManifest(manifest) {
|
|
1185
1452
|
return sha1(JSON.stringify(manifest));
|
|
1186
1453
|
}
|
|
1187
1454
|
|
|
1188
|
-
//
|
|
1455
|
+
// packages/service-worker/worker/src/msg.js
|
|
1189
1456
|
function isMsgCheckForUpdates(msg) {
|
|
1190
1457
|
return msg.action === "CHECK_FOR_UPDATES";
|
|
1191
1458
|
}
|
|
@@ -1193,7 +1460,7 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
|
|
|
1193
1460
|
return msg.action === "ACTIVATE_UPDATE";
|
|
1194
1461
|
}
|
|
1195
1462
|
|
|
1196
|
-
//
|
|
1463
|
+
// packages/service-worker/worker/src/driver.js
|
|
1197
1464
|
var IDLE_DELAY = 5e3;
|
|
1198
1465
|
var MAX_IDLE_DELAY = 3e4;
|
|
1199
1466
|
var SUPPORTED_CONFIG_VERSION = 1;
|
|
@@ -1214,6 +1481,9 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
|
|
|
1214
1481
|
"title",
|
|
1215
1482
|
"vibrate"
|
|
1216
1483
|
];
|
|
1484
|
+
function isLocalhost(scope2) {
|
|
1485
|
+
return /(?:^https?:\/\/)?(?:(?:^|[^\w.])localhost|\[::1\]|127(?:\.\d{1,3}){3})(?::\d+)?(?:\/.*)?$/.test(scope2);
|
|
1486
|
+
}
|
|
1217
1487
|
var DriverReadyState;
|
|
1218
1488
|
(function(DriverReadyState2) {
|
|
1219
1489
|
DriverReadyState2[DriverReadyState2["NORMAL"] = 0] = "NORMAL";
|
|
@@ -1222,18 +1492,59 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
|
|
|
1222
1492
|
})(DriverReadyState || (DriverReadyState = {}));
|
|
1223
1493
|
var Driver = class {
|
|
1224
1494
|
constructor(scope2, adapter2, db) {
|
|
1495
|
+
__publicField(this, "scope");
|
|
1496
|
+
__publicField(this, "adapter");
|
|
1497
|
+
__publicField(this, "db");
|
|
1498
|
+
/**
|
|
1499
|
+
* Tracks the current readiness condition under which the SW is operating. This controls
|
|
1500
|
+
* whether the SW attempts to respond to some or all requests.
|
|
1501
|
+
*/
|
|
1502
|
+
__publicField(this, "state", DriverReadyState.NORMAL);
|
|
1503
|
+
__publicField(this, "stateMessage", "(nominal)");
|
|
1504
|
+
/**
|
|
1505
|
+
* Tracks whether the SW is in an initialized state or not. Before initialization,
|
|
1506
|
+
* it's not legal to respond to requests.
|
|
1507
|
+
*/
|
|
1508
|
+
__publicField(this, "initialized", null);
|
|
1509
|
+
/**
|
|
1510
|
+
* Maps client IDs to the manifest hash of the application version being used to serve
|
|
1511
|
+
* them. If a client ID is not present here, it has not yet been assigned a version.
|
|
1512
|
+
*
|
|
1513
|
+
* If a ManifestHash appears here, it is also present in the `versions` map below.
|
|
1514
|
+
*/
|
|
1515
|
+
__publicField(this, "clientVersionMap", /* @__PURE__ */ new Map());
|
|
1516
|
+
/**
|
|
1517
|
+
* Maps manifest hashes to instances of `AppVersion` for those manifests.
|
|
1518
|
+
*/
|
|
1519
|
+
__publicField(this, "versions", /* @__PURE__ */ new Map());
|
|
1520
|
+
/**
|
|
1521
|
+
* The latest version fetched from the server.
|
|
1522
|
+
*
|
|
1523
|
+
* Valid after initialization has completed.
|
|
1524
|
+
*/
|
|
1525
|
+
__publicField(this, "latestHash", null);
|
|
1526
|
+
__publicField(this, "lastUpdateCheck", null);
|
|
1527
|
+
/**
|
|
1528
|
+
* Whether there is a check for updates currently scheduled due to navigation.
|
|
1529
|
+
*/
|
|
1530
|
+
__publicField(this, "scheduledNavUpdateCheck", false);
|
|
1531
|
+
/**
|
|
1532
|
+
* Keep track of whether we have logged an invalid `only-if-cached` request.
|
|
1533
|
+
* (See `.onFetch()` for details.)
|
|
1534
|
+
*/
|
|
1535
|
+
__publicField(this, "loggedInvalidOnlyIfCachedRequest", false);
|
|
1536
|
+
__publicField(this, "ngswStatePath");
|
|
1537
|
+
/**
|
|
1538
|
+
* A scheduler which manages a queue of tasks that need to be executed when the SW is
|
|
1539
|
+
* not doing any other work (not processing any other requests).
|
|
1540
|
+
*/
|
|
1541
|
+
__publicField(this, "idle");
|
|
1542
|
+
__publicField(this, "debugger");
|
|
1543
|
+
// A promise resolving to the control DB table.
|
|
1544
|
+
__publicField(this, "controlTable");
|
|
1225
1545
|
this.scope = scope2;
|
|
1226
1546
|
this.adapter = adapter2;
|
|
1227
1547
|
this.db = db;
|
|
1228
|
-
this.state = DriverReadyState.NORMAL;
|
|
1229
|
-
this.stateMessage = "(nominal)";
|
|
1230
|
-
this.initialized = null;
|
|
1231
|
-
this.clientVersionMap = /* @__PURE__ */ new Map();
|
|
1232
|
-
this.versions = /* @__PURE__ */ new Map();
|
|
1233
|
-
this.latestHash = null;
|
|
1234
|
-
this.lastUpdateCheck = null;
|
|
1235
|
-
this.scheduledNavUpdateCheck = false;
|
|
1236
|
-
this.loggedInvalidOnlyIfCachedRequest = false;
|
|
1237
1548
|
this.controlTable = this.db.open("control");
|
|
1238
1549
|
this.ngswStatePath = this.adapter.parseUrl("ngsw/state", this.scope.registration.scope).path;
|
|
1239
1550
|
this.scope.addEventListener("install", (event) => {
|
|
@@ -1242,13 +1553,6 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
|
|
|
1242
1553
|
this.scope.addEventListener("activate", (event) => {
|
|
1243
1554
|
event.waitUntil((async () => {
|
|
1244
1555
|
await this.scope.clients.claim();
|
|
1245
|
-
this.idle.schedule("activate: cleanup-old-sw-caches", async () => {
|
|
1246
|
-
try {
|
|
1247
|
-
await this.cleanupOldSwCaches();
|
|
1248
|
-
} catch (err) {
|
|
1249
|
-
this.debugger.log(err, "cleanupOldSwCaches @ activate: cleanup-old-sw-caches");
|
|
1250
|
-
}
|
|
1251
|
-
});
|
|
1252
1556
|
})());
|
|
1253
1557
|
if (this.scope.registration.active !== null) {
|
|
1254
1558
|
this.scope.registration.active.postMessage({ action: "INITIALIZE" });
|
|
@@ -1258,9 +1562,23 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
|
|
|
1258
1562
|
this.scope.addEventListener("message", (event) => this.onMessage(event));
|
|
1259
1563
|
this.scope.addEventListener("push", (event) => this.onPush(event));
|
|
1260
1564
|
this.scope.addEventListener("notificationclick", (event) => this.onClick(event));
|
|
1565
|
+
this.scope.addEventListener("notificationclose", (event) => this.onClose(event));
|
|
1566
|
+
this.scope.addEventListener("pushsubscriptionchange", (event) => (
|
|
1567
|
+
// This is a bug in TypeScript, where they removed `PushSubscriptionChangeEvent`
|
|
1568
|
+
// based on the incorrect assumption that browsers don't support it.
|
|
1569
|
+
this.onPushSubscriptionChange(event)
|
|
1570
|
+
));
|
|
1571
|
+
this.scope.addEventListener("messageerror", (event) => this.onMessageError(event));
|
|
1572
|
+
this.scope.addEventListener("unhandledrejection", (event) => this.onUnhandledRejection(event));
|
|
1261
1573
|
this.debugger = new DebugHandler(this, this.adapter);
|
|
1262
1574
|
this.idle = new IdleScheduler(this.adapter, IDLE_DELAY, MAX_IDLE_DELAY, this.debugger);
|
|
1263
1575
|
}
|
|
1576
|
+
/**
|
|
1577
|
+
* The handler for fetch events.
|
|
1578
|
+
*
|
|
1579
|
+
* This is the transition point between the synchronous event handler and the
|
|
1580
|
+
* asynchronous execution that eventually resolves for respondWith() and waitUntil().
|
|
1581
|
+
*/
|
|
1264
1582
|
onFetch(event) {
|
|
1265
1583
|
const req = event.request;
|
|
1266
1584
|
const scopeUrl = this.scope.registration.scope;
|
|
@@ -1289,6 +1607,9 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
|
|
|
1289
1607
|
}
|
|
1290
1608
|
event.respondWith(this.handleFetch(event));
|
|
1291
1609
|
}
|
|
1610
|
+
/**
|
|
1611
|
+
* The handler for message events.
|
|
1612
|
+
*/
|
|
1292
1613
|
onMessage(event) {
|
|
1293
1614
|
if (this.state === DriverReadyState.SAFE_MODE) {
|
|
1294
1615
|
return;
|
|
@@ -1317,6 +1638,18 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
|
|
|
1317
1638
|
onClick(event) {
|
|
1318
1639
|
event.waitUntil(this.handleClick(event.notification, event.action));
|
|
1319
1640
|
}
|
|
1641
|
+
onClose(event) {
|
|
1642
|
+
event.waitUntil(this.handleClose(event.notification, event.action));
|
|
1643
|
+
}
|
|
1644
|
+
onPushSubscriptionChange(event) {
|
|
1645
|
+
event.waitUntil(this.handlePushSubscriptionChange(event));
|
|
1646
|
+
}
|
|
1647
|
+
onMessageError(event) {
|
|
1648
|
+
this.debugger.log(`Message error occurred - data could not be deserialized`, `Driver.onMessageError(origin: ${event.origin})`);
|
|
1649
|
+
}
|
|
1650
|
+
onUnhandledRejection(event) {
|
|
1651
|
+
this.debugger.log(`Unhandled promise rejection occurred`, `Driver.onUnhandledRejection(reason: ${event.reason})`);
|
|
1652
|
+
}
|
|
1320
1653
|
async ensureInitialized(event) {
|
|
1321
1654
|
if (this.initialized !== null) {
|
|
1322
1655
|
return this.initialized;
|
|
@@ -1397,6 +1730,43 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
|
|
|
1397
1730
|
data: { action, notification: options }
|
|
1398
1731
|
});
|
|
1399
1732
|
}
|
|
1733
|
+
/**
|
|
1734
|
+
* Handles the closing of a notification by extracting its options and
|
|
1735
|
+
* broadcasting a `NOTIFICATION_CLOSE` message.
|
|
1736
|
+
*
|
|
1737
|
+
* This is typically called when a notification is dismissed by the user
|
|
1738
|
+
* or closed programmatically, and it relays that information to clients
|
|
1739
|
+
* listening for service worker events.
|
|
1740
|
+
*
|
|
1741
|
+
* @param notification - The original `Notification` object that was closed.
|
|
1742
|
+
* @param action - The action string associated with the close event, if any (usually an empty string).
|
|
1743
|
+
*/
|
|
1744
|
+
async handleClose(notification, action) {
|
|
1745
|
+
const options = {};
|
|
1746
|
+
NOTIFICATION_OPTION_NAMES.filter((name) => name in notification).forEach((name) => options[name] = notification[name]);
|
|
1747
|
+
await this.broadcast({
|
|
1748
|
+
type: "NOTIFICATION_CLOSE",
|
|
1749
|
+
data: { action, notification: options }
|
|
1750
|
+
});
|
|
1751
|
+
}
|
|
1752
|
+
/**
|
|
1753
|
+
* Handles changes to the push subscription by capturing the old and new
|
|
1754
|
+
* subscription details and broadcasting a `PUSH_SUBSCRIPTION_CHANGE` message.
|
|
1755
|
+
*
|
|
1756
|
+
* This method is triggered when the browser invalidates an existing push
|
|
1757
|
+
* subscription and creates a new one, which can happen without user interaction.
|
|
1758
|
+
* It ensures that clients listening for service worker events are informed
|
|
1759
|
+
* of the subscription update.
|
|
1760
|
+
*
|
|
1761
|
+
* @param event - The `PushSubscriptionChangeEvent` containing the old and new subscriptions.
|
|
1762
|
+
*/
|
|
1763
|
+
async handlePushSubscriptionChange(event) {
|
|
1764
|
+
const { oldSubscription, newSubscription } = event;
|
|
1765
|
+
await this.broadcast({
|
|
1766
|
+
type: "PUSH_SUBSCRIPTION_CHANGE",
|
|
1767
|
+
data: { oldSubscription, newSubscription }
|
|
1768
|
+
});
|
|
1769
|
+
}
|
|
1400
1770
|
async getLastFocusedMatchingClient(scope2) {
|
|
1401
1771
|
const windowClients = await scope2.clients.matchAll({ type: "window" });
|
|
1402
1772
|
return windowClients[0];
|
|
@@ -1442,9 +1812,10 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
|
|
|
1442
1812
|
});
|
|
1443
1813
|
}
|
|
1444
1814
|
const appVersion = await this.assignVersion(event);
|
|
1815
|
+
const isVersionWithinMaxAge = (appVersion == null ? void 0 : appVersion.manifest.applicationMaxAge) === void 0 || this.adapter.time - appVersion.manifest.timestamp < appVersion.manifest.applicationMaxAge;
|
|
1445
1816
|
let res = null;
|
|
1446
1817
|
try {
|
|
1447
|
-
if (appVersion !== null) {
|
|
1818
|
+
if (appVersion !== null && isVersionWithinMaxAge) {
|
|
1448
1819
|
try {
|
|
1449
1820
|
res = await appVersion.handleFetch(event.request, event);
|
|
1450
1821
|
} catch (err) {
|
|
@@ -1467,6 +1838,9 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
|
|
|
1467
1838
|
event.waitUntil(this.idle.trigger());
|
|
1468
1839
|
}
|
|
1469
1840
|
}
|
|
1841
|
+
/**
|
|
1842
|
+
* Attempt to quickly reach a state where it's safe to serve responses.
|
|
1843
|
+
*/
|
|
1470
1844
|
async initialize() {
|
|
1471
1845
|
const table = await this.controlTable;
|
|
1472
1846
|
let manifests, assignments, latest;
|
|
@@ -1531,8 +1905,12 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
|
|
|
1531
1905
|
}
|
|
1532
1906
|
return this.versions.get(hash);
|
|
1533
1907
|
}
|
|
1908
|
+
/**
|
|
1909
|
+
* Decide which version of the manifest to use for the event.
|
|
1910
|
+
*/
|
|
1534
1911
|
async assignVersion(event) {
|
|
1535
|
-
const
|
|
1912
|
+
const isWorkerScriptRequest = event.request.destination === "worker" && event.resultingClientId && event.clientId;
|
|
1913
|
+
const clientId = isWorkerScriptRequest ? event.clientId : event.resultingClientId || event.clientId;
|
|
1536
1914
|
if (clientId) {
|
|
1537
1915
|
if (this.clientVersionMap.has(clientId)) {
|
|
1538
1916
|
const hash = this.clientVersionMap.get(clientId);
|
|
@@ -1547,6 +1925,14 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
|
|
|
1547
1925
|
}
|
|
1548
1926
|
appVersion = this.lookupVersionByHash(this.latestHash, "assignVersion");
|
|
1549
1927
|
}
|
|
1928
|
+
if (isWorkerScriptRequest) {
|
|
1929
|
+
if (!this.clientVersionMap.has(event.resultingClientId)) {
|
|
1930
|
+
this.clientVersionMap.set(event.resultingClientId, hash);
|
|
1931
|
+
await this.sync();
|
|
1932
|
+
} else if (this.clientVersionMap.get(event.resultingClientId) !== hash) {
|
|
1933
|
+
throw new Error(`Version mismatch between worker client ${event.resultingClientId} and requesting client ${clientId}`);
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1550
1936
|
return appVersion;
|
|
1551
1937
|
} else {
|
|
1552
1938
|
if (this.state !== DriverReadyState.NORMAL) {
|
|
@@ -1555,6 +1941,13 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
|
|
|
1555
1941
|
if (this.latestHash === null) {
|
|
1556
1942
|
throw new Error(`Invariant violated (assignVersion): latestHash was null`);
|
|
1557
1943
|
}
|
|
1944
|
+
if (isWorkerScriptRequest) {
|
|
1945
|
+
if (!this.clientVersionMap.has(event.resultingClientId)) {
|
|
1946
|
+
this.clientVersionMap.set(event.resultingClientId, this.latestHash);
|
|
1947
|
+
} else if (this.clientVersionMap.get(event.resultingClientId) !== this.latestHash) {
|
|
1948
|
+
throw new Error(`Version mismatch between worker client ${event.resultingClientId} and requesting client ${clientId}`);
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1558
1951
|
this.clientVersionMap.set(clientId, this.latestHash);
|
|
1559
1952
|
await this.sync();
|
|
1560
1953
|
return this.lookupVersionByHash(this.latestHash, "assignVersion");
|
|
@@ -1587,6 +1980,11 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
|
|
|
1587
1980
|
const cacheNames = await this.adapter.caches.keys();
|
|
1588
1981
|
await Promise.all(cacheNames.map((name) => this.adapter.caches.delete(name)));
|
|
1589
1982
|
}
|
|
1983
|
+
/**
|
|
1984
|
+
* Schedule the SW's attempt to reach a fully prefetched state for the given AppVersion
|
|
1985
|
+
* when the SW is not busy and has connectivity. This returns a Promise which must be
|
|
1986
|
+
* awaited, as under some conditions the AppVersion might be initialized immediately.
|
|
1987
|
+
*/
|
|
1590
1988
|
async scheduleInitialization(appVersion) {
|
|
1591
1989
|
const initialize = async () => {
|
|
1592
1990
|
try {
|
|
@@ -1596,7 +1994,7 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
|
|
|
1596
1994
|
await this.versionFailed(appVersion, err);
|
|
1597
1995
|
}
|
|
1598
1996
|
};
|
|
1599
|
-
if (this.scope.registration.scope
|
|
1997
|
+
if (isLocalhost(this.scope.registration.scope)) {
|
|
1600
1998
|
return initialize();
|
|
1601
1999
|
}
|
|
1602
2000
|
this.idle.schedule(`initialization(${appVersion.manifestHash})`, initialize);
|
|
@@ -1657,6 +2055,9 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
|
|
|
1657
2055
|
return false;
|
|
1658
2056
|
}
|
|
1659
2057
|
}
|
|
2058
|
+
/**
|
|
2059
|
+
* Synchronize the existing state to the underlying database.
|
|
2060
|
+
*/
|
|
1660
2061
|
async sync() {
|
|
1661
2062
|
const table = await this.controlTable;
|
|
1662
2063
|
const manifests = {};
|
|
@@ -1694,12 +2095,10 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
|
|
|
1694
2095
|
this.debugger.log(err, "cleanupCaches");
|
|
1695
2096
|
}
|
|
1696
2097
|
}
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
await Promise.all(oldSwCacheNames.map((name) => caches.delete(name)));
|
|
1702
|
-
}
|
|
2098
|
+
/**
|
|
2099
|
+
* Determine if a specific version of the given resource is cached anywhere within the SW,
|
|
2100
|
+
* and fetch it if so.
|
|
2101
|
+
*/
|
|
1703
2102
|
lookupResourceWithHash(url, hash) {
|
|
1704
2103
|
return Array.from(this.versions.values()).reduce(async (prev, version) => {
|
|
1705
2104
|
if (await prev !== null) {
|
|
@@ -1849,7 +2248,7 @@ ${msgIdle}`, { headers: this.adapter.newHeaders({ "Content-Type": "text/plain" }
|
|
|
1849
2248
|
}
|
|
1850
2249
|
};
|
|
1851
2250
|
|
|
1852
|
-
//
|
|
2251
|
+
// packages/service-worker/worker/main.ts
|
|
1853
2252
|
var scope = self;
|
|
1854
2253
|
var adapter = new Adapter(scope.registration.scope, self.caches);
|
|
1855
2254
|
new Driver(scope, adapter, new CacheDatabase(adapter));
|