@lls/offline 24.20.0-debug2 → 24.22.0-34f32711

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.
@@ -11,7 +11,7 @@ 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);
@@ -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-ignore TODO: handle variables from body(stream) properly!!
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
- return ev.respondWith(fetchAsset(ev, { entryId, mimeType, offlineWorkerSync }));
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", (_event) => {
310
- return swSelf.clients.claim();
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 setKnownLinks = ({ entryNames, bookId }) => {
329
- entryNames.forEach((entryName) => {
330
- const link = entryName.replace(/^\d+\/media\//, "");
331
- knownLinks.set(link, { entryName, bookId });
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 = {};
@@ -11,7 +22,7 @@ var makeSyncWorker = (offlineWorker, methodNames, dbg) => {
11
22
  }
12
23
  } else {
13
24
  if (methodName && !methodName.startsWith("async") && !(methodName in cbks)) {
14
- console.error(`syncWorker: ${dbg}`, eventId, methodName, error);
25
+ console.error(`syncWorker: unknown methodName cbk ${dbg}`, eventId, methodName, error);
15
26
  }
16
27
  }
17
28
  methodName && cbks[methodName]?.(arg);
@@ -63,15 +74,16 @@ var makeSyncHandler = a(
63
74
  );
64
75
  var bufToJson = (buf) => JSON.parse(new TextDecoder("UTF-8").decode(new Uint8Array(buf)));
65
76
  var combineHandlers = (...handlers) => {
66
- return ({ data: { methodName, ...data }, ports }) => {
77
+ return ({ data: { methodName, ...data } = {}, ports }) => {
67
78
  for (const h of handlers) {
68
- if (h.canHandle(methodName)) {
79
+ if (h.canHandle(String(methodName))) {
69
80
  return h.handle({ data: { methodName, ...data }, ports });
70
81
  }
71
82
  }
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 NATIVE = false;
834
- var LOADED_BOOKS = /* @__PURE__ */ new Set();
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 (NATIVE) {
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();
@@ -867,8 +886,8 @@ var fetchZipFile = async (zipUrl, { forceRefresh } = {}) => {
867
886
  }
868
887
  return buf;
869
888
  } catch (e) {
870
- if (e.message !== "forceRefresh" && !e.message.includes("refetching")) {
871
- console.debug("opfs db not found, creating it", e, zipUrl);
889
+ if (e instanceof Error && e.message !== "forceRefresh" && !e.message.includes("refetching")) {
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 (NATIVE) {
916
+ if (STORAGE === "native") {
897
917
  await sender.nativeWriteFile({ fname: fileName, buffer: arrayBuffer });
898
- return await readArrayBuffer();
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
- 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
- }
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,
@@ -964,28 +1009,35 @@ var initChannel = (__, { ports }) => {
964
1009
  self.postMessage({ methodName: "ready" });
965
1010
  return;
966
1011
  }
967
- if (canHandle(dataObj.data?.methodName)) {
1012
+ if (canHandle(dataObj.data?.methodName || "")) {
968
1013
  return handle(dataObj);
969
1014
  }
970
1015
  console.error("unknown methodName", dataObj.data?.methodName);
971
1016
  };
972
1017
  fetchWorker.onmessage = fn;
973
1018
  };
974
- var loadBooks = async () => {
1019
+ var loadBooks = async ({ primaryOnly = false } = {}) => {
975
1020
  let entries = [];
976
- if (NATIVE) {
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)) {
984
1034
  continue;
985
1035
  }
986
1036
  if (/\d+\.zip$/.test(entry.name)) {
987
- const bookId = entry.name.match(/\d+/)[0];
988
- await loadBook2({ id: Number.parseInt(bookId, 10) });
1037
+ if (!primaryOnly) {
1038
+ const bookId = entry.name.match(/\d+/)[0];
1039
+ await loadBook2({ id: Number.parseInt(bookId, 10) });
1040
+ }
989
1041
  } else if (/zip$/.test(entry.name)) {
990
1042
  const methodUri = entry.name.replace(".zip", "");
991
1043
  await loadBook2({ id: methodUri });
@@ -994,14 +1046,24 @@ var loadBooks = async () => {
994
1046
  }
995
1047
  }
996
1048
  };
997
- var configure = ({ native, checkUpdates }) => {
998
- console.info("configuring!!", native, checkUpdates);
999
- if (typeof native !== "undefined") {
1000
- NATIVE = !!native;
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;
1001
1059
  }
1002
- if (typeof native !== "undefined") {
1060
+ if (typeof checkUpdates !== "undefined") {
1003
1061
  CHECK_UPDATES = !!checkUpdates;
1004
1062
  }
1063
+ if (typeof zipBaseUrl !== "undefined") {
1064
+ ZIP_BASE_URL = zipBaseUrl;
1065
+ }
1066
+ console.info("ow::configure", { STORAGE, CHECK_UPDATES, ZIP_BASE_URL });
1005
1067
  };
1006
1068
  var loadPreload2 = async () => {
1007
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 = {};
@@ -11,7 +22,7 @@ var makeSyncWorker = (offlineWorker2, methodNames, dbg) => {
11
22
  }
12
23
  } else {
13
24
  if (methodName && !methodName.startsWith("async") && !(methodName in cbks)) {
14
- console.error(`syncWorker: ${dbg}`, eventId, methodName, error);
25
+ console.error(`syncWorker: unknown methodName cbk ${dbg}`, eventId, methodName, error);
15
26
  }
16
27
  }
17
28
  methodName && cbks[methodName]?.(arg);
@@ -62,9 +73,9 @@ var makeSyncHandler = a(
62
73
  })
63
74
  );
64
75
  var combineHandlers = (...handlers) => {
65
- return ({ data: { methodName, ...data }, ports }) => {
76
+ return ({ data: { methodName, ...data } = {}, ports }) => {
66
77
  for (const h of handlers) {
67
- if (h.canHandle(methodName)) {
78
+ if (h.canHandle(String(methodName))) {
68
79
  return h.handle({ data: { methodName, ...data }, ports });
69
80
  }
70
81
  }
@@ -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,61 +118,77 @@ var setBooksLoadedPromise = new Promise((resolve) => {
90
118
  setBooksLoaded = resolve;
91
119
  });
92
120
  var installWorker = async ({
93
- skipPreload = false,
121
+ skipLoadBooks = false,
122
+ primaryOnly = false,
94
123
  nativeReadFile,
95
124
  nativeWriteFile,
96
125
  nativeListZips,
126
+ storage,
127
+ zipBaseUrl,
97
128
  checkUpdates
98
129
  } = {}) => {
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
- }
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
- offlineWorkerSync.configure({ native: true, checkUpdates });
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({ 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
- if (!skipPreload) {
150
+ if (!primaryOnly) {
129
151
  await offlineWorkerSync.loadPreload();
130
152
  }
131
- await offlineWorkerSync.loadBooks();
153
+ if (!skipLoadBooks) {
154
+ await offlineWorkerSync.loadBooks({ primaryOnly });
155
+ }
132
156
  setBooksLoaded();
133
157
  };
134
- var useOfflineWorker_default = ({ skipPreload = false, nativeReadFile, nativeWriteFile, nativeListZips, checkUpdates } = {}) => {
158
+ var useOfflineWorker_default = ({
159
+ primaryOnly = false,
160
+ nativeReadFile,
161
+ nativeWriteFile,
162
+ nativeListZips,
163
+ checkUpdates,
164
+ storage,
165
+ zipBaseUrl
166
+ } = {}) => {
135
167
  const [ready, setReady] = useState(false);
136
168
  useEffect(() => {
137
169
  const fn = async () => {
138
- await installWorker({ skipPreload, nativeReadFile, nativeWriteFile, nativeListZips, checkUpdates });
170
+ await installWorker({
171
+ primaryOnly,
172
+ nativeReadFile,
173
+ nativeWriteFile,
174
+ nativeListZips,
175
+ storage,
176
+ zipBaseUrl,
177
+ checkUpdates
178
+ });
139
179
  await Promise.all([workersReadyPromise, setBooksLoadedPromise]);
180
+ fetch(window.location.href.replace(window.location.search, ""));
140
181
  setReady(true);
141
182
  };
142
183
  fn();
143
- }, [skipPreload, nativeReadFile, nativeWriteFile, nativeListZips, checkUpdates]);
144
- const loadBook = useCallback(async ({ id, forceRefresh }, cbk) => {
145
- offlineWorkerSync.on("opfsProgress", cbk);
146
- return await offlineWorkerSync.loadBook({ id, forceRefresh });
147
- }, []);
184
+ }, [primaryOnly, nativeReadFile, nativeWriteFile, nativeListZips, storage, zipBaseUrl, checkUpdates]);
185
+ const loadBook = useCallback(
186
+ async ({ id, forceRefresh }, cbk) => {
187
+ offlineWorkerSync.on("opfsProgress", cbk);
188
+ return await offlineWorkerSync.loadBook({ id, forceRefresh });
189
+ },
190
+ []
191
+ );
148
192
  return {
149
193
  ready,
150
194
  loadBook
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lls/offline",
3
- "version": "24.20.0-debug2",
3
+ "version": "24.22.0-34f32711",
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-34f32711"
56
56
  },
57
57
  "dependencies": {
58
58
  "fflate": "0.8.2"