@lls/offline 24.22.0-5bf1d034 → 24.22.0-5c0809f5
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/lib/assets/fetch-worker.js +65 -18
- package/lib/assets/offline-worker.js +95 -35
- package/lib/index.js +57 -22
- package/package.json +2 -2
|
@@ -62,6 +62,7 @@ var makeSyncHandler = a(
|
|
|
62
62
|
})
|
|
63
63
|
);
|
|
64
64
|
var jsonToBuf = (json) => new TextEncoder().encode(JSON.stringify(json));
|
|
65
|
+
var openCache = async () => caches.open(`LLS_OFFLINE_${process.env.CONF_ENV}`);
|
|
65
66
|
|
|
66
67
|
// src/worker/swFetchScreenCall.ts
|
|
67
68
|
var zipSlugName = (str) => str.replace(/[^a-zA-Z0-9-.]/g, "");
|
|
@@ -196,7 +197,7 @@ var canHandleScreenCall = (url) => new RegExp(Object.keys(handles).join("|")).te
|
|
|
196
197
|
var handleScreenCall = async (ev, { offlineWorkerSync: offlineWorkerSync2, knownLinks: knownLinks2 }) => {
|
|
197
198
|
try {
|
|
198
199
|
const variables = (
|
|
199
|
-
// @ts-
|
|
200
|
+
// @ts-expect-error TODO: handle variables from body(stream) properly!!
|
|
200
201
|
ev.request.body?.variables || JSON.parse(new URLSearchParams(new URL(ev.request.url).search).get("variables") || "{}")
|
|
201
202
|
);
|
|
202
203
|
console.debug("variables are", variables, "vs", ev.request.body);
|
|
@@ -211,6 +212,12 @@ var handleScreenCall = async (ev, { offlineWorkerSync: offlineWorkerSync2, known
|
|
|
211
212
|
return { status: 500, json: JSON.stringify(e) };
|
|
212
213
|
}
|
|
213
214
|
};
|
|
215
|
+
var setKnownLinks = (knownLinks2, { entryNames, bookId }) => {
|
|
216
|
+
entryNames.forEach((entryName) => {
|
|
217
|
+
const link = entryName.replace(new RegExp(`^\\d+/media/|^${bookId}/medias/`), "").replace(new RegExp(`^${bookId}/gqls/`), "gqls/");
|
|
218
|
+
knownLinks2.set(link, { entryName, bookId });
|
|
219
|
+
});
|
|
220
|
+
};
|
|
214
221
|
|
|
215
222
|
// src/worker/fetch-worker.ts
|
|
216
223
|
var fetchAsset = async (ev, { entryId, mimeType, offlineWorkerSync: offlineWorkerSync2 }) => {
|
|
@@ -278,36 +285,70 @@ var ACCEPTED_EXTENSIONS = {
|
|
|
278
285
|
".m4a": "audio/mp4",
|
|
279
286
|
".webp": "image/webp"
|
|
280
287
|
};
|
|
288
|
+
var putInCache = async (request, response) => {
|
|
289
|
+
const cache = await openCache();
|
|
290
|
+
await cache.put(request, response);
|
|
291
|
+
};
|
|
292
|
+
var onlineFirst = async (request, event) => {
|
|
293
|
+
try {
|
|
294
|
+
const responseFromNetwork = await fetch(request);
|
|
295
|
+
const cached = putInCache(request, responseFromNetwork.clone());
|
|
296
|
+
if (request.url.endsWith(".zip")) {
|
|
297
|
+
await cached;
|
|
298
|
+
event.waitUntil(Promise.resolve());
|
|
299
|
+
} else {
|
|
300
|
+
event.waitUntil(cached);
|
|
301
|
+
}
|
|
302
|
+
return responseFromNetwork;
|
|
303
|
+
} catch (_e) {
|
|
304
|
+
const over = /\/\?story=basic/.test(request.url) ? request.url.replace(/\/\?story=.*$/, "") : request;
|
|
305
|
+
const responseFromCache = await caches.match(over);
|
|
306
|
+
if (!responseFromCache) {
|
|
307
|
+
return new Response("FAILED fetch", {
|
|
308
|
+
// @ts-ignore: poor ts typing
|
|
309
|
+
ok: false,
|
|
310
|
+
status: 500,
|
|
311
|
+
type: "cors",
|
|
312
|
+
url: event.request.url
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
return responseFromCache;
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
var STORAGE = "cache";
|
|
281
319
|
var swSelf = self;
|
|
282
320
|
swSelf.addEventListener("fetch", (ev) => {
|
|
283
321
|
const url = ev.request.url;
|
|
284
322
|
const extension = url.match(/\.[^.]+$/)?.[0];
|
|
285
323
|
const mimeType = extension && extension in ACCEPTED_EXTENSIONS ? ACCEPTED_EXTENSIONS[extension] : "";
|
|
286
324
|
const isValidScreenCall = canHandleScreenCall(url);
|
|
325
|
+
if (STORAGE !== "cache" && url.endsWith(".zip")) {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
287
328
|
if (!mimeType && !isValidScreenCall) {
|
|
288
329
|
if (!/\.(css|tsx?|jsx?|woff2|fr|manifest)(\??|$)|@(vite|react|id)/.test(url)) {
|
|
289
330
|
console.debug("no ext", extension || url);
|
|
290
331
|
}
|
|
291
|
-
return;
|
|
332
|
+
return ev.respondWith(onlineFirst(ev.request, ev));
|
|
292
333
|
}
|
|
293
334
|
const entryId = knownLinks.get(url.replace(/https:\/\/.*?\//, "")) || knownLinks.get(`medias/${url.replace(/https:\/\/.*?\//, "")}`);
|
|
294
|
-
if (!entryId && !isValidScreenCall) {
|
|
295
|
-
if (/lls|lelivrescolaire/.test(url)) {
|
|
296
|
-
console.info("no link for", url.replace(/https:\/\/.*?\//, ""));
|
|
297
|
-
}
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
335
|
if (isValidScreenCall) {
|
|
301
336
|
console.debug("screencall!");
|
|
302
337
|
return ev.respondWith(fetchScreenCall(ev, { offlineWorkerSync, knownLinks }));
|
|
303
338
|
}
|
|
304
|
-
|
|
339
|
+
if (entryId) {
|
|
340
|
+
return ev.respondWith(fetchAsset(ev, { entryId, mimeType, offlineWorkerSync }));
|
|
341
|
+
}
|
|
342
|
+
if (/lls|lelivrescolaire/.test(url)) {
|
|
343
|
+
console.info("no link for", url.replace(/https:\/\/.*?\//, ""), `medias/${url.replace(/https:\/\/.*?\//, "")}`);
|
|
344
|
+
}
|
|
345
|
+
return;
|
|
305
346
|
});
|
|
306
347
|
swSelf.addEventListener("install", (_event) => {
|
|
307
348
|
swSelf.skipWaiting();
|
|
308
349
|
});
|
|
309
|
-
swSelf.addEventListener("activate", (
|
|
310
|
-
|
|
350
|
+
swSelf.addEventListener("activate", (event) => {
|
|
351
|
+
event.waitUntil(swSelf.clients.claim());
|
|
311
352
|
});
|
|
312
353
|
var offlineWorker;
|
|
313
354
|
var offlineWorkerSync;
|
|
@@ -321,24 +362,30 @@ var initChannel = async (__, { ports }) => {
|
|
|
321
362
|
);
|
|
322
363
|
offlineWorkerSync = sender;
|
|
323
364
|
offlineWorker.onmessage = handler.handle;
|
|
324
|
-
offlineWorkerSync.on("setKnownLinks", setKnownLinks);
|
|
365
|
+
offlineWorkerSync.on("setKnownLinks", setKnownLinks.bind(null, setKnownLinks));
|
|
325
366
|
offlineWorker.postMessage({ methodName: "sendAppReady" });
|
|
326
367
|
};
|
|
327
368
|
var knownLinks = /* @__PURE__ */ new Map();
|
|
328
|
-
var
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
}
|
|
369
|
+
var configure = ({ storage } = {}) => {
|
|
370
|
+
STORAGE = "cache";
|
|
371
|
+
if (typeof storage !== "undefined") {
|
|
372
|
+
STORAGE = storage;
|
|
373
|
+
}
|
|
374
|
+
console.info("sw::configure", { STORAGE });
|
|
333
375
|
};
|
|
334
376
|
swSelf.onmessage = async ({
|
|
335
377
|
data: { methodName, arg } = {},
|
|
336
378
|
ports
|
|
337
379
|
}) => {
|
|
338
380
|
const services = {
|
|
339
|
-
initChannel
|
|
381
|
+
initChannel,
|
|
382
|
+
configure
|
|
340
383
|
};
|
|
341
384
|
try {
|
|
385
|
+
if (methodName === "configure") {
|
|
386
|
+
await services[methodName](arg);
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
342
389
|
if (methodName === "initChannel") {
|
|
343
390
|
if (!ports.length) {
|
|
344
391
|
throw new Error("fetchworker::missing port!");
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
// src/utils/error.ts
|
|
2
|
+
var tryCatch = (fn) => {
|
|
3
|
+
return (resolve, reject) => {
|
|
4
|
+
try {
|
|
5
|
+
return fn().then(resolve);
|
|
6
|
+
} catch (e) {
|
|
7
|
+
return reject(e);
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
|
|
1
12
|
// src/utils/worker.ts
|
|
2
13
|
var makeSyncWorker = (offlineWorker, methodNames, dbg) => {
|
|
3
14
|
const dic = {};
|
|
@@ -72,6 +83,7 @@ var combineHandlers = (...handlers) => {
|
|
|
72
83
|
console.error("no handlers matched", methodName);
|
|
73
84
|
};
|
|
74
85
|
};
|
|
86
|
+
var openCache = async () => caches.open(`LLS_OFFLINE_${process.env.CONF_ENV}`);
|
|
75
87
|
|
|
76
88
|
// src/worker/wwApi.ts
|
|
77
89
|
var STATE = {
|
|
@@ -830,17 +842,24 @@ var loadZip = async (buf, bookId) => {
|
|
|
830
842
|
|
|
831
843
|
// src/worker/offline-worker.ts
|
|
832
844
|
var CHECK_UPDATES = true;
|
|
833
|
-
var
|
|
834
|
-
var
|
|
845
|
+
var STORAGE = "cache";
|
|
846
|
+
var ZIP_BASE_URL = "https://ci.lls.fr/artefacts/content/development";
|
|
847
|
+
var LOADED_BOOKS = /* @__PURE__ */ new Map();
|
|
835
848
|
var fetchZipFile = async (zipUrl, { forceRefresh } = {}) => {
|
|
836
849
|
const fileName = zipUrl.split("/").slice(-1)[0];
|
|
837
850
|
const readArrayBuffer = async () => {
|
|
838
|
-
if (
|
|
839
|
-
console.debug("try reading native", fileName);
|
|
851
|
+
if (STORAGE === "native") {
|
|
840
852
|
const back = await sender.nativeReadFile({ fname: fileName });
|
|
841
|
-
console.debug("done readnig");
|
|
842
853
|
return back;
|
|
843
854
|
}
|
|
855
|
+
if (STORAGE === "cache") {
|
|
856
|
+
const response = await caches.match(zipUrl);
|
|
857
|
+
if (!response) {
|
|
858
|
+
throw new Error(`missing zip ${zipUrl}`);
|
|
859
|
+
}
|
|
860
|
+
const buf = await response.arrayBuffer();
|
|
861
|
+
return buf;
|
|
862
|
+
}
|
|
844
863
|
const opfsRoot = await navigator.storage.getDirectory();
|
|
845
864
|
const handle = await opfsRoot.getFileHandle(fileName);
|
|
846
865
|
const accessHandle = await handle.createSyncAccessHandle();
|
|
@@ -868,7 +887,7 @@ var fetchZipFile = async (zipUrl, { forceRefresh } = {}) => {
|
|
|
868
887
|
return buf;
|
|
869
888
|
} catch (e) {
|
|
870
889
|
if (e instanceof Error && e.message !== "forceRefresh" && !e.message.includes("refetching")) {
|
|
871
|
-
console.debug(
|
|
890
|
+
console.debug(`${STORAGE} zip not found, creating it`, e, zipUrl);
|
|
872
891
|
}
|
|
873
892
|
const response = await fetch(zipUrl);
|
|
874
893
|
const contentLength = +response.headers.get("Content-Length");
|
|
@@ -879,6 +898,7 @@ var fetchZipFile = async (zipUrl, { forceRefresh } = {}) => {
|
|
|
879
898
|
while (true) {
|
|
880
899
|
const { done, value: chunk } = await reader.read();
|
|
881
900
|
if (done) {
|
|
901
|
+
self.postMessage({ methodName: "opfsProgress", arg: { total: contentLength, bytes: contentLength } });
|
|
882
902
|
break;
|
|
883
903
|
}
|
|
884
904
|
arrayBuffer.set(chunk, position);
|
|
@@ -893,44 +913,69 @@ var fetchZipFile = async (zipUrl, { forceRefresh } = {}) => {
|
|
|
893
913
|
console.debug(error);
|
|
894
914
|
throw new Error(error);
|
|
895
915
|
}
|
|
896
|
-
if (
|
|
916
|
+
if (STORAGE === "native") {
|
|
897
917
|
await sender.nativeWriteFile({ fname: fileName, buffer: arrayBuffer });
|
|
898
|
-
|
|
918
|
+
} else if (STORAGE === "opfs") {
|
|
919
|
+
const opfsRoot = await navigator.storage.getDirectory();
|
|
920
|
+
const handle = await opfsRoot.getFileHandle(fileName, { create: true });
|
|
921
|
+
const accessHandle = await handle.createSyncAccessHandle();
|
|
922
|
+
await accessHandle.truncate(0);
|
|
923
|
+
await accessHandle.write(arrayBuffer);
|
|
924
|
+
await accessHandle.close();
|
|
925
|
+
} else {
|
|
926
|
+
const cache = await openCache();
|
|
927
|
+
const response2 = new Response(arrayBuffer, {
|
|
928
|
+
headers: {
|
|
929
|
+
"Cache-Control": "max-age=600, s-maxage=600, public, proxy-revalidate",
|
|
930
|
+
"Content-Type": "application/zip"
|
|
931
|
+
},
|
|
932
|
+
// @ts-ignore: poor ts typing
|
|
933
|
+
ok: true,
|
|
934
|
+
redirected: false,
|
|
935
|
+
status: 200,
|
|
936
|
+
type: "cors",
|
|
937
|
+
url: zipUrl
|
|
938
|
+
});
|
|
939
|
+
await cache.put(zipUrl, response2);
|
|
899
940
|
}
|
|
900
|
-
const opfsRoot = await navigator.storage.getDirectory();
|
|
901
|
-
const handle = await opfsRoot.getFileHandle(fileName, { create: true });
|
|
902
|
-
const accessHandle = await handle.createSyncAccessHandle();
|
|
903
|
-
await accessHandle.truncate(0);
|
|
904
|
-
await accessHandle.write(arrayBuffer);
|
|
905
|
-
await accessHandle.close();
|
|
906
941
|
return await readArrayBuffer();
|
|
907
942
|
}
|
|
908
943
|
};
|
|
909
944
|
var slugToFileMeta2 = async ({ slug }) => {
|
|
910
|
-
console.debug("hereshit");
|
|
911
945
|
const json = await readZipEntry({ bookId: "preload", entryName: "preload/hashmap_slugToMetaPage.json", asJson: true });
|
|
912
|
-
console.debug("hereshit2");
|
|
913
946
|
return slugToFileMeta({ slug, json });
|
|
914
947
|
};
|
|
915
948
|
var PRELOAD_AS_BOOK_ID = "preload";
|
|
916
949
|
var isOldZip = (bookId) => typeof bookId === "number";
|
|
917
950
|
var loadBook2 = async ({ id: bookId, forceRefresh }) => {
|
|
918
951
|
if (LOADED_BOOKS.has(bookId)) {
|
|
952
|
+
await LOADED_BOOKS.get(bookId);
|
|
919
953
|
self.postMessage({ methodName: "opfsProgress", arg: { total: 1, bytes: 1 } });
|
|
920
954
|
return;
|
|
921
955
|
}
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
956
|
+
const p = new Promise(
|
|
957
|
+
tryCatch(async () => {
|
|
958
|
+
const buf = await fetchZipFile(`${ZIP_BASE_URL}/${bookId}.zip`, { forceRefresh });
|
|
959
|
+
try {
|
|
960
|
+
const entryNames = await loadZip(new Uint8Array(buf), bookId);
|
|
961
|
+
fetchWorker.postMessage({ methodName: "setKnownLinks", arg: { entryNames, bookId } });
|
|
962
|
+
if (isOldZip(bookId)) {
|
|
963
|
+
const json = await readZipEntry({
|
|
964
|
+
entryName: `preload/${bookId}.json`,
|
|
965
|
+
bookId: PRELOAD_AS_BOOK_ID,
|
|
966
|
+
asJson: true
|
|
967
|
+
});
|
|
968
|
+
loadBook(json);
|
|
969
|
+
}
|
|
970
|
+
return true;
|
|
971
|
+
} catch (e) {
|
|
972
|
+
console.error("failed", e);
|
|
973
|
+
return false;
|
|
974
|
+
}
|
|
975
|
+
})
|
|
976
|
+
);
|
|
977
|
+
LOADED_BOOKS.set(bookId, p);
|
|
978
|
+
await p;
|
|
934
979
|
};
|
|
935
980
|
var loadPageContent2 = async ({
|
|
936
981
|
bookId: iBookId,
|
|
@@ -973,11 +1018,16 @@ var initChannel = (__, { ports }) => {
|
|
|
973
1018
|
};
|
|
974
1019
|
var loadBooks = async ({ primaryOnly = false } = {}) => {
|
|
975
1020
|
let entries = [];
|
|
976
|
-
if (
|
|
1021
|
+
if (STORAGE === "native") {
|
|
977
1022
|
entries = await sender.nativeListZips();
|
|
978
|
-
} else {
|
|
1023
|
+
} else if (STORAGE === "opfs") {
|
|
979
1024
|
const opfsRoot = await navigator.storage.getDirectory();
|
|
980
1025
|
entries = await opfsRoot.values();
|
|
1026
|
+
} else {
|
|
1027
|
+
const cache = await openCache();
|
|
1028
|
+
const keys = await cache.keys();
|
|
1029
|
+
const zips = keys.filter((key2) => key2.url.endsWith(".zip"));
|
|
1030
|
+
entries = zips.map((zip) => ({ name: String(zip.url.split("/").pop()) }));
|
|
981
1031
|
}
|
|
982
1032
|
for await (const entry of entries) {
|
|
983
1033
|
if (/preload/.test(entry.name)) {
|
|
@@ -996,14 +1046,24 @@ var loadBooks = async ({ primaryOnly = false } = {}) => {
|
|
|
996
1046
|
}
|
|
997
1047
|
}
|
|
998
1048
|
};
|
|
999
|
-
var configure = ({
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1049
|
+
var configure = ({
|
|
1050
|
+
storage,
|
|
1051
|
+
checkUpdates,
|
|
1052
|
+
zipBaseUrl
|
|
1053
|
+
}) => {
|
|
1054
|
+
CHECK_UPDATES = true;
|
|
1055
|
+
STORAGE = "cache";
|
|
1056
|
+
ZIP_BASE_URL = "https://ci.lls.fr/artefacts/content/development";
|
|
1057
|
+
if (typeof storage !== "undefined") {
|
|
1058
|
+
STORAGE = storage;
|
|
1003
1059
|
}
|
|
1004
|
-
if (typeof
|
|
1060
|
+
if (typeof checkUpdates !== "undefined") {
|
|
1005
1061
|
CHECK_UPDATES = !!checkUpdates;
|
|
1006
1062
|
}
|
|
1063
|
+
if (typeof zipBaseUrl !== "undefined") {
|
|
1064
|
+
ZIP_BASE_URL = zipBaseUrl;
|
|
1065
|
+
}
|
|
1066
|
+
console.info("ow::configure", { STORAGE, CHECK_UPDATES, ZIP_BASE_URL });
|
|
1007
1067
|
};
|
|
1008
1068
|
var loadPreload2 = async () => {
|
|
1009
1069
|
const zipUrl = "https://lls-ci-fr.s3.eu-west-3.amazonaws.com/artefacts/content/development/preload.zip";
|
package/lib/index.js
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
// src/utils/error.ts
|
|
2
|
+
var tryCatch = (fn) => {
|
|
3
|
+
return (resolve, reject) => {
|
|
4
|
+
try {
|
|
5
|
+
return fn().then(resolve);
|
|
6
|
+
} catch (e) {
|
|
7
|
+
return reject(e);
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
|
|
1
12
|
// src/utils/worker.ts
|
|
2
13
|
var makeSyncWorker = (offlineWorker2, methodNames, dbg) => {
|
|
3
14
|
const dic = {};
|
|
@@ -76,11 +87,28 @@ var combineHandlers = (...handlers) => {
|
|
|
76
87
|
import { useCallback, useEffect, useState } from "react";
|
|
77
88
|
var offlineWorker = new Worker("/src/worker/offline-worker.js", { type: "module" });
|
|
78
89
|
var { handler, ...offlineWorkerSync } = makeSyncWorker(
|
|
79
|
-
// @ts-ignore: TODO
|
|
80
90
|
offlineWorker,
|
|
81
91
|
["initChannel", "readZipEntry", "configure", "loadPreload", "loadBooks", "loadBook"],
|
|
82
92
|
"app:offlineWorker"
|
|
83
93
|
);
|
|
94
|
+
var fetchWorkerPromise = new Promise(
|
|
95
|
+
tryCatch(async () => {
|
|
96
|
+
let fetchWorker = null;
|
|
97
|
+
await navigator.serviceWorker.register("/fetch-worker.js", { type: "module" }).then((reg) => {
|
|
98
|
+
return reg.update().catch((e) => {
|
|
99
|
+
console.debug(e, "likely we are offline");
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
await navigator.serviceWorker.ready.then(async (reg) => {
|
|
103
|
+
console.debug("Service Worker registered:", reg.scope);
|
|
104
|
+
fetchWorker = reg.active;
|
|
105
|
+
}).catch((err) => console.error("Service Worker registration failed:", err));
|
|
106
|
+
if (!fetchWorker) {
|
|
107
|
+
console.debug("failed to get fetch worker");
|
|
108
|
+
}
|
|
109
|
+
return fetchWorker;
|
|
110
|
+
})
|
|
111
|
+
);
|
|
84
112
|
var setWorkersReady;
|
|
85
113
|
var workersReadyPromise = new Promise((resolve) => {
|
|
86
114
|
setWorkersReady = resolve;
|
|
@@ -90,45 +118,41 @@ var setBooksLoadedPromise = new Promise((resolve) => {
|
|
|
90
118
|
setBooksLoaded = resolve;
|
|
91
119
|
});
|
|
92
120
|
var installWorker = async ({
|
|
121
|
+
skipLoadBooks = false,
|
|
93
122
|
primaryOnly = false,
|
|
94
123
|
nativeReadFile,
|
|
95
124
|
nativeWriteFile,
|
|
96
125
|
nativeListZips,
|
|
126
|
+
storage,
|
|
127
|
+
zipBaseUrl,
|
|
97
128
|
checkUpdates
|
|
98
129
|
} = {}) => {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
for (const registration of registrations) {
|
|
102
|
-
await registration.unregister();
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
await navigator.serviceWorker.register("/fetch-worker.js", { type: "module" }).then((reg) => reg.update());
|
|
106
|
-
await navigator.serviceWorker.ready.then(async (reg) => {
|
|
107
|
-
console.debug("Service Worker registered:", reg.scope);
|
|
108
|
-
fetchWorker = reg.active;
|
|
109
|
-
}).catch((err) => console.error("Service Worker registration failed:", err));
|
|
110
|
-
if (!fetchWorker) {
|
|
111
|
-
console.debug("failed to get fetch worker");
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
130
|
+
const fetchWorker = await fetchWorkerPromise;
|
|
131
|
+
const configureOptions = { storage, zipBaseUrl, checkUpdates };
|
|
114
132
|
if (nativeReadFile) {
|
|
115
133
|
const wwHandler = makeSyncHandler(offlineWorker, { nativeReadFile, nativeWriteFile, nativeListZips });
|
|
116
134
|
offlineWorker.onmessage = combineHandlers(handler, wwHandler);
|
|
117
|
-
|
|
135
|
+
if (storage !== "native") {
|
|
136
|
+
console.warn("nativeReadFile given, ignoring storage", storage);
|
|
137
|
+
}
|
|
138
|
+
offlineWorkerSync.configure({ ...configureOptions, storage: "native" });
|
|
118
139
|
} else {
|
|
119
|
-
offlineWorkerSync.configure({ native: false, checkUpdates });
|
|
120
140
|
offlineWorker.onmessage = handler.handle;
|
|
141
|
+
offlineWorkerSync.configure(configureOptions);
|
|
121
142
|
}
|
|
122
143
|
offlineWorkerSync.on("ready", setWorkersReady);
|
|
123
144
|
const channel = new MessageChannel();
|
|
124
145
|
offlineWorkerSync.initChannel({ ports: [channel.port1] });
|
|
125
146
|
fetchWorker.postMessage({ methodName: "initChannel" }, [channel.port2]);
|
|
147
|
+
fetchWorker.postMessage({ methodName: "configure", arg: { storage } });
|
|
126
148
|
offlineWorkerSync.on("opfsProgress", () => {
|
|
127
149
|
});
|
|
128
150
|
if (!primaryOnly) {
|
|
129
151
|
await offlineWorkerSync.loadPreload();
|
|
130
152
|
}
|
|
131
|
-
|
|
153
|
+
if (!skipLoadBooks) {
|
|
154
|
+
await offlineWorkerSync.loadBooks({ primaryOnly });
|
|
155
|
+
}
|
|
132
156
|
setBooksLoaded();
|
|
133
157
|
};
|
|
134
158
|
var useOfflineWorker_default = ({
|
|
@@ -136,17 +160,28 @@ var useOfflineWorker_default = ({
|
|
|
136
160
|
nativeReadFile,
|
|
137
161
|
nativeWriteFile,
|
|
138
162
|
nativeListZips,
|
|
139
|
-
checkUpdates
|
|
163
|
+
checkUpdates,
|
|
164
|
+
storage,
|
|
165
|
+
zipBaseUrl
|
|
140
166
|
} = {}) => {
|
|
141
167
|
const [ready, setReady] = useState(false);
|
|
142
168
|
useEffect(() => {
|
|
143
169
|
const fn = async () => {
|
|
144
|
-
await installWorker({
|
|
170
|
+
await installWorker({
|
|
171
|
+
primaryOnly,
|
|
172
|
+
nativeReadFile,
|
|
173
|
+
nativeWriteFile,
|
|
174
|
+
nativeListZips,
|
|
175
|
+
storage,
|
|
176
|
+
zipBaseUrl,
|
|
177
|
+
checkUpdates
|
|
178
|
+
});
|
|
145
179
|
await Promise.all([workersReadyPromise, setBooksLoadedPromise]);
|
|
180
|
+
fetch(window.location.href.replace(window.location.search, ""));
|
|
146
181
|
setReady(true);
|
|
147
182
|
};
|
|
148
183
|
fn();
|
|
149
|
-
}, [primaryOnly, nativeReadFile, nativeWriteFile, nativeListZips, checkUpdates]);
|
|
184
|
+
}, [primaryOnly, nativeReadFile, nativeWriteFile, nativeListZips, storage, zipBaseUrl, checkUpdates]);
|
|
150
185
|
const loadBook = useCallback(
|
|
151
186
|
async ({ id, forceRefresh }, cbk) => {
|
|
152
187
|
offlineWorkerSync.on("opfsProgress", cbk);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lls/offline",
|
|
3
|
-
"version": "24.22.0-
|
|
3
|
+
"version": "24.22.0-5c0809f5",
|
|
4
4
|
"description": "offline",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"module": "./lib/index.js",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"vite": "7.0.0",
|
|
53
53
|
"vite-tsconfig-paths": "5.1.4",
|
|
54
54
|
"zod": "3.25.50",
|
|
55
|
-
"@lls/vitescripts": "24.22.0-
|
|
55
|
+
"@lls/vitescripts": "24.22.0-5c0809f5"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"fflate": "0.8.2"
|