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