textbrowser 0.54.9 → 0.54.11
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/CHANGES.md +8 -0
- package/dist/activateCallback-es.js +23 -0
- package/dist/sw-helper.js +45 -7
- package/package.json +1 -1
- package/resources/activateCallback.js +23 -0
package/CHANGES.md
CHANGED
|
@@ -55,10 +55,12 @@ async function activateCallback ({
|
|
|
55
55
|
// anyways); also important to avoid conflicts with
|
|
56
56
|
// already-running versions upon future sw updates
|
|
57
57
|
log('Activate: Callback called');
|
|
58
|
+
log('Activate: Fetching files manifest', files);
|
|
58
59
|
const r = await fetch(files);
|
|
59
60
|
const {groups} = /** @type {import('./utils/WorkInfo.js').FilesObject} */ (
|
|
60
61
|
await r.json()
|
|
61
62
|
);
|
|
63
|
+
log('Activate: Manifest loaded; groups:', groups.length);
|
|
62
64
|
|
|
63
65
|
/* eslint-disable jsdoc/reject-any-type -- Generic */
|
|
64
66
|
/**
|
|
@@ -67,6 +69,7 @@ async function activateCallback ({
|
|
|
67
69
|
*/
|
|
68
70
|
const addJSONFetch = (arr, path) => {
|
|
69
71
|
/* eslint-enable jsdoc/reject-any-type -- Generic */
|
|
72
|
+
log('Activate: Queueing JSON fetch', basePath + path);
|
|
70
73
|
arr.push(
|
|
71
74
|
(async () => (await fetch(basePath + path)).json())()
|
|
72
75
|
);
|
|
@@ -89,6 +92,13 @@ async function activateCallback ({
|
|
|
89
92
|
const metadataFiles = [];
|
|
90
93
|
groups.forEach(
|
|
91
94
|
({files: fileObjs, metadataBaseDirectory, schemaBaseDirectory}) => {
|
|
95
|
+
log(
|
|
96
|
+
'Activate: Processing group',
|
|
97
|
+
metadataBaseDirectory,
|
|
98
|
+
schemaBaseDirectory,
|
|
99
|
+
'files:',
|
|
100
|
+
fileObjs.length
|
|
101
|
+
);
|
|
92
102
|
fileObjs.forEach(({file: {$ref: filePath}, metadataFile, schemaFile, name}) => {
|
|
93
103
|
// We don't i18nize the name here
|
|
94
104
|
dataFileNames.push(name);
|
|
@@ -98,6 +108,7 @@ async function activateCallback ({
|
|
|
98
108
|
});
|
|
99
109
|
}
|
|
100
110
|
);
|
|
111
|
+
log('Activate: Awaiting queued fetches; works:', dataFiles.length);
|
|
101
112
|
const promises = await Promise.all([
|
|
102
113
|
...dataFiles, ...schemaFiles, ...metadataFiles
|
|
103
114
|
]);
|
|
@@ -109,11 +120,14 @@ async function activateCallback ({
|
|
|
109
120
|
|
|
110
121
|
log('Activate: Files fetched');
|
|
111
122
|
const dbName = namespace + '-textbrowser-cache-data';
|
|
123
|
+
log('Activate: Deleting existing database', dbName);
|
|
112
124
|
indexedDB.deleteDatabase(dbName);
|
|
113
125
|
return new Promise((resolve, reject) => {
|
|
126
|
+
log('Activate: Opening database', dbName);
|
|
114
127
|
const req = indexedDB.open(dbName);
|
|
115
128
|
// @ts-expect-error Ok
|
|
116
129
|
req.addEventListener('upgradeneeded', ({target: {result: db}}) => {
|
|
130
|
+
log('Activate: Database upgrade needed', dbName);
|
|
117
131
|
db.onversionchange = () => {
|
|
118
132
|
db.close();
|
|
119
133
|
const err = /** @type {Error & {type: string}} */ (new Error('versionchange'));
|
|
@@ -122,6 +136,7 @@ async function activateCallback ({
|
|
|
122
136
|
};
|
|
123
137
|
dataFileResponses.forEach(({data: tableRows}, i) => {
|
|
124
138
|
const dataFileName = dataFileNames[i];
|
|
139
|
+
log('Activate: Creating object store', dataFileName, 'rows:', tableRows.length);
|
|
125
140
|
const store = db.createObjectStore('files-to-cache-' + dataFileName);
|
|
126
141
|
|
|
127
142
|
const schemaFileResponse = schemaFileResponses[i];
|
|
@@ -180,6 +195,12 @@ async function activateCallback ({
|
|
|
180
195
|
});
|
|
181
196
|
|
|
182
197
|
const uniqueColumnIndexes = [...new Set(columnIndexes)];
|
|
198
|
+
log(
|
|
199
|
+
'Activate: Preparing rows for store',
|
|
200
|
+
dataFileName,
|
|
201
|
+
'unique indexes:',
|
|
202
|
+
uniqueColumnIndexes.length
|
|
203
|
+
);
|
|
183
204
|
|
|
184
205
|
tableRows.forEach((tableRow, j) => {
|
|
185
206
|
// Todo: Optionally send notice when complete
|
|
@@ -203,6 +224,7 @@ async function activateCallback ({
|
|
|
203
224
|
// log('objRow', objRow);
|
|
204
225
|
store.put(objRow, j);
|
|
205
226
|
});
|
|
227
|
+
log('Activate: Finished object store population', dataFileName);
|
|
206
228
|
});
|
|
207
229
|
});
|
|
208
230
|
|
|
@@ -218,6 +240,7 @@ async function activateCallback ({
|
|
|
218
240
|
* @param {Event & {error?: Error}} ev
|
|
219
241
|
*/
|
|
220
242
|
const onerr = (ev) => {
|
|
243
|
+
log('Activate: Database request error event fired');
|
|
221
244
|
const error = /** @type {Error & {type: string}} */ (
|
|
222
245
|
ev.error ?? new Error('dbError')
|
|
223
246
|
);
|
package/dist/sw-helper.js
CHANGED
|
@@ -184,7 +184,7 @@ function swHelper (self) {
|
|
|
184
184
|
* @returns {Promise<void>}
|
|
185
185
|
*/
|
|
186
186
|
async function install (time) {
|
|
187
|
-
post({type: 'beginInstall'});
|
|
187
|
+
await post({type: 'beginInstall'});
|
|
188
188
|
log(`Install: Trying, attempt ${time}`);
|
|
189
189
|
const now = Date.now();
|
|
190
190
|
const json = await getJSON(/** @type {string} */ (pathToUserJSON));
|
|
@@ -249,7 +249,9 @@ function swHelper (self) {
|
|
|
249
249
|
}, 10000);
|
|
250
250
|
// .map((url) => url === 'index.html' ? new Request(url, {cache: 'reload'}) : url)
|
|
251
251
|
try {
|
|
252
|
-
const
|
|
252
|
+
const maxConcurrentPrefetches = 8;
|
|
253
|
+
const prefetchTimeoutMs = 120000;
|
|
254
|
+
const fetchAndCacheAsset = async (urlToPrefetch, idx) => {
|
|
253
255
|
// This constructs a new URL object using the service worker's script
|
|
254
256
|
// location as the base for relative URLs.
|
|
255
257
|
pendingAssets.add(urlToPrefetch);
|
|
@@ -260,8 +262,14 @@ function swHelper (self) {
|
|
|
260
262
|
const url = new URL(urlToPrefetch, location.href);
|
|
261
263
|
url.search += (url.search ? '&' : '?') + 'cache-bust=' + now;
|
|
262
264
|
const request = new Request(url, {mode: 'no-cors'});
|
|
265
|
+
const controller = new AbortController();
|
|
266
|
+
const timeout = setTimeout(() => {
|
|
267
|
+
controller.abort();
|
|
268
|
+
}, prefetchTimeoutMs);
|
|
263
269
|
try {
|
|
264
|
-
const response = await fetch(request
|
|
270
|
+
const response = await fetch(request, {
|
|
271
|
+
signal: controller.signal
|
|
272
|
+
});
|
|
265
273
|
if (response.status >= 400) {
|
|
266
274
|
throw new Error('request for ' + urlToPrefetch +
|
|
267
275
|
' failed with status ' + response.statusText);
|
|
@@ -272,15 +280,36 @@ function swHelper (self) {
|
|
|
272
280
|
return;
|
|
273
281
|
} catch (error) {
|
|
274
282
|
pendingAssets.delete(urlToPrefetch);
|
|
283
|
+
if (
|
|
284
|
+
error && typeof error === 'object' && 'name' in error &&
|
|
285
|
+
error.name === 'AbortError'
|
|
286
|
+
) {
|
|
287
|
+
error = new Error(
|
|
288
|
+
`Timed out after ${prefetchTimeoutMs}ms while fetching ${urlToPrefetch}`
|
|
289
|
+
);
|
|
290
|
+
}
|
|
275
291
|
logError(
|
|
276
292
|
/** @type {Error} */
|
|
277
293
|
(error),
|
|
278
294
|
`Not caching ${urlToPrefetch} due to ${error}`
|
|
279
295
|
);
|
|
280
296
|
throw error;
|
|
297
|
+
} finally {
|
|
298
|
+
clearTimeout(timeout);
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
let nextAssetIndex = 0;
|
|
303
|
+
const workers = Array.from({
|
|
304
|
+
length: Math.min(maxConcurrentPrefetches, urlsToPrefetch.length)
|
|
305
|
+
}, async () => {
|
|
306
|
+
while (nextAssetIndex < urlsToPrefetch.length) {
|
|
307
|
+
const idx = nextAssetIndex;
|
|
308
|
+
nextAssetIndex++;
|
|
309
|
+
await fetchAndCacheAsset(urlsToPrefetch[idx], idx);
|
|
281
310
|
}
|
|
282
311
|
});
|
|
283
|
-
await Promise.all(
|
|
312
|
+
await Promise.all(workers);
|
|
284
313
|
log('Install: Pre-fetching complete.');
|
|
285
314
|
} catch (error) {
|
|
286
315
|
logError(
|
|
@@ -300,7 +329,7 @@ function swHelper (self) {
|
|
|
300
329
|
|
|
301
330
|
// Although we only need one client to which to send
|
|
302
331
|
// arguments, we want to signal phase complete to all
|
|
303
|
-
post({type: 'finishedInstall'});
|
|
332
|
+
await post({type: 'finishedInstall'});
|
|
304
333
|
}
|
|
305
334
|
|
|
306
335
|
/**
|
|
@@ -309,7 +338,12 @@ function swHelper (self) {
|
|
|
309
338
|
* @returns {Promise<void>}
|
|
310
339
|
*/
|
|
311
340
|
async function activate (time) {
|
|
312
|
-
|
|
341
|
+
console.log('Activate event worker callback entered', time);
|
|
342
|
+
await post({
|
|
343
|
+
type: 'log',
|
|
344
|
+
message: `Activate: Event callback entered (attempt ${time})`
|
|
345
|
+
});
|
|
346
|
+
await post({type: 'beginActivate'});
|
|
313
347
|
log(`Activate: Trying, attempt ${time}`);
|
|
314
348
|
const [json, cacheNames] = await Promise.all([
|
|
315
349
|
getJSON(/** @type {string} */ (pathToUserJSON)),
|
|
@@ -329,9 +363,12 @@ function swHelper (self) {
|
|
|
329
363
|
await activateCallback({namespace, files, basePath, log});
|
|
330
364
|
log('Activate: Database changes completed');
|
|
331
365
|
|
|
366
|
+
await self.clients.claim();
|
|
367
|
+
log('Activate: Clients claimed');
|
|
368
|
+
|
|
332
369
|
log(`Activate: Posting finished message to clients`);
|
|
333
370
|
// Signal phase complete to all clients
|
|
334
|
-
post({type: 'finishedActivate'});
|
|
371
|
+
await post({type: 'finishedActivate'});
|
|
335
372
|
}
|
|
336
373
|
|
|
337
374
|
// @ts-expect-error Ok
|
|
@@ -348,6 +385,7 @@ function swHelper (self) {
|
|
|
348
385
|
});
|
|
349
386
|
|
|
350
387
|
self.addEventListener('activate', (e) => {
|
|
388
|
+
console.log('sw activate event fired');
|
|
351
389
|
// Erring is of no present use here:
|
|
352
390
|
// https://github.com/w3c/ServiceWorker/issues/659#issuecomment-384919053
|
|
353
391
|
e.waitUntil(tryAndRetry(activate, 5 * minutes, 'Error activating'));
|
package/package.json
CHANGED
|
@@ -55,10 +55,12 @@ export default async function activateCallback ({
|
|
|
55
55
|
// anyways); also important to avoid conflicts with
|
|
56
56
|
// already-running versions upon future sw updates
|
|
57
57
|
log('Activate: Callback called');
|
|
58
|
+
log('Activate: Fetching files manifest', files);
|
|
58
59
|
const r = await fetch(files);
|
|
59
60
|
const {groups} = /** @type {import('./utils/WorkInfo.js').FilesObject} */ (
|
|
60
61
|
await r.json()
|
|
61
62
|
);
|
|
63
|
+
log('Activate: Manifest loaded; groups:', groups.length);
|
|
62
64
|
|
|
63
65
|
/* eslint-disable jsdoc/reject-any-type -- Generic */
|
|
64
66
|
/**
|
|
@@ -67,6 +69,7 @@ export default async function activateCallback ({
|
|
|
67
69
|
*/
|
|
68
70
|
const addJSONFetch = (arr, path) => {
|
|
69
71
|
/* eslint-enable jsdoc/reject-any-type -- Generic */
|
|
72
|
+
log('Activate: Queueing JSON fetch', basePath + path);
|
|
70
73
|
arr.push(
|
|
71
74
|
(async () => (await fetch(basePath + path)).json())()
|
|
72
75
|
);
|
|
@@ -89,6 +92,13 @@ export default async function activateCallback ({
|
|
|
89
92
|
const metadataFiles = [];
|
|
90
93
|
groups.forEach(
|
|
91
94
|
({files: fileObjs, metadataBaseDirectory, schemaBaseDirectory}) => {
|
|
95
|
+
log(
|
|
96
|
+
'Activate: Processing group',
|
|
97
|
+
metadataBaseDirectory,
|
|
98
|
+
schemaBaseDirectory,
|
|
99
|
+
'files:',
|
|
100
|
+
fileObjs.length
|
|
101
|
+
);
|
|
92
102
|
fileObjs.forEach(({file: {$ref: filePath}, metadataFile, schemaFile, name}) => {
|
|
93
103
|
// We don't i18nize the name here
|
|
94
104
|
dataFileNames.push(name);
|
|
@@ -98,6 +108,7 @@ export default async function activateCallback ({
|
|
|
98
108
|
});
|
|
99
109
|
}
|
|
100
110
|
);
|
|
111
|
+
log('Activate: Awaiting queued fetches; works:', dataFiles.length);
|
|
101
112
|
const promises = await Promise.all([
|
|
102
113
|
...dataFiles, ...schemaFiles, ...metadataFiles
|
|
103
114
|
]);
|
|
@@ -109,11 +120,14 @@ export default async function activateCallback ({
|
|
|
109
120
|
|
|
110
121
|
log('Activate: Files fetched');
|
|
111
122
|
const dbName = namespace + '-textbrowser-cache-data';
|
|
123
|
+
log('Activate: Deleting existing database', dbName);
|
|
112
124
|
indexedDB.deleteDatabase(dbName);
|
|
113
125
|
return new Promise((resolve, reject) => {
|
|
126
|
+
log('Activate: Opening database', dbName);
|
|
114
127
|
const req = indexedDB.open(dbName);
|
|
115
128
|
// @ts-expect-error Ok
|
|
116
129
|
req.addEventListener('upgradeneeded', ({target: {result: db}}) => {
|
|
130
|
+
log('Activate: Database upgrade needed', dbName);
|
|
117
131
|
db.onversionchange = () => {
|
|
118
132
|
db.close();
|
|
119
133
|
const err = /** @type {Error & {type: string}} */ (new Error('versionchange'));
|
|
@@ -122,6 +136,7 @@ export default async function activateCallback ({
|
|
|
122
136
|
};
|
|
123
137
|
dataFileResponses.forEach(({data: tableRows}, i) => {
|
|
124
138
|
const dataFileName = dataFileNames[i];
|
|
139
|
+
log('Activate: Creating object store', dataFileName, 'rows:', tableRows.length);
|
|
125
140
|
const store = db.createObjectStore('files-to-cache-' + dataFileName);
|
|
126
141
|
|
|
127
142
|
const schemaFileResponse = schemaFileResponses[i];
|
|
@@ -180,6 +195,12 @@ export default async function activateCallback ({
|
|
|
180
195
|
});
|
|
181
196
|
|
|
182
197
|
const uniqueColumnIndexes = [...new Set(columnIndexes)];
|
|
198
|
+
log(
|
|
199
|
+
'Activate: Preparing rows for store',
|
|
200
|
+
dataFileName,
|
|
201
|
+
'unique indexes:',
|
|
202
|
+
uniqueColumnIndexes.length
|
|
203
|
+
);
|
|
183
204
|
|
|
184
205
|
tableRows.forEach((tableRow, j) => {
|
|
185
206
|
// Todo: Optionally send notice when complete
|
|
@@ -203,6 +224,7 @@ export default async function activateCallback ({
|
|
|
203
224
|
// log('objRow', objRow);
|
|
204
225
|
store.put(objRow, j);
|
|
205
226
|
});
|
|
227
|
+
log('Activate: Finished object store population', dataFileName);
|
|
206
228
|
});
|
|
207
229
|
});
|
|
208
230
|
|
|
@@ -218,6 +240,7 @@ export default async function activateCallback ({
|
|
|
218
240
|
* @param {Event & {error?: Error}} ev
|
|
219
241
|
*/
|
|
220
242
|
const onerr = (ev) => {
|
|
243
|
+
log('Activate: Database request error event fired');
|
|
221
244
|
const error = /** @type {Error & {type: string}} */ (
|
|
222
245
|
ev.error ?? new Error('dbError')
|
|
223
246
|
);
|