@lls/offline 24.22.0-a4074e64 → 24.22.0-b0b2683d

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.
@@ -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 () => caches.open(`LLS_OFFLINE_${process.env.CONF_ENV}`);
66
65
 
67
66
  // src/worker/swFetchScreenCall.ts
68
67
  var zipSlugName = (str) => str.replace(/[^a-zA-Z0-9-.]/g, "");
@@ -197,7 +196,7 @@ var canHandleScreenCall = (url) => new RegExp(Object.keys(handles).join("|")).te
197
196
  var handleScreenCall = async (ev, { offlineWorkerSync: offlineWorkerSync2, knownLinks: knownLinks2 }) => {
198
197
  try {
199
198
  const variables = (
200
- // @ts-expect-error TODO: handle variables from body(stream) properly!!
199
+ // @ts-ignore TODO: handle variables from body(stream) properly!!
201
200
  ev.request.body?.variables || JSON.parse(new URLSearchParams(new URL(ev.request.url).search).get("variables") || "{}")
202
201
  );
203
202
  console.debug("variables are", variables, "vs", ev.request.body);
@@ -212,12 +211,6 @@ var handleScreenCall = async (ev, { offlineWorkerSync: offlineWorkerSync2, known
212
211
  return { status: 500, json: JSON.stringify(e) };
213
212
  }
214
213
  };
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
- };
221
214
 
222
215
  // src/worker/fetch-worker.ts
223
216
  var fetchAsset = async (ev, { entryId, mimeType, offlineWorkerSync: offlineWorkerSync2 }) => {
@@ -285,70 +278,36 @@ var ACCEPTED_EXTENSIONS = {
285
278
  ".m4a": "audio/mp4",
286
279
  ".webp": "image/webp"
287
280
  };
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";
319
281
  var swSelf = self;
320
282
  swSelf.addEventListener("fetch", (ev) => {
321
283
  const url = ev.request.url;
322
284
  const extension = url.match(/\.[^.]+$/)?.[0];
323
285
  const mimeType = extension && extension in ACCEPTED_EXTENSIONS ? ACCEPTED_EXTENSIONS[extension] : "";
324
286
  const isValidScreenCall = canHandleScreenCall(url);
325
- if (STORAGE !== "cache" && url.endsWith(".zip")) {
326
- return;
327
- }
328
287
  if (!mimeType && !isValidScreenCall) {
329
288
  if (!/\.(css|tsx?|jsx?|woff2|fr|manifest)(\??|$)|@(vite|react|id)/.test(url)) {
330
289
  console.debug("no ext", extension || url);
331
290
  }
332
- return ev.respondWith(onlineFirst(ev.request, ev));
291
+ return;
333
292
  }
334
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
+ }
335
300
  if (isValidScreenCall) {
336
301
  console.debug("screencall!");
337
302
  return ev.respondWith(fetchScreenCall(ev, { offlineWorkerSync, knownLinks }));
338
303
  }
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;
304
+ return ev.respondWith(fetchAsset(ev, { entryId, mimeType, offlineWorkerSync }));
346
305
  });
347
306
  swSelf.addEventListener("install", (_event) => {
348
307
  swSelf.skipWaiting();
349
308
  });
350
- swSelf.addEventListener("activate", (event) => {
351
- event.waitUntil(swSelf.clients.claim());
309
+ swSelf.addEventListener("activate", (_event) => {
310
+ return swSelf.clients.claim();
352
311
  });
353
312
  var offlineWorker;
354
313
  var offlineWorkerSync;
@@ -362,30 +321,24 @@ var initChannel = async (__, { ports }) => {
362
321
  );
363
322
  offlineWorkerSync = sender;
364
323
  offlineWorker.onmessage = handler.handle;
365
- offlineWorkerSync.on("setKnownLinks", setKnownLinks.bind(null, setKnownLinks));
324
+ offlineWorkerSync.on("setKnownLinks", setKnownLinks);
366
325
  offlineWorker.postMessage({ methodName: "sendAppReady" });
367
326
  };
368
327
  var knownLinks = /* @__PURE__ */ new Map();
369
- var configure = ({ storage } = {}) => {
370
- STORAGE = "cache";
371
- if (typeof storage !== "undefined") {
372
- STORAGE = storage;
373
- }
374
- console.info("sw::configure", { STORAGE });
328
+ var setKnownLinks = ({ entryNames, bookId }) => {
329
+ entryNames.forEach((entryName) => {
330
+ const link = entryName.replace(/^\d+\/media\//, "");
331
+ knownLinks.set(link, { entryName, bookId });
332
+ });
375
333
  };
376
334
  swSelf.onmessage = async ({
377
335
  data: { methodName, arg } = {},
378
336
  ports
379
337
  }) => {
380
338
  const services = {
381
- initChannel,
382
- configure
339
+ initChannel
383
340
  };
384
341
  try {
385
- if (methodName === "configure") {
386
- await services[methodName](arg);
387
- return;
388
- }
389
342
  if (methodName === "initChannel") {
390
343
  if (!ports.length) {
391
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 = {};
@@ -83,7 +72,6 @@ var combineHandlers = (...handlers) => {
83
72
  console.error("no handlers matched", methodName);
84
73
  };
85
74
  };
86
- var openCache = async () => caches.open(`LLS_OFFLINE_${process.env.CONF_ENV}`);
87
75
 
88
76
  // src/worker/wwApi.ts
89
77
  var STATE = {
@@ -842,24 +830,17 @@ var loadZip = async (buf, bookId) => {
842
830
 
843
831
  // src/worker/offline-worker.ts
844
832
  var CHECK_UPDATES = true;
845
- var STORAGE = "cache";
846
- var ZIP_BASE_URL = "https://ci.lls.fr/artefacts/content/development";
847
- var LOADED_BOOKS = /* @__PURE__ */ new Map();
833
+ var NATIVE = false;
834
+ var LOADED_BOOKS = /* @__PURE__ */ new Set();
848
835
  var fetchZipFile = async (zipUrl, { forceRefresh } = {}) => {
849
836
  const fileName = zipUrl.split("/").slice(-1)[0];
850
837
  const readArrayBuffer = async () => {
851
- if (STORAGE === "native") {
838
+ if (NATIVE) {
839
+ console.debug("try reading native", fileName);
852
840
  const back = await sender.nativeReadFile({ fname: fileName });
841
+ console.debug("done readnig");
853
842
  return back;
854
843
  }
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
- }
863
844
  const opfsRoot = await navigator.storage.getDirectory();
864
845
  const handle = await opfsRoot.getFileHandle(fileName);
865
846
  const accessHandle = await handle.createSyncAccessHandle();
@@ -887,7 +868,7 @@ var fetchZipFile = async (zipUrl, { forceRefresh } = {}) => {
887
868
  return buf;
888
869
  } catch (e) {
889
870
  if (e instanceof Error && e.message !== "forceRefresh" && !e.message.includes("refetching")) {
890
- console.debug(`${STORAGE} zip not found, creating it`, e, zipUrl);
871
+ console.debug("opfs db not found, creating it", e, zipUrl);
891
872
  }
892
873
  const response = await fetch(zipUrl);
893
874
  const contentLength = +response.headers.get("Content-Length");
@@ -898,7 +879,6 @@ var fetchZipFile = async (zipUrl, { forceRefresh } = {}) => {
898
879
  while (true) {
899
880
  const { done, value: chunk } = await reader.read();
900
881
  if (done) {
901
- self.postMessage({ methodName: "opfsProgress", arg: { total: contentLength, bytes: contentLength } });
902
882
  break;
903
883
  }
904
884
  arrayBuffer.set(chunk, position);
@@ -913,69 +893,44 @@ var fetchZipFile = async (zipUrl, { forceRefresh } = {}) => {
913
893
  console.debug(error);
914
894
  throw new Error(error);
915
895
  }
916
- if (STORAGE === "native") {
896
+ if (NATIVE) {
917
897
  await sender.nativeWriteFile({ fname: fileName, buffer: arrayBuffer });
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);
898
+ return await readArrayBuffer();
940
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();
941
906
  return await readArrayBuffer();
942
907
  }
943
908
  };
944
909
  var slugToFileMeta2 = async ({ slug }) => {
910
+ console.debug("hereshit");
945
911
  const json = await readZipEntry({ bookId: "preload", entryName: "preload/hashmap_slugToMetaPage.json", asJson: true });
912
+ console.debug("hereshit2");
946
913
  return slugToFileMeta({ slug, json });
947
914
  };
948
915
  var PRELOAD_AS_BOOK_ID = "preload";
949
916
  var isOldZip = (bookId) => typeof bookId === "number";
950
917
  var loadBook2 = async ({ id: bookId, forceRefresh }) => {
951
918
  if (LOADED_BOOKS.has(bookId)) {
952
- await LOADED_BOOKS.get(bookId);
953
919
  self.postMessage({ methodName: "opfsProgress", arg: { total: 1, bytes: 1 } });
954
920
  return;
955
921
  }
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;
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
+ }
979
934
  };
980
935
  var loadPageContent2 = async ({
981
936
  bookId: iBookId,
@@ -1018,16 +973,11 @@ var initChannel = (__, { ports }) => {
1018
973
  };
1019
974
  var loadBooks = async ({ primaryOnly = false } = {}) => {
1020
975
  let entries = [];
1021
- if (STORAGE === "native") {
976
+ if (NATIVE) {
1022
977
  entries = await sender.nativeListZips();
1023
- } else if (STORAGE === "opfs") {
978
+ } else {
1024
979
  const opfsRoot = await navigator.storage.getDirectory();
1025
980
  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()) }));
1031
981
  }
1032
982
  for await (const entry of entries) {
1033
983
  if (/preload/.test(entry.name)) {
@@ -1046,24 +996,14 @@ var loadBooks = async ({ primaryOnly = false } = {}) => {
1046
996
  }
1047
997
  }
1048
998
  };
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;
999
+ var configure = ({ native, checkUpdates }) => {
1000
+ console.info("configuring!!", native, checkUpdates);
1001
+ if (typeof native !== "undefined") {
1002
+ NATIVE = !!native;
1059
1003
  }
1060
- if (typeof checkUpdates !== "undefined") {
1004
+ if (typeof native !== "undefined") {
1061
1005
  CHECK_UPDATES = !!checkUpdates;
1062
1006
  }
1063
- if (typeof zipBaseUrl !== "undefined") {
1064
- ZIP_BASE_URL = zipBaseUrl;
1065
- }
1066
- console.info("ow::configure", { STORAGE, CHECK_UPDATES, ZIP_BASE_URL });
1067
1007
  };
1068
1008
  var loadPreload2 = async () => {
1069
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 = {};
@@ -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,41 +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
- storage,
127
- zipBaseUrl,
128
97
  checkUpdates
129
98
  } = {}) => {
130
- const fetchWorker = await fetchWorkerPromise;
131
- const configureOptions = { storage, zipBaseUrl, checkUpdates };
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
+ }
132
114
  if (nativeReadFile) {
133
115
  const wwHandler = makeSyncHandler(offlineWorker, { nativeReadFile, nativeWriteFile, nativeListZips });
134
116
  offlineWorker.onmessage = combineHandlers(handler, wwHandler);
135
- if (storage !== "native") {
136
- console.warn("nativeReadFile given, ignoring storage", storage);
137
- }
138
- offlineWorkerSync.configure({ ...configureOptions, storage: "native" });
117
+ offlineWorkerSync.configure({ native: true, checkUpdates });
139
118
  } else {
119
+ offlineWorkerSync.configure({ native: false, checkUpdates });
140
120
  offlineWorker.onmessage = handler.handle;
141
- offlineWorkerSync.configure(configureOptions);
142
121
  }
143
122
  offlineWorkerSync.on("ready", setWorkersReady);
144
123
  const channel = new MessageChannel();
145
124
  offlineWorkerSync.initChannel({ ports: [channel.port1] });
146
125
  fetchWorker.postMessage({ methodName: "initChannel" }, [channel.port2]);
147
- fetchWorker.postMessage({ methodName: "configure", arg: { storage } });
148
126
  offlineWorkerSync.on("opfsProgress", () => {
149
127
  });
150
128
  if (!primaryOnly) {
151
129
  await offlineWorkerSync.loadPreload();
152
130
  }
153
- if (!skipLoadBooks) {
154
- await offlineWorkerSync.loadBooks({ primaryOnly });
155
- }
131
+ await offlineWorkerSync.loadBooks();
156
132
  setBooksLoaded();
157
133
  };
158
134
  var useOfflineWorker_default = ({
@@ -160,28 +136,17 @@ var useOfflineWorker_default = ({
160
136
  nativeReadFile,
161
137
  nativeWriteFile,
162
138
  nativeListZips,
163
- checkUpdates,
164
- storage,
165
- zipBaseUrl
139
+ checkUpdates
166
140
  } = {}) => {
167
141
  const [ready, setReady] = useState(false);
168
142
  useEffect(() => {
169
143
  const fn = async () => {
170
- await installWorker({
171
- primaryOnly,
172
- nativeReadFile,
173
- nativeWriteFile,
174
- nativeListZips,
175
- storage,
176
- zipBaseUrl,
177
- checkUpdates
178
- });
144
+ await installWorker({ primaryOnly, nativeReadFile, nativeWriteFile, nativeListZips, checkUpdates });
179
145
  await Promise.all([workersReadyPromise, setBooksLoadedPromise]);
180
- fetch(window.location.href.replace(window.location.search, ""));
181
146
  setReady(true);
182
147
  };
183
148
  fn();
184
- }, [primaryOnly, nativeReadFile, nativeWriteFile, nativeListZips, storage, zipBaseUrl, checkUpdates]);
149
+ }, [primaryOnly, nativeReadFile, nativeWriteFile, nativeListZips, checkUpdates]);
185
150
  const loadBook = useCallback(
186
151
  async ({ id, forceRefresh }, cbk) => {
187
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-a4074e64",
3
+ "version": "24.22.0-b0b2683d",
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-a4074e64"
55
+ "@lls/vitescripts": "24.22.0-b0b2683d"
56
56
  },
57
57
  "dependencies": {
58
58
  "fflate": "0.8.2"