@lls/offline 24.22.0-ebe52096 → 24.23.0-0e1cb633

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.
@@ -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()}-${Math.random().toFixed(5)}`;
23
23
  dic[eventId] = { resolve, reject };
24
24
  offlineWorker2.postMessage({ eventId, methodName, arg }, ports);
25
25
  });
@@ -62,7 +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
+ var openCache = async (mode) => caches.open(`LLS_OFFLINE_${mode}`);
66
66
 
67
67
  // src/worker/swFetchScreenCall.ts
68
68
  var zipSlugName = (str) => str.replace(/[^a-zA-Z0-9-.]/g, "");
@@ -75,6 +75,15 @@ var cocoreFetchPartialPageScreen = async (_ev, { offlineWorkerSync: offlineWorke
75
75
  const gqlPage = await offlineWorkerSync2.loadPageContent({ entryId });
76
76
  return { data: gqlPage };
77
77
  };
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
+ };
78
87
  var cocoreFetchPartialPageSiblingsScreen = async (_ev) => {
79
88
  return { data: { viewer: {} } };
80
89
  };
@@ -189,6 +198,7 @@ var coreFetchPagesApi = async (ev, { offlineWorkerSync: offlineWorkerSync2, vari
189
198
  };
190
199
  var handles = {
191
200
  coreFetchBookDrawerScreen,
201
+ cocoreFetchBookScreen,
192
202
  coreFetchPagesApi,
193
203
  cocoreFetchPartialPageScreen,
194
204
  cocoreFetchPartialPageSiblingsScreen
@@ -220,21 +230,20 @@ var setKnownLinks = (knownLinks2, { entryNames, bookId }) => {
220
230
  };
221
231
 
222
232
  // src/worker/fetch-worker.ts
223
- var fetchAsset = async (ev, { entryId, mimeType, offlineWorkerSync: offlineWorkerSync2 }) => {
233
+ var STORAGE = "cache";
234
+ var CONF_ENV = "development";
235
+ var fetchAsset = async (_ev, { entryId, mimeType, offlineWorkerSync: offlineWorkerSync2 }) => {
224
236
  try {
225
237
  const buf = await offlineWorkerSync2.readZipEntry(entryId);
226
- const url = ev.request.url;
227
238
  return new Response(buf, {
228
239
  headers: {
229
240
  "Cache-Control": "max-age=600, s-maxage=600, public, proxy-revalidate",
241
+ "Content-Length": buf.byteLength,
230
242
  "Content-Type": mimeType
231
243
  },
232
244
  // @ts-ignore: poor ts typing
233
- ok: true,
234
- redirected: false,
235
245
  status: 200,
236
- type: "cors",
237
- url
246
+ statusText: "OK"
238
247
  });
239
248
  } catch (e) {
240
249
  console.error("FAILED fetchAsset", e);
@@ -242,8 +251,7 @@ var fetchAsset = async (ev, { entryId, mimeType, offlineWorkerSync: offlineWorke
242
251
  // @ts-ignore: poor ts typing
243
252
  ok: false,
244
253
  status: 500,
245
- type: "cors",
246
- url: ev.request.url
254
+ statusText: e?.toString?.() || "fail fetch"
247
255
  });
248
256
  }
249
257
  };
@@ -283,10 +291,12 @@ var ACCEPTED_EXTENSIONS = {
283
291
  ".gif": "image/gif",
284
292
  ".webm": "video/webm",
285
293
  ".m4a": "audio/mp4",
286
- ".webp": "image/webp"
294
+ ".webp": "image/webp",
295
+ ".riv": "application/octet-stream",
296
+ ".pdf": "application/pdf"
287
297
  };
288
298
  var putInCache = async (request, response) => {
289
- const cache = await openCache();
299
+ const cache = await openCache(CONF_ENV);
290
300
  await cache.put(request, response);
291
301
  };
292
302
  var onlineFirst = async (request, event) => {
@@ -300,22 +310,24 @@ var onlineFirst = async (request, event) => {
300
310
  event.waitUntil(cached);
301
311
  }
302
312
  return responseFromNetwork;
303
- } catch (_e) {
313
+ } catch (e) {
304
314
  const over = /\/\?story=basic/.test(request.url) ? request.url.replace(/\/\?story=.*$/, "") : request;
305
315
  const responseFromCache = await caches.match(over);
306
316
  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
- });
317
+ return new Response(
318
+ `FAILED fetch ${e && typeof e === "object" && "message" in e ? e.message : e?.toString?.()}`,
319
+ {
320
+ // @ts-ignore: poor ts typing
321
+ ok: false,
322
+ status: 500,
323
+ type: "cors",
324
+ url: event.request.url
325
+ }
326
+ );
314
327
  }
315
328
  return responseFromCache;
316
329
  }
317
330
  };
318
- var STORAGE = "cache";
319
331
  var swSelf = self;
320
332
  swSelf.addEventListener("fetch", (ev) => {
321
333
  const url = ev.request.url;
@@ -362,16 +374,23 @@ var initChannel = async (__, { ports }) => {
362
374
  );
363
375
  offlineWorkerSync = sender;
364
376
  offlineWorker.onmessage = handler.handle;
365
- offlineWorkerSync.on("setKnownLinks", setKnownLinks.bind(null, setKnownLinks));
377
+ offlineWorkerSync.on("setKnownLinks", setKnownLinks.bind(null, knownLinks));
366
378
  offlineWorker.postMessage({ methodName: "sendAppReady" });
367
379
  };
368
380
  var knownLinks = /* @__PURE__ */ new Map();
369
- var configure = ({ storage } = {}) => {
381
+ var configure = ({
382
+ storage,
383
+ confEnv
384
+ } = {}) => {
370
385
  STORAGE = "cache";
386
+ CONF_ENV = "development";
371
387
  if (typeof storage !== "undefined") {
372
388
  STORAGE = storage;
373
389
  }
374
- console.info("sw::configure", { STORAGE });
390
+ if (typeof confEnv !== "undefined") {
391
+ CONF_ENV = confEnv;
392
+ }
393
+ console.info("sw::configure", { STORAGE, CONF_ENV });
375
394
  };
376
395
  swSelf.onmessage = async ({
377
396
  data: { methodName, arg } = {},
@@ -30,7 +30,7 @@ var makeSyncWorker = (offlineWorker, methodNames, dbg) => {
30
30
  const makeFn = (methodName) => {
31
31
  return ({ ports, ...arg } = {}) => {
32
32
  return new Promise((resolve, reject) => {
33
- const eventId = `${methodName}:${Date.now()}`;
33
+ const eventId = `${methodName}:${Date.now()}-${Math.random().toFixed(5)}`;
34
34
  dic[eventId] = { resolve, reject };
35
35
  offlineWorker.postMessage({ eventId, methodName, arg }, ports);
36
36
  });
@@ -83,7 +83,17 @@ var combineHandlers = (...handlers) => {
83
83
  console.error("no handlers matched", methodName);
84
84
  };
85
85
  };
86
- var openCache = async () => caches.open(`LLS_OFFLINE_${process.env.CONF_ENV}`);
86
+ var openCache = async (mode) => caches.open(`LLS_OFFLINE_${mode}`);
87
+ var concatArrayBuffers = (buffers) => {
88
+ const totalLength = buffers.reduce((sum, buf) => sum + buf.byteLength, 0);
89
+ const concatenated = new Uint8Array(totalLength);
90
+ let offset = 0;
91
+ for (const buffer of buffers) {
92
+ concatenated.set(new Uint8Array(buffer), offset);
93
+ offset += buffer.byteLength;
94
+ }
95
+ return concatenated.buffer;
96
+ };
87
97
 
88
98
  // src/worker/wwApi.ts
89
99
  var STATE = {
@@ -765,6 +775,9 @@ async function decryptData(encryptedData, key2, iv2) {
765
775
  return decryptedData;
766
776
  }
767
777
  var BOOKS = {};
778
+ var zipNameInMedias = (zipName) => {
779
+ return /^(pages|book)/.test(zipName);
780
+ };
768
781
  var readZipEntry = async ({
769
782
  bookId,
770
783
  entryName,
@@ -774,9 +787,20 @@ var readZipEntry = async ({
774
787
  console.trace("no bookId", bookId, "found");
775
788
  return null;
776
789
  }
777
- const bookEntry = BOOKS[bookId].get(entryName);
790
+ const manifest = BOOKS[bookId].manifest;
791
+ let overridenName = entryName;
792
+ if (manifest && !entryName.includes("gqls/")) {
793
+ const zipName = entryName.replace("medias/", "");
794
+ if (zipNameInMedias(zipName)) {
795
+ const originalName = manifest.medias[zipName];
796
+ overridenName = `medias/${originalName}`;
797
+ } else {
798
+ console.error("any media should exist in manifest", zipName, entryName, bookId);
799
+ }
800
+ }
801
+ const bookEntry = BOOKS[bookId].map.get(overridenName);
778
802
  if (!bookEntry) {
779
- console.info("no bookEntry", entryName, "found");
803
+ console.info("no bookEntry", entryName, "found", overridenName);
780
804
  return null;
781
805
  }
782
806
  if (!bookEntry.decoded) {
@@ -787,16 +811,6 @@ var readZipEntry = async ({
787
811
  var hasZip = (bookId) => {
788
812
  return !!BOOKS[bookId];
789
813
  };
790
- function concatArrayBuffers(buffers) {
791
- const totalLength = buffers.reduce((sum, buf) => sum + buf.byteLength, 0);
792
- const concatenated = new Uint8Array(totalLength);
793
- let offset = 0;
794
- for (const buffer of buffers) {
795
- concatenated.set(new Uint8Array(buffer), offset);
796
- offset += buffer.byteLength;
797
- }
798
- return concatenated.buffer;
799
- }
800
814
  var loadZip = async (buf, bookId) => {
801
815
  const m = /* @__PURE__ */ new Map();
802
816
  const unzipper = new Unzip();
@@ -836,14 +850,26 @@ var loadZip = async (buf, bookId) => {
836
850
  await sleep;
837
851
  }
838
852
  unzipper.push(buf.slice((nChunks - 1) * chunkSize, buf.byteLength), true);
839
- BOOKS[bookId] = m;
840
- return [...m.keys()];
853
+ BOOKS[bookId] = {
854
+ map: m,
855
+ manifest: null
856
+ };
857
+ const manifestEntry = m.get("manifest.json");
858
+ const keys = [...m.keys()];
859
+ if (manifestEntry) {
860
+ manifestEntry.decoded = await decryptData(await manifestEntry.zipEntry.getData(), key, iv);
861
+ BOOKS[bookId].manifest = bufToJson(manifestEntry.decoded);
862
+ const { medias } = BOOKS[bookId].manifest;
863
+ keys.push(...Object.keys(medias).map((entryName) => `medias/${entryName}`));
864
+ }
865
+ return keys;
841
866
  };
842
867
 
843
868
  // src/worker/offline-worker.ts
844
869
  var CHECK_UPDATES = true;
845
870
  var STORAGE = "cache";
846
871
  var ZIP_BASE_URL = "https://ci.lls.fr/artefacts/content/development";
872
+ var CONF_ENV = "development";
847
873
  var LOADED_BOOKS = /* @__PURE__ */ new Map();
848
874
  var fetchZipFile = async (zipUrl, { forceRefresh } = {}) => {
849
875
  const fileName = zipUrl.split("/").slice(-1)[0];
@@ -923,7 +949,7 @@ var fetchZipFile = async (zipUrl, { forceRefresh } = {}) => {
923
949
  await accessHandle.write(arrayBuffer);
924
950
  await accessHandle.close();
925
951
  } else {
926
- const cache = await openCache();
952
+ const cache = await openCache(CONF_ENV);
927
953
  const response2 = new Response(arrayBuffer, {
928
954
  headers: {
929
955
  "Cache-Control": "max-age=600, s-maxage=600, public, proxy-revalidate",
@@ -1024,9 +1050,11 @@ var loadBooks = async ({ primaryOnly = false } = {}) => {
1024
1050
  const opfsRoot = await navigator.storage.getDirectory();
1025
1051
  entries = await opfsRoot.values();
1026
1052
  } else {
1027
- const cache = await openCache();
1053
+ const cache = await openCache(CONF_ENV);
1028
1054
  const keys = await cache.keys();
1029
- const zips = keys.filter((key2) => key2.url.endsWith(".zip"));
1055
+ const zips = keys.filter((key2) => {
1056
+ return key2.url.match(/lecture-cp\.zip|story-.*?\.zip/);
1057
+ });
1030
1058
  entries = zips.map((zip) => ({ name: String(zip.url.split("/").pop()) }));
1031
1059
  }
1032
1060
  for await (const entry of entries) {
@@ -1049,11 +1077,13 @@ var loadBooks = async ({ primaryOnly = false } = {}) => {
1049
1077
  var configure = ({
1050
1078
  storage,
1051
1079
  checkUpdates,
1052
- zipBaseUrl
1080
+ zipBaseUrl,
1081
+ confEnv
1053
1082
  }) => {
1054
1083
  CHECK_UPDATES = true;
1055
1084
  STORAGE = "cache";
1056
1085
  ZIP_BASE_URL = "https://ci.lls.fr/artefacts/content/development";
1086
+ CONF_ENV = "development";
1057
1087
  if (typeof storage !== "undefined") {
1058
1088
  STORAGE = storage;
1059
1089
  }
@@ -1063,7 +1093,10 @@ var configure = ({
1063
1093
  if (typeof zipBaseUrl !== "undefined") {
1064
1094
  ZIP_BASE_URL = zipBaseUrl;
1065
1095
  }
1066
- console.info("ow::configure", { STORAGE, CHECK_UPDATES, ZIP_BASE_URL });
1096
+ if (typeof confEnv !== "undefined") {
1097
+ CONF_ENV = confEnv;
1098
+ }
1099
+ console.info("ow::configure", { STORAGE, CHECK_UPDATES, ZIP_BASE_URL, CONF_ENV });
1067
1100
  };
1068
1101
  var loadPreload2 = async () => {
1069
1102
  const zipUrl = "https://lls-ci-fr.s3.eu-west-3.amazonaws.com/artefacts/content/development/preload.zip";
package/lib/index.js CHANGED
@@ -30,7 +30,7 @@ var makeSyncWorker = (offlineWorker2, methodNames, dbg) => {
30
30
  const makeFn = (methodName) => {
31
31
  return ({ ports, ...arg } = {}) => {
32
32
  return new Promise((resolve, reject) => {
33
- const eventId = `${methodName}:${Date.now()}`;
33
+ const eventId = `${methodName}:${Date.now()}-${Math.random().toFixed(5)}`;
34
34
  dic[eventId] = { resolve, reject };
35
35
  offlineWorker2.postMessage({ eventId, methodName, arg }, ports);
36
36
  });
@@ -94,6 +94,9 @@ var { handler, ...offlineWorkerSync } = makeSyncWorker(
94
94
  var fetchWorkerPromise = new Promise(
95
95
  tryCatch(async () => {
96
96
  let fetchWorker = null;
97
+ await navigator.serviceWorker.getRegistrations().then((registrations) => {
98
+ return Promise.all(registrations.map((reg) => reg.unregister()));
99
+ });
97
100
  await navigator.serviceWorker.register("/fetch-worker.js", { type: "module" }).then((reg) => {
98
101
  return reg.update().catch((e) => {
99
102
  console.debug(e, "likely we are offline");
@@ -125,10 +128,11 @@ var installWorker = async ({
125
128
  nativeListZips,
126
129
  storage,
127
130
  zipBaseUrl,
128
- checkUpdates
131
+ checkUpdates,
132
+ confEnv
129
133
  } = {}) => {
130
134
  const fetchWorker = await fetchWorkerPromise;
131
- const configureOptions = { storage, zipBaseUrl, checkUpdates };
135
+ const configureOptions = { storage, zipBaseUrl, checkUpdates, confEnv };
132
136
  if (nativeReadFile) {
133
137
  const wwHandler = makeSyncHandler(offlineWorker, { nativeReadFile, nativeWriteFile, nativeListZips });
134
138
  offlineWorker.onmessage = combineHandlers(handler, wwHandler);
@@ -144,7 +148,7 @@ var installWorker = async ({
144
148
  const channel = new MessageChannel();
145
149
  offlineWorkerSync.initChannel({ ports: [channel.port1] });
146
150
  fetchWorker.postMessage({ methodName: "initChannel" }, [channel.port2]);
147
- fetchWorker.postMessage({ methodName: "configure", arg: { storage } });
151
+ fetchWorker.postMessage({ methodName: "configure", arg: { storage, confEnv } });
148
152
  offlineWorkerSync.on("opfsProgress", () => {
149
153
  });
150
154
  if (!primaryOnly) {
@@ -162,7 +166,8 @@ var useOfflineWorker_default = ({
162
166
  nativeListZips,
163
167
  checkUpdates,
164
168
  storage,
165
- zipBaseUrl
169
+ zipBaseUrl,
170
+ confEnv
166
171
  } = {}) => {
167
172
  const [ready, setReady] = useState(false);
168
173
  useEffect(() => {
@@ -174,14 +179,15 @@ var useOfflineWorker_default = ({
174
179
  nativeListZips,
175
180
  storage,
176
181
  zipBaseUrl,
177
- checkUpdates
182
+ checkUpdates,
183
+ confEnv
178
184
  });
179
185
  await Promise.all([workersReadyPromise, setBooksLoadedPromise]);
180
186
  fetch(window.location.href.replace(window.location.search, ""));
181
187
  setReady(true);
182
188
  };
183
189
  fn();
184
- }, [primaryOnly, nativeReadFile, nativeWriteFile, nativeListZips, storage, zipBaseUrl, checkUpdates]);
190
+ }, [primaryOnly, nativeReadFile, nativeWriteFile, nativeListZips, storage, zipBaseUrl, checkUpdates, confEnv]);
185
191
  const loadBook = useCallback(
186
192
  async ({ id, forceRefresh }, cbk) => {
187
193
  offlineWorkerSync.on("opfsProgress", cbk);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lls/offline",
3
- "version": "24.22.0-ebe52096",
3
+ "version": "24.23.0-0e1cb633",
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-ebe52096"
55
+ "@lls/vitescripts": "24.23.0-0e1cb633"
56
56
  },
57
57
  "dependencies": {
58
58
  "fflate": "0.8.2"