@lls/offline 24.22.0-debug → 24.22.0-eaf69c80
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 +32 -18
- package/lib/assets/offline-worker.js +128 -24
- package/lib/index.js +81 -33
- package/package.json +12 -6
|
@@ -11,12 +11,11 @@ var makeSyncWorker = (offlineWorker2, methodNames, dbg) => {
|
|
|
11
11
|
}
|
|
12
12
|
} else {
|
|
13
13
|
if (methodName && !methodName.startsWith("async") && !(methodName in cbks)) {
|
|
14
|
-
console.error(`syncWorker: ${dbg}`, eventId, methodName, error);
|
|
14
|
+
console.error(`syncWorker: unknown methodName cbk ${dbg}`, eventId, methodName, error);
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
methodName && cbks[methodName]?.(arg);
|
|
18
18
|
};
|
|
19
|
-
offlineWorker2.onmessage = fn;
|
|
20
19
|
const makeFn = (methodName) => {
|
|
21
20
|
return ({ ports, ...arg } = {}) => {
|
|
22
21
|
return new Promise((resolve, reject) => {
|
|
@@ -31,23 +30,36 @@ var makeSyncWorker = (offlineWorker2, methodNames, dbg) => {
|
|
|
31
30
|
cbks[key] = fn2;
|
|
32
31
|
}
|
|
33
32
|
});
|
|
34
|
-
return
|
|
33
|
+
return {
|
|
34
|
+
...obj,
|
|
35
|
+
handler: {
|
|
36
|
+
canHandle: (methodName) => {
|
|
37
|
+
return methodName in cbks || methodNames.includes(methodName);
|
|
38
|
+
},
|
|
39
|
+
handle: fn
|
|
40
|
+
}
|
|
41
|
+
};
|
|
35
42
|
};
|
|
36
43
|
var a = (a2) => a2;
|
|
37
44
|
var makeSyncHandler = a(
|
|
38
|
-
(sender, services) =>
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
45
|
+
(sender, services) => ({
|
|
46
|
+
canHandle: (methodName) => {
|
|
47
|
+
return methodName in services;
|
|
48
|
+
},
|
|
49
|
+
handle: async ({ data: { eventId, methodName, arg } = {}, ports }) => {
|
|
50
|
+
try {
|
|
51
|
+
if (typeof methodName === "string" && methodName in services && services[methodName]) {
|
|
52
|
+
const results = await services[methodName](arg, { ports });
|
|
53
|
+
sender.postMessage({ eventId, methodName, results });
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
throw new Error(`invalid methodName ${Object.keys(services)} |${String(methodName)}`);
|
|
57
|
+
} catch (e) {
|
|
58
|
+
console.debug("failed", e);
|
|
59
|
+
sender.postMessage({ eventId, methodName, error: e });
|
|
44
60
|
}
|
|
45
|
-
throw new Error(`invalid methodName ${Object.keys(services)} |${String(methodName)}`);
|
|
46
|
-
} catch (e) {
|
|
47
|
-
console.debug("failed", e);
|
|
48
|
-
sender.postMessage({ eventId, methodName, error: e });
|
|
49
61
|
}
|
|
50
|
-
}
|
|
62
|
+
})
|
|
51
63
|
);
|
|
52
64
|
var jsonToBuf = (json) => new TextEncoder().encode(JSON.stringify(json));
|
|
53
65
|
|
|
@@ -273,8 +285,8 @@ swSelf.addEventListener("fetch", (ev) => {
|
|
|
273
285
|
const mimeType = extension && extension in ACCEPTED_EXTENSIONS ? ACCEPTED_EXTENSIONS[extension] : "";
|
|
274
286
|
const isValidScreenCall = canHandleScreenCall(url);
|
|
275
287
|
if (!mimeType && !isValidScreenCall) {
|
|
276
|
-
if (!/\.(css|tsx?|jsx?|woff2|fr)/.test(url)) {
|
|
277
|
-
console.debug("no ext", url
|
|
288
|
+
if (!/\.(css|tsx?|jsx?|woff2|fr|manifest)(\??|$)|@(vite|react|id)/.test(url)) {
|
|
289
|
+
console.debug("no ext", extension || url);
|
|
278
290
|
}
|
|
279
291
|
return;
|
|
280
292
|
}
|
|
@@ -300,13 +312,15 @@ swSelf.addEventListener("activate", (_event) => {
|
|
|
300
312
|
var offlineWorker;
|
|
301
313
|
var offlineWorkerSync;
|
|
302
314
|
var initChannel = async (__, { ports }) => {
|
|
303
|
-
console.info(`FETCH WORKER innitChannel v${
|
|
315
|
+
console.info(`FETCH WORKER innitChannel v${/* @__PURE__ */ new Date()}`);
|
|
304
316
|
offlineWorker = ports[0];
|
|
305
|
-
|
|
317
|
+
const { handler, ...sender } = makeSyncWorker(
|
|
306
318
|
offlineWorker,
|
|
307
319
|
["readZipEntry", "loadBook", "slugToFileMeta", "loadPageContent", "searchBooks"],
|
|
308
320
|
"fetchworker"
|
|
309
321
|
);
|
|
322
|
+
offlineWorkerSync = sender;
|
|
323
|
+
offlineWorker.onmessage = handler.handle;
|
|
310
324
|
offlineWorkerSync.on("setKnownLinks", setKnownLinks);
|
|
311
325
|
offlineWorker.postMessage({ methodName: "sendAppReady" });
|
|
312
326
|
};
|
|
@@ -1,21 +1,77 @@
|
|
|
1
1
|
// src/utils/worker.ts
|
|
2
|
+
var makeSyncWorker = (offlineWorker, methodNames, dbg) => {
|
|
3
|
+
const dic = {};
|
|
4
|
+
const cbks = {};
|
|
5
|
+
const fn = ({ data: { eventId, methodName, results, error, arg } = {} } = {}) => {
|
|
6
|
+
if (eventId && eventId in dic) {
|
|
7
|
+
if (error) {
|
|
8
|
+
dic[eventId].reject(error);
|
|
9
|
+
} else {
|
|
10
|
+
dic[eventId].resolve(results);
|
|
11
|
+
}
|
|
12
|
+
} else {
|
|
13
|
+
if (methodName && !methodName.startsWith("async") && !(methodName in cbks)) {
|
|
14
|
+
console.error(`syncWorker: unknown methodName cbk ${dbg}`, eventId, methodName, error);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
methodName && cbks[methodName]?.(arg);
|
|
18
|
+
};
|
|
19
|
+
const makeFn = (methodName) => {
|
|
20
|
+
return ({ ports, ...arg } = {}) => {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
const eventId = `${methodName}:${Date.now()}`;
|
|
23
|
+
dic[eventId] = { resolve, reject };
|
|
24
|
+
offlineWorker.postMessage({ eventId, methodName, arg }, ports);
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
const obj = Object.assign(Object.fromEntries(methodNames.map((name) => [name, makeFn(name)])), {
|
|
29
|
+
on: (key2, fn2) => {
|
|
30
|
+
cbks[key2] = fn2;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
...obj,
|
|
35
|
+
handler: {
|
|
36
|
+
canHandle: (methodName) => {
|
|
37
|
+
return methodName in cbks || methodNames.includes(methodName);
|
|
38
|
+
},
|
|
39
|
+
handle: fn
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
};
|
|
2
43
|
var a = (a2) => a2;
|
|
3
44
|
var makeSyncHandler = a(
|
|
4
|
-
(
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
45
|
+
(sender2, services) => ({
|
|
46
|
+
canHandle: (methodName) => {
|
|
47
|
+
return methodName in services;
|
|
48
|
+
},
|
|
49
|
+
handle: async ({ data: { eventId, methodName, arg } = {}, ports }) => {
|
|
50
|
+
try {
|
|
51
|
+
if (typeof methodName === "string" && methodName in services && services[methodName]) {
|
|
52
|
+
const results = await services[methodName](arg, { ports });
|
|
53
|
+
sender2.postMessage({ eventId, methodName, results });
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
throw new Error(`invalid methodName ${Object.keys(services)} |${String(methodName)}`);
|
|
57
|
+
} catch (e) {
|
|
58
|
+
console.debug("failed", e);
|
|
59
|
+
sender2.postMessage({ eventId, methodName, error: e });
|
|
10
60
|
}
|
|
11
|
-
throw new Error(`invalid methodName ${Object.keys(services)} |${String(methodName)}`);
|
|
12
|
-
} catch (e) {
|
|
13
|
-
console.debug("failed", e);
|
|
14
|
-
sender.postMessage({ eventId, methodName, error: e });
|
|
15
61
|
}
|
|
16
|
-
}
|
|
62
|
+
})
|
|
17
63
|
);
|
|
18
64
|
var bufToJson = (buf) => JSON.parse(new TextDecoder("UTF-8").decode(new Uint8Array(buf)));
|
|
65
|
+
var combineHandlers = (...handlers) => {
|
|
66
|
+
return ({ data: { methodName, ...data } = {}, ports }) => {
|
|
67
|
+
for (const h of handlers) {
|
|
68
|
+
if (h.canHandle(String(methodName))) {
|
|
69
|
+
return h.handle({ data: { methodName, ...data }, ports });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
console.error("no handlers matched", methodName);
|
|
73
|
+
};
|
|
74
|
+
};
|
|
19
75
|
|
|
20
76
|
// src/worker/wwApi.ts
|
|
21
77
|
var STATE = {
|
|
@@ -734,6 +790,9 @@ var loadZip = async (buf, bookId) => {
|
|
|
734
790
|
const unzipper = new Unzip();
|
|
735
791
|
unzipper.register(UnzipInflate);
|
|
736
792
|
unzipper.onfile = (file) => {
|
|
793
|
+
if (!file.name.includes(".")) {
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
737
796
|
m.set(file.name, {
|
|
738
797
|
decoded: null,
|
|
739
798
|
zipEntry: {
|
|
@@ -771,10 +830,18 @@ var loadZip = async (buf, bookId) => {
|
|
|
771
830
|
|
|
772
831
|
// src/worker/offline-worker.ts
|
|
773
832
|
var CHECK_UPDATES = true;
|
|
774
|
-
var
|
|
775
|
-
|
|
833
|
+
var NATIVE = false;
|
|
834
|
+
var LOADED_BOOKS = /* @__PURE__ */ new Set();
|
|
835
|
+
var fetchZipFile = async (zipUrl, { forceRefresh } = {}) => {
|
|
776
836
|
const fileName = zipUrl.split("/").slice(-1)[0];
|
|
777
837
|
const readArrayBuffer = async () => {
|
|
838
|
+
if (NATIVE) {
|
|
839
|
+
console.debug("try reading native", fileName);
|
|
840
|
+
const back = await sender.nativeReadFile({ fname: fileName });
|
|
841
|
+
console.debug("done readnig");
|
|
842
|
+
return back;
|
|
843
|
+
}
|
|
844
|
+
const opfsRoot = await navigator.storage.getDirectory();
|
|
778
845
|
const handle = await opfsRoot.getFileHandle(fileName);
|
|
779
846
|
const accessHandle = await handle.createSyncAccessHandle();
|
|
780
847
|
const size = accessHandle.getSize();
|
|
@@ -800,7 +867,7 @@ var fetchZipFile = async (zipUrl, forceRefresh) => {
|
|
|
800
867
|
}
|
|
801
868
|
return buf;
|
|
802
869
|
} catch (e) {
|
|
803
|
-
if (e.message !== "forceRefresh" && !e.message.includes("refetching")) {
|
|
870
|
+
if (e instanceof Error && e.message !== "forceRefresh" && !e.message.includes("refetching")) {
|
|
804
871
|
console.debug("opfs db not found, creating it", e, zipUrl);
|
|
805
872
|
}
|
|
806
873
|
const response = await fetch(zipUrl);
|
|
@@ -826,6 +893,11 @@ var fetchZipFile = async (zipUrl, forceRefresh) => {
|
|
|
826
893
|
console.debug(error);
|
|
827
894
|
throw new Error(error);
|
|
828
895
|
}
|
|
896
|
+
if (NATIVE) {
|
|
897
|
+
await sender.nativeWriteFile({ fname: fileName, buffer: arrayBuffer });
|
|
898
|
+
return await readArrayBuffer();
|
|
899
|
+
}
|
|
900
|
+
const opfsRoot = await navigator.storage.getDirectory();
|
|
829
901
|
const handle = await opfsRoot.getFileHandle(fileName, { create: true });
|
|
830
902
|
const accessHandle = await handle.createSyncAccessHandle();
|
|
831
903
|
await accessHandle.truncate(0);
|
|
@@ -843,7 +915,12 @@ var slugToFileMeta2 = async ({ slug }) => {
|
|
|
843
915
|
var PRELOAD_AS_BOOK_ID = "preload";
|
|
844
916
|
var isOldZip = (bookId) => typeof bookId === "number";
|
|
845
917
|
var loadBook2 = async ({ id: bookId, forceRefresh }) => {
|
|
846
|
-
|
|
918
|
+
if (LOADED_BOOKS.has(bookId)) {
|
|
919
|
+
self.postMessage({ methodName: "opfsProgress", arg: { total: 1, bytes: 1 } });
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
922
|
+
LOADED_BOOKS.add(bookId);
|
|
923
|
+
const buf = await fetchZipFile(`https://ci.lls.fr/artefacts/content/development/${bookId}.zip`, { forceRefresh });
|
|
847
924
|
try {
|
|
848
925
|
const entryNames = await loadZip(new Uint8Array(buf), bookId);
|
|
849
926
|
fetchWorker.postMessage({ methodName: "setKnownLinks", arg: { entryNames, bookId } });
|
|
@@ -875,7 +952,7 @@ var loadPageContent2 = async ({
|
|
|
875
952
|
var fetchWorker;
|
|
876
953
|
var initChannel = (__, { ports }) => {
|
|
877
954
|
fetchWorker = ports[0];
|
|
878
|
-
const
|
|
955
|
+
const { canHandle, handle } = makeSyncHandler(fetchWorker, {
|
|
879
956
|
readZipEntry,
|
|
880
957
|
loadBook: loadBook2,
|
|
881
958
|
slugToFileMeta: slugToFileMeta2,
|
|
@@ -887,23 +964,47 @@ var initChannel = (__, { ports }) => {
|
|
|
887
964
|
self.postMessage({ methodName: "ready" });
|
|
888
965
|
return;
|
|
889
966
|
}
|
|
890
|
-
|
|
967
|
+
if (canHandle(dataObj.data?.methodName || "")) {
|
|
968
|
+
return handle(dataObj);
|
|
969
|
+
}
|
|
970
|
+
console.error("unknown methodName", dataObj.data?.methodName);
|
|
891
971
|
};
|
|
892
972
|
fetchWorker.onmessage = fn;
|
|
893
973
|
};
|
|
894
|
-
var loadBooks = async () => {
|
|
895
|
-
|
|
896
|
-
|
|
974
|
+
var loadBooks = async ({ primaryOnly = false } = {}) => {
|
|
975
|
+
let entries = [];
|
|
976
|
+
if (NATIVE) {
|
|
977
|
+
entries = await sender.nativeListZips();
|
|
978
|
+
} else {
|
|
979
|
+
const opfsRoot = await navigator.storage.getDirectory();
|
|
980
|
+
entries = await opfsRoot.values();
|
|
981
|
+
}
|
|
897
982
|
for await (const entry of entries) {
|
|
983
|
+
if (/preload/.test(entry.name)) {
|
|
984
|
+
continue;
|
|
985
|
+
}
|
|
898
986
|
if (/\d+\.zip$/.test(entry.name)) {
|
|
899
|
-
|
|
900
|
-
|
|
987
|
+
if (!primaryOnly) {
|
|
988
|
+
const bookId = entry.name.match(/\d+/)[0];
|
|
989
|
+
await loadBook2({ id: Number.parseInt(bookId, 10) });
|
|
990
|
+
}
|
|
901
991
|
} else if (/zip$/.test(entry.name)) {
|
|
902
992
|
const methodUri = entry.name.replace(".zip", "");
|
|
903
993
|
await loadBook2({ id: methodUri });
|
|
994
|
+
} else {
|
|
995
|
+
console.info(`invalid book entry ${entry.name}`);
|
|
904
996
|
}
|
|
905
997
|
}
|
|
906
998
|
};
|
|
999
|
+
var configure = ({ native, checkUpdates }) => {
|
|
1000
|
+
console.info("configuring!!", native, checkUpdates);
|
|
1001
|
+
if (typeof native !== "undefined") {
|
|
1002
|
+
NATIVE = !!native;
|
|
1003
|
+
}
|
|
1004
|
+
if (typeof native !== "undefined") {
|
|
1005
|
+
CHECK_UPDATES = !!checkUpdates;
|
|
1006
|
+
}
|
|
1007
|
+
};
|
|
907
1008
|
var loadPreload2 = async () => {
|
|
908
1009
|
const zipUrl = "https://lls-ci-fr.s3.eu-west-3.amazonaws.com/artefacts/content/development/preload.zip";
|
|
909
1010
|
const buf = await fetchZipFile(zipUrl);
|
|
@@ -916,10 +1017,13 @@ var loadPreload2 = async () => {
|
|
|
916
1017
|
console.error("failed", e);
|
|
917
1018
|
}
|
|
918
1019
|
};
|
|
919
|
-
|
|
1020
|
+
var mainHandle = makeSyncHandler(self, {
|
|
920
1021
|
initChannel,
|
|
921
1022
|
loadPreload: loadPreload2,
|
|
922
1023
|
readZipEntry,
|
|
923
1024
|
loadBooks,
|
|
924
|
-
loadBook: loadBook2
|
|
1025
|
+
loadBook: loadBook2,
|
|
1026
|
+
configure
|
|
925
1027
|
});
|
|
1028
|
+
var { handler, ...sender } = makeSyncWorker(self, ["nativeWriteFile", "nativeReadFile", "nativeListZips"]);
|
|
1029
|
+
self.onmessage = combineHandlers(mainHandle, handler);
|
package/lib/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// src/utils/worker.ts
|
|
2
|
-
var makeSyncWorker = (
|
|
2
|
+
var makeSyncWorker = (offlineWorker2, methodNames, dbg) => {
|
|
3
3
|
const dic = {};
|
|
4
4
|
const cbks = {};
|
|
5
|
-
const
|
|
5
|
+
const fn = ({ data: { eventId, methodName, results, error, arg } = {} } = {}) => {
|
|
6
6
|
if (eventId && eventId in dic) {
|
|
7
7
|
if (error) {
|
|
8
8
|
dic[eventId].reject(error);
|
|
@@ -11,51 +11,74 @@ var makeSyncWorker = (offlineWorker, methodNames, dbg) => {
|
|
|
11
11
|
}
|
|
12
12
|
} else {
|
|
13
13
|
if (methodName && !methodName.startsWith("async") && !(methodName in cbks)) {
|
|
14
|
-
console.error(`syncWorker: ${dbg}`, eventId, methodName, error);
|
|
14
|
+
console.error(`syncWorker: unknown methodName cbk ${dbg}`, eventId, methodName, error);
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
methodName && cbks[methodName]?.(arg);
|
|
18
18
|
};
|
|
19
|
-
offlineWorker.onmessage = fn2;
|
|
20
19
|
const makeFn = (methodName) => {
|
|
21
20
|
return ({ ports, ...arg } = {}) => {
|
|
22
21
|
return new Promise((resolve, reject) => {
|
|
23
22
|
const eventId = `${methodName}:${Date.now()}`;
|
|
24
23
|
dic[eventId] = { resolve, reject };
|
|
25
|
-
|
|
24
|
+
offlineWorker2.postMessage({ eventId, methodName, arg }, ports);
|
|
26
25
|
});
|
|
27
26
|
};
|
|
28
27
|
};
|
|
29
28
|
const obj = Object.assign(Object.fromEntries(methodNames.map((name) => [name, makeFn(name)])), {
|
|
30
|
-
on: (key,
|
|
31
|
-
cbks[key] =
|
|
29
|
+
on: (key, fn2) => {
|
|
30
|
+
cbks[key] = fn2;
|
|
32
31
|
}
|
|
33
32
|
});
|
|
34
|
-
return
|
|
33
|
+
return {
|
|
34
|
+
...obj,
|
|
35
|
+
handler: {
|
|
36
|
+
canHandle: (methodName) => {
|
|
37
|
+
return methodName in cbks || methodNames.includes(methodName);
|
|
38
|
+
},
|
|
39
|
+
handle: fn
|
|
40
|
+
}
|
|
41
|
+
};
|
|
35
42
|
};
|
|
36
43
|
var a = (a2) => a2;
|
|
37
44
|
var makeSyncHandler = a(
|
|
38
|
-
(sender, services) =>
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
45
|
+
(sender, services) => ({
|
|
46
|
+
canHandle: (methodName) => {
|
|
47
|
+
return methodName in services;
|
|
48
|
+
},
|
|
49
|
+
handle: async ({ data: { eventId, methodName, arg } = {}, ports }) => {
|
|
50
|
+
try {
|
|
51
|
+
if (typeof methodName === "string" && methodName in services && services[methodName]) {
|
|
52
|
+
const results = await services[methodName](arg, { ports });
|
|
53
|
+
sender.postMessage({ eventId, methodName, results });
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
throw new Error(`invalid methodName ${Object.keys(services)} |${String(methodName)}`);
|
|
57
|
+
} catch (e) {
|
|
58
|
+
console.debug("failed", e);
|
|
59
|
+
sender.postMessage({ eventId, methodName, error: e });
|
|
44
60
|
}
|
|
45
|
-
throw new Error(`invalid methodName ${Object.keys(services)} |${String(methodName)}`);
|
|
46
|
-
} catch (e) {
|
|
47
|
-
console.debug("failed", e);
|
|
48
|
-
sender.postMessage({ eventId, methodName, error: e });
|
|
49
61
|
}
|
|
50
|
-
}
|
|
62
|
+
})
|
|
51
63
|
);
|
|
64
|
+
var combineHandlers = (...handlers) => {
|
|
65
|
+
return ({ data: { methodName, ...data } = {}, ports }) => {
|
|
66
|
+
for (const h of handlers) {
|
|
67
|
+
if (h.canHandle(String(methodName))) {
|
|
68
|
+
return h.handle({ data: { methodName, ...data }, ports });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
console.error("no handlers matched", methodName);
|
|
72
|
+
};
|
|
73
|
+
};
|
|
52
74
|
|
|
53
75
|
// src/hooks/useOfflineWorker.ts
|
|
54
76
|
import { useCallback, useEffect, useState } from "react";
|
|
55
|
-
var
|
|
77
|
+
var offlineWorker = new Worker("/src/worker/offline-worker.js", { type: "module" });
|
|
78
|
+
var { handler, ...offlineWorkerSync } = makeSyncWorker(
|
|
56
79
|
// @ts-ignore: TODO
|
|
57
|
-
|
|
58
|
-
["initChannel", "readZipEntry", "loadPreload", "loadBooks", "loadBook"],
|
|
80
|
+
offlineWorker,
|
|
81
|
+
["initChannel", "readZipEntry", "configure", "loadPreload", "loadBooks", "loadBook"],
|
|
59
82
|
"app:offlineWorker"
|
|
60
83
|
);
|
|
61
84
|
var setWorkersReady;
|
|
@@ -66,7 +89,13 @@ var setBooksLoaded;
|
|
|
66
89
|
var setBooksLoadedPromise = new Promise((resolve) => {
|
|
67
90
|
setBooksLoaded = resolve;
|
|
68
91
|
});
|
|
69
|
-
var
|
|
92
|
+
var installWorker = async ({
|
|
93
|
+
primaryOnly = false,
|
|
94
|
+
nativeReadFile,
|
|
95
|
+
nativeWriteFile,
|
|
96
|
+
nativeListZips,
|
|
97
|
+
checkUpdates
|
|
98
|
+
} = {}) => {
|
|
70
99
|
let fetchWorker = null;
|
|
71
100
|
await navigator.serviceWorker.getRegistrations().then(async (registrations) => {
|
|
72
101
|
for (const registration of registrations) {
|
|
@@ -82,30 +111,49 @@ var fn = async () => {
|
|
|
82
111
|
console.debug("failed to get fetch worker");
|
|
83
112
|
return;
|
|
84
113
|
}
|
|
114
|
+
if (nativeReadFile) {
|
|
115
|
+
const wwHandler = makeSyncHandler(offlineWorker, { nativeReadFile, nativeWriteFile, nativeListZips });
|
|
116
|
+
offlineWorker.onmessage = combineHandlers(handler, wwHandler);
|
|
117
|
+
offlineWorkerSync.configure({ native: true, checkUpdates });
|
|
118
|
+
} else {
|
|
119
|
+
offlineWorkerSync.configure({ native: false, checkUpdates });
|
|
120
|
+
offlineWorker.onmessage = handler.handle;
|
|
121
|
+
}
|
|
85
122
|
offlineWorkerSync.on("ready", setWorkersReady);
|
|
86
123
|
const channel = new MessageChannel();
|
|
87
124
|
offlineWorkerSync.initChannel({ ports: [channel.port1] });
|
|
88
125
|
fetchWorker.postMessage({ methodName: "initChannel" }, [channel.port2]);
|
|
89
126
|
offlineWorkerSync.on("opfsProgress", () => {
|
|
90
127
|
});
|
|
91
|
-
|
|
128
|
+
if (!primaryOnly) {
|
|
129
|
+
await offlineWorkerSync.loadPreload();
|
|
130
|
+
}
|
|
92
131
|
await offlineWorkerSync.loadBooks();
|
|
93
132
|
setBooksLoaded();
|
|
94
133
|
};
|
|
95
|
-
|
|
96
|
-
|
|
134
|
+
var useOfflineWorker_default = ({
|
|
135
|
+
primaryOnly = false,
|
|
136
|
+
nativeReadFile,
|
|
137
|
+
nativeWriteFile,
|
|
138
|
+
nativeListZips,
|
|
139
|
+
checkUpdates
|
|
140
|
+
} = {}) => {
|
|
97
141
|
const [ready, setReady] = useState(false);
|
|
98
142
|
useEffect(() => {
|
|
99
|
-
const
|
|
143
|
+
const fn = async () => {
|
|
144
|
+
await installWorker({ primaryOnly, nativeReadFile, nativeWriteFile, nativeListZips, checkUpdates });
|
|
100
145
|
await Promise.all([workersReadyPromise, setBooksLoadedPromise]);
|
|
101
146
|
setReady(true);
|
|
102
147
|
};
|
|
103
|
-
|
|
104
|
-
}, []);
|
|
105
|
-
const loadBook = useCallback(
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
148
|
+
fn();
|
|
149
|
+
}, [primaryOnly, nativeReadFile, nativeWriteFile, nativeListZips, checkUpdates]);
|
|
150
|
+
const loadBook = useCallback(
|
|
151
|
+
async ({ id, forceRefresh }, cbk) => {
|
|
152
|
+
offlineWorkerSync.on("opfsProgress", cbk);
|
|
153
|
+
return await offlineWorkerSync.loadBook({ id, forceRefresh });
|
|
154
|
+
},
|
|
155
|
+
[]
|
|
156
|
+
);
|
|
109
157
|
return {
|
|
110
158
|
ready,
|
|
111
159
|
loadBook
|
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-eaf69c80",
|
|
4
4
|
"description": "offline",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"module": "./lib/index.js",
|
|
@@ -36,10 +36,12 @@
|
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@biomejs/biome": "1.9.4",
|
|
38
38
|
"@happy-dom/global-registrator": "15.11.0",
|
|
39
|
+
"@ladle/react": "5.0.3",
|
|
39
40
|
"@testing-library/react": "16.3.0",
|
|
40
41
|
"@types/react": "18.3.12",
|
|
41
42
|
"@types/react-dom": "18.3.1",
|
|
42
43
|
"@vitejs/plugin-react": "4.5.1",
|
|
44
|
+
"@vitejs/plugin-react-swc": "3.10.1",
|
|
43
45
|
"esbuild": "0.24.0",
|
|
44
46
|
"happy-dom": "15.11.0",
|
|
45
47
|
"lodash": "4.17.21",
|
|
@@ -48,17 +50,21 @@
|
|
|
48
50
|
"react-dom": "18.3.1",
|
|
49
51
|
"typescript": "5.8.3",
|
|
50
52
|
"vite": "7.0.0",
|
|
53
|
+
"vite-tsconfig-paths": "5.1.4",
|
|
51
54
|
"zod": "3.25.50",
|
|
52
|
-
"@lls/vitescripts": "24.22.0"
|
|
55
|
+
"@lls/vitescripts": "24.22.0-eaf69c80"
|
|
53
56
|
},
|
|
54
57
|
"dependencies": {
|
|
55
58
|
"fflate": "0.8.2"
|
|
56
59
|
},
|
|
57
60
|
"scripts": {
|
|
58
|
-
"start": "
|
|
61
|
+
"start": "pnpm ladle serve",
|
|
59
62
|
"dts": "pnpm tsc --project tsconfig.production.json",
|
|
60
|
-
"build": "node build",
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
+
"build": "NODE_ENV=production node build.js",
|
|
64
|
+
"deploy-ladle": "PUBLISH=1 pnpm ladle build",
|
|
65
|
+
"deploy-ladle-pr": "pnpm ladle build && s5cmd sync --delete --acl public-read --destination-region eu-west-1 'dist/*' s3://build.lelivrescolaire.fr/storybook/viewer-pr-$PR_NUMBER/",
|
|
66
|
+
"test": "bun test --bail __tests__/unit __tests__/e2e",
|
|
67
|
+
"lint": "pnpm biome check --apply src __tests__ stories",
|
|
68
|
+
"precommit": "pnpm lint"
|
|
63
69
|
}
|
|
64
70
|
}
|