@lls/offline 24.27.0 → 24.28.0-12ba1b40
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 +165 -30
- package/lib/assets/offline-worker.js +121 -643
- package/lib/index.js +71 -7
- package/package.json +4 -3
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
// src/utils/stream.ts
|
|
2
|
+
var parseRange = (range, size) => {
|
|
3
|
+
const parts = range.replace("bytes=", "").split("-");
|
|
4
|
+
let start = Number.parseInt(parts[0], 10);
|
|
5
|
+
let end = Number.parseInt(parts[1], 10);
|
|
6
|
+
if (isNaN(start)) {
|
|
7
|
+
start = size - end;
|
|
8
|
+
end = size - 1;
|
|
9
|
+
} else if (isNaN(end)) {
|
|
10
|
+
end = size - 1;
|
|
11
|
+
}
|
|
12
|
+
if (end > size - 1) {
|
|
13
|
+
end = size - 1;
|
|
14
|
+
}
|
|
15
|
+
const chunkSize = end - start + 1;
|
|
16
|
+
return { start, end, chunkSize };
|
|
17
|
+
};
|
|
18
|
+
|
|
1
19
|
// src/utils/worker.ts
|
|
2
20
|
var makeSyncWorker = (offlineWorker2, methodNames, dbg) => {
|
|
3
21
|
const dic = {};
|
|
@@ -20,7 +38,18 @@ var makeSyncWorker = (offlineWorker2, methodNames, dbg) => {
|
|
|
20
38
|
return ({ ports, ...arg } = {}) => {
|
|
21
39
|
return new Promise((resolve, reject) => {
|
|
22
40
|
const eventId = `${methodName}:${Date.now()}-${Math.random().toFixed(5)}`;
|
|
23
|
-
|
|
41
|
+
let resolved = false;
|
|
42
|
+
const timeout = setTimeout(() => {
|
|
43
|
+
console.warn("slow request for", methodName, arg);
|
|
44
|
+
}, 3e3);
|
|
45
|
+
const doResolve = (arg2) => {
|
|
46
|
+
if (!resolved) {
|
|
47
|
+
resolved = true;
|
|
48
|
+
clearTimeout(timeout);
|
|
49
|
+
resolve(arg2);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
dic[eventId] = { resolve: doResolve, reject };
|
|
24
53
|
offlineWorker2.postMessage({ eventId, methodName, arg }, ports);
|
|
25
54
|
});
|
|
26
55
|
};
|
|
@@ -77,7 +106,7 @@ var cocoreFetchPartialPageScreen = async (_ev, { offlineWorkerSync: offlineWorke
|
|
|
77
106
|
const key = `gqls/${zipSlugName(variables.slugs[0] || "")}.json`;
|
|
78
107
|
const entryId = knownLinks2.get(key);
|
|
79
108
|
if (!entryId) {
|
|
80
|
-
throw new Error(`slug not found ${key}`);
|
|
109
|
+
throw new Error(`slug not found ${key}, links size: ${knownLinks2.size}`);
|
|
81
110
|
}
|
|
82
111
|
const gqlPage = await offlineWorkerSync2.loadPageContent({ entryId });
|
|
83
112
|
return { data: gqlPage };
|
|
@@ -202,22 +231,90 @@ var coreFetchPagesApi = async (ev, { offlineWorkerSync: offlineWorkerSync2, vari
|
|
|
202
231
|
}
|
|
203
232
|
}
|
|
204
233
|
};
|
|
234
|
+
var cocoreFetchPrimaryMethod = async (_ev, { offlineWorkerSync: offlineWorkerSync2, variables }) => {
|
|
235
|
+
const uri = variables.uris?.[0];
|
|
236
|
+
if (!uri) {
|
|
237
|
+
throw new Error("invalid uri");
|
|
238
|
+
}
|
|
239
|
+
const method = await offlineWorkerSync2.readZipEntry({ bookId: uri, entryName: "gqls/method.json", asJson: true });
|
|
240
|
+
return {
|
|
241
|
+
data: method
|
|
242
|
+
};
|
|
243
|
+
};
|
|
244
|
+
var cocoreCreateLexicalFlower = async (_ev, { variables }) => {
|
|
245
|
+
const flower = variables.flower;
|
|
246
|
+
if (!flower) {
|
|
247
|
+
throw new Error("invalid flower");
|
|
248
|
+
}
|
|
249
|
+
const back = {
|
|
250
|
+
viewer: {
|
|
251
|
+
createLexicalFlower: {
|
|
252
|
+
...flower,
|
|
253
|
+
id: Date.now(),
|
|
254
|
+
user: null,
|
|
255
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
return {
|
|
260
|
+
data: back
|
|
261
|
+
};
|
|
262
|
+
};
|
|
263
|
+
var cocoreUpdateLexicalFlower = async (_ev, { variables }) => {
|
|
264
|
+
const flower = variables.flower;
|
|
265
|
+
if (!flower) {
|
|
266
|
+
throw new Error("invalid flower");
|
|
267
|
+
}
|
|
268
|
+
const back = {
|
|
269
|
+
viewer: {
|
|
270
|
+
updateLexicalFlower: {
|
|
271
|
+
...flower,
|
|
272
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
return {
|
|
277
|
+
data: back
|
|
278
|
+
};
|
|
279
|
+
};
|
|
280
|
+
var cocoreDeleteLexicalFlower = async (_ev, { variables }) => {
|
|
281
|
+
const flower = variables.flower;
|
|
282
|
+
if (!flower) {
|
|
283
|
+
throw new Error("invalid flower");
|
|
284
|
+
}
|
|
285
|
+
const back = {
|
|
286
|
+
viewer: {
|
|
287
|
+
deleteLexicalFlower: flower
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
return {
|
|
291
|
+
data: back
|
|
292
|
+
};
|
|
293
|
+
};
|
|
205
294
|
var handles = {
|
|
206
295
|
coreFetchBookDrawerScreen,
|
|
207
296
|
cocoreFetchBookScreen,
|
|
208
297
|
coreFetchPagesApi,
|
|
209
298
|
cocoreFetchPartialPageScreen,
|
|
210
|
-
cocoreFetchPartialPageSiblingsScreen
|
|
299
|
+
cocoreFetchPartialPageSiblingsScreen,
|
|
300
|
+
cocoreFetchPrimaryMethod,
|
|
301
|
+
cocoreCreateLexicalFlower,
|
|
302
|
+
cocoreUpdateLexicalFlower,
|
|
303
|
+
cocoreDeleteLexicalFlower
|
|
211
304
|
};
|
|
212
305
|
var canHandleScreenCall = (url) => new RegExp(Object.keys(handles).join("|")).test(url);
|
|
213
306
|
var handleScreenCall = async (ev, { offlineWorkerSync: offlineWorkerSync2, knownLinks: knownLinks2 }) => {
|
|
214
307
|
try {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
308
|
+
let variables;
|
|
309
|
+
const searchParamsVariables = new URLSearchParams(new URL(ev.request.url).search).get("variables");
|
|
310
|
+
if (searchParamsVariables) {
|
|
311
|
+
variables = JSON.parse(searchParamsVariables);
|
|
312
|
+
} else {
|
|
313
|
+
const body = await new Response(ev.request.body).json();
|
|
314
|
+
variables = body.variables;
|
|
315
|
+
}
|
|
220
316
|
const key = ev.request.url.match(Object.keys(handles).join("|"))?.[0];
|
|
317
|
+
console.debug("screencall", key, "qs", variables, "vs body", ev.request.body);
|
|
221
318
|
if (!key) {
|
|
222
319
|
throw new Error("unknown ev");
|
|
223
320
|
}
|
|
@@ -238,17 +335,39 @@ var setKnownLinks = (knownLinks2, { entryNames, bookId }) => {
|
|
|
238
335
|
// src/worker/fetch-worker.ts
|
|
239
336
|
var STORAGE = "cache";
|
|
240
337
|
var CONF_ENV = "development";
|
|
241
|
-
var fetchAsset = async (
|
|
338
|
+
var fetchAsset = async (ev, { entryId, mimeType, offlineWorkerSync: offlineWorkerSync2 }) => {
|
|
242
339
|
try {
|
|
243
|
-
const buf = await offlineWorkerSync2.readZipEntry(entryId)
|
|
340
|
+
const [buf, maybeRangeHeaders] = await offlineWorkerSync2.readZipEntry(entryId).then((buf2) => {
|
|
341
|
+
const range = ev.request.headers.get("Range");
|
|
342
|
+
if (!ev.request.url.endsWith(".mp4") && !ev.request.url.endsWith(".webm")) {
|
|
343
|
+
return [buf2, {}];
|
|
344
|
+
}
|
|
345
|
+
if (!range) {
|
|
346
|
+
return [
|
|
347
|
+
buf2,
|
|
348
|
+
{
|
|
349
|
+
"Accept-Ranges": "bytes",
|
|
350
|
+
"Content-Range": `bytes ${0}-${buf2.byteLength}/${buf2.byteLength}`
|
|
351
|
+
}
|
|
352
|
+
];
|
|
353
|
+
}
|
|
354
|
+
const { start, end, chunkSize } = parseRange(range, buf2.byteLength);
|
|
355
|
+
const rangeHeaders = {
|
|
356
|
+
"Content-Length": chunkSize,
|
|
357
|
+
"Accept-Ranges": "bytes",
|
|
358
|
+
"Content-Range": `bytes ${start}-${end}/${buf2.byteLength}`
|
|
359
|
+
};
|
|
360
|
+
return [buf2.slice(start, end + 1), rangeHeaders];
|
|
361
|
+
});
|
|
244
362
|
return new Response(buf, {
|
|
245
363
|
headers: {
|
|
246
364
|
"Cache-Control": "max-age=600, s-maxage=600, public, proxy-revalidate",
|
|
247
365
|
"Content-Length": buf.byteLength,
|
|
248
|
-
"Content-Type": mimeType
|
|
366
|
+
"Content-Type": mimeType,
|
|
367
|
+
...maybeRangeHeaders
|
|
249
368
|
},
|
|
250
369
|
// @ts-ignore: poor ts typing
|
|
251
|
-
status: 200,
|
|
370
|
+
status: maybeRangeHeaders["Content-Range"] ? 206 : 200,
|
|
252
371
|
statusText: "OK"
|
|
253
372
|
});
|
|
254
373
|
} catch (e) {
|
|
@@ -305,23 +424,30 @@ var putInCache = async (request, response) => {
|
|
|
305
424
|
const cache = await openCache(CONF_ENV);
|
|
306
425
|
await cache.put(request, response);
|
|
307
426
|
};
|
|
427
|
+
var tryOnline = async (request, event) => {
|
|
428
|
+
const responseFromNetwork = await fetch(request);
|
|
429
|
+
if (isValidZipName(request.url) && !isValidS3Zip(responseFromNetwork)) {
|
|
430
|
+
throw new Error(`zip is invalid: got ${responseFromNetwork.headers.get("Content-Length")} bytes`);
|
|
431
|
+
}
|
|
432
|
+
const cached = request.method === "GET" || request.method === "OPTIONS" ? putInCache(request, responseFromNetwork.clone()) : Promise.resolve();
|
|
433
|
+
if (request.url.endsWith(".zip")) {
|
|
434
|
+
await cached;
|
|
435
|
+
event.waitUntil(Promise.resolve());
|
|
436
|
+
} else {
|
|
437
|
+
event.waitUntil(cached);
|
|
438
|
+
}
|
|
439
|
+
return responseFromNetwork;
|
|
440
|
+
};
|
|
441
|
+
var tryOffline = async (request, _event) => {
|
|
442
|
+
const over = /\/\?story=basic/.test(request.url) ? request.url.replace(/\/\?story=.*$/, "") : request;
|
|
443
|
+
const responseFromCache = await caches.match(over);
|
|
444
|
+
return responseFromCache;
|
|
445
|
+
};
|
|
308
446
|
var onlineFirst = async (request, event) => {
|
|
309
447
|
try {
|
|
310
|
-
|
|
311
|
-
if (isValidZipName(request.url) && !isValidS3Zip(responseFromNetwork)) {
|
|
312
|
-
throw new Error(`zip is invalid: got ${responseFromNetwork.headers.get("Content-Length")} bytes`);
|
|
313
|
-
}
|
|
314
|
-
const cached = request.method === "HEAD" ? Promise.resolve() : putInCache(request, responseFromNetwork.clone());
|
|
315
|
-
if (request.url.endsWith(".zip")) {
|
|
316
|
-
await cached;
|
|
317
|
-
event.waitUntil(Promise.resolve());
|
|
318
|
-
} else {
|
|
319
|
-
event.waitUntil(cached);
|
|
320
|
-
}
|
|
321
|
-
return responseFromNetwork;
|
|
448
|
+
return await tryOnline(request, event);
|
|
322
449
|
} catch (e) {
|
|
323
|
-
const
|
|
324
|
-
const responseFromCache = await caches.match(over);
|
|
450
|
+
const responseFromCache = await tryOffline(request, event);
|
|
325
451
|
if (!responseFromCache) {
|
|
326
452
|
return new Response(
|
|
327
453
|
`FAILED fetch ${e && typeof e === "object" && "message" in e ? e.message : e?.toString?.()}`,
|
|
@@ -343,18 +469,23 @@ swSelf.addEventListener("fetch", (ev) => {
|
|
|
343
469
|
const extension = url.match(/\.[^.]+$/)?.[0];
|
|
344
470
|
const mimeType = extension && extension in ACCEPTED_EXTENSIONS ? ACCEPTED_EXTENSIONS[extension] : "";
|
|
345
471
|
const isValidScreenCall = canHandleScreenCall(url);
|
|
346
|
-
if (
|
|
472
|
+
if (url.endsWith(".zip")) {
|
|
473
|
+
if (STORAGE === "cache") {
|
|
474
|
+
return ev.respondWith(onlineFirst(ev.request, ev));
|
|
475
|
+
}
|
|
347
476
|
return;
|
|
348
477
|
}
|
|
349
478
|
if (!mimeType && !isValidScreenCall) {
|
|
350
|
-
if (!/\.(css|tsx?|
|
|
479
|
+
if (!/\.(css|tsx?|[mj]sx?|woff2|wasm|fr|(web)?manifest)(\??|$)|@(vite|react|id)|(:6019\/?$)/.test(url)) {
|
|
351
480
|
console.debug("no ext", extension || url);
|
|
352
481
|
}
|
|
353
482
|
return ev.respondWith(onlineFirst(ev.request, ev));
|
|
354
483
|
}
|
|
484
|
+
if (/http:\/\/localhost:\d+\/(favicon\.svg|assets\/)/.test(url)) {
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
355
487
|
const entryId = knownLinks.get(url.replace(/https:\/\/.*?\//, "")) || knownLinks.get(`medias/${url.replace(/https:\/\/.*?\//, "")}`);
|
|
356
488
|
if (isValidScreenCall) {
|
|
357
|
-
console.debug("screencall!");
|
|
358
489
|
return ev.respondWith(fetchScreenCall(ev, { offlineWorkerSync, knownLinks }));
|
|
359
490
|
}
|
|
360
491
|
if (entryId) {
|
|
@@ -363,6 +494,7 @@ swSelf.addEventListener("fetch", (ev) => {
|
|
|
363
494
|
if (/lls|lelivrescolaire/.test(url)) {
|
|
364
495
|
console.info("no link for", url.replace(/https:\/\/.*?\//, ""), `medias/${url.replace(/https:\/\/.*?\//, "")}`);
|
|
365
496
|
}
|
|
497
|
+
console.debug("unintercepted url", url);
|
|
366
498
|
return;
|
|
367
499
|
});
|
|
368
500
|
swSelf.addEventListener("install", (_event) => {
|
|
@@ -383,7 +515,10 @@ var initChannel = async (__, { ports }) => {
|
|
|
383
515
|
);
|
|
384
516
|
offlineWorkerSync = sender;
|
|
385
517
|
offlineWorker.onmessage = handler.handle;
|
|
386
|
-
offlineWorkerSync.on("setKnownLinks",
|
|
518
|
+
offlineWorkerSync.on("setKnownLinks", ({ entryNames, bookId, eventId }) => {
|
|
519
|
+
setKnownLinks(knownLinks, { entryNames, bookId });
|
|
520
|
+
offlineWorker.postMessage({ methodName: "setKnownLinks:back", eventId });
|
|
521
|
+
});
|
|
387
522
|
offlineWorker.postMessage({ methodName: "sendAppReady" });
|
|
388
523
|
};
|
|
389
524
|
var knownLinks = /* @__PURE__ */ new Map();
|
|
@@ -31,7 +31,18 @@ var makeSyncWorker = (offlineWorker, methodNames, dbg) => {
|
|
|
31
31
|
return ({ ports, ...arg } = {}) => {
|
|
32
32
|
return new Promise((resolve, reject) => {
|
|
33
33
|
const eventId = `${methodName}:${Date.now()}-${Math.random().toFixed(5)}`;
|
|
34
|
-
|
|
34
|
+
let resolved = false;
|
|
35
|
+
const timeout = setTimeout(() => {
|
|
36
|
+
console.warn("slow request for", methodName, arg);
|
|
37
|
+
}, 3e3);
|
|
38
|
+
const doResolve = (arg2) => {
|
|
39
|
+
if (!resolved) {
|
|
40
|
+
resolved = true;
|
|
41
|
+
clearTimeout(timeout);
|
|
42
|
+
resolve(arg2);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
dic[eventId] = { resolve: doResolve, reject };
|
|
35
46
|
offlineWorker.postMessage({ eventId, methodName, arg }, ports);
|
|
36
47
|
});
|
|
37
48
|
};
|
|
@@ -84,16 +95,6 @@ var combineHandlers = (...handlers) => {
|
|
|
84
95
|
};
|
|
85
96
|
};
|
|
86
97
|
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
|
-
};
|
|
97
98
|
var isStoryZip = (name) => /story-.*?\.zip/.test(name);
|
|
98
99
|
var isValidZipName = (name) => {
|
|
99
100
|
return /lecture-cp\.zip/.test(name) || isStoryZip(name);
|
|
@@ -170,615 +171,72 @@ var loadPreload = (json) => {
|
|
|
170
171
|
});
|
|
171
172
|
};
|
|
172
173
|
|
|
173
|
-
//
|
|
174
|
-
var
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
0,
|
|
182
|
-
0,
|
|
183
|
-
0,
|
|
184
|
-
0,
|
|
185
|
-
0,
|
|
186
|
-
1,
|
|
187
|
-
1,
|
|
188
|
-
1,
|
|
189
|
-
1,
|
|
190
|
-
2,
|
|
191
|
-
2,
|
|
192
|
-
2,
|
|
193
|
-
2,
|
|
194
|
-
3,
|
|
195
|
-
3,
|
|
196
|
-
3,
|
|
197
|
-
3,
|
|
198
|
-
4,
|
|
199
|
-
4,
|
|
200
|
-
4,
|
|
201
|
-
4,
|
|
202
|
-
5,
|
|
203
|
-
5,
|
|
204
|
-
5,
|
|
205
|
-
5,
|
|
206
|
-
0,
|
|
207
|
-
/* unused */
|
|
208
|
-
0,
|
|
209
|
-
0,
|
|
210
|
-
/* impossible */
|
|
211
|
-
0
|
|
212
|
-
]);
|
|
213
|
-
var fdeb = new u8([
|
|
214
|
-
0,
|
|
215
|
-
0,
|
|
216
|
-
0,
|
|
217
|
-
0,
|
|
218
|
-
1,
|
|
219
|
-
1,
|
|
220
|
-
2,
|
|
221
|
-
2,
|
|
222
|
-
3,
|
|
223
|
-
3,
|
|
224
|
-
4,
|
|
225
|
-
4,
|
|
226
|
-
5,
|
|
227
|
-
5,
|
|
228
|
-
6,
|
|
229
|
-
6,
|
|
230
|
-
7,
|
|
231
|
-
7,
|
|
232
|
-
8,
|
|
233
|
-
8,
|
|
234
|
-
9,
|
|
235
|
-
9,
|
|
236
|
-
10,
|
|
237
|
-
10,
|
|
238
|
-
11,
|
|
239
|
-
11,
|
|
240
|
-
12,
|
|
241
|
-
12,
|
|
242
|
-
13,
|
|
243
|
-
13,
|
|
244
|
-
/* unused */
|
|
245
|
-
0,
|
|
246
|
-
0
|
|
247
|
-
]);
|
|
248
|
-
var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);
|
|
249
|
-
var freb = function(eb, start) {
|
|
250
|
-
var b = new u16(31);
|
|
251
|
-
for (var i = 0; i < 31; ++i) {
|
|
252
|
-
b[i] = start += 1 << eb[i - 1];
|
|
253
|
-
}
|
|
254
|
-
var r = new i32(b[30]);
|
|
255
|
-
for (var i = 1; i < 30; ++i) {
|
|
256
|
-
for (var j = b[i]; j < b[i + 1]; ++j) {
|
|
257
|
-
r[j] = j - b[i] << 5 | i;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
return { b, r };
|
|
261
|
-
};
|
|
262
|
-
var _a = freb(fleb, 2);
|
|
263
|
-
var fl = _a.b;
|
|
264
|
-
var revfl = _a.r;
|
|
265
|
-
fl[28] = 258, revfl[258] = 28;
|
|
266
|
-
var _b = freb(fdeb, 0);
|
|
267
|
-
var fd = _b.b;
|
|
268
|
-
var revfd = _b.r;
|
|
269
|
-
var rev = new u16(32768);
|
|
270
|
-
for (i = 0; i < 32768; ++i) {
|
|
271
|
-
x = (i & 43690) >> 1 | (i & 21845) << 1;
|
|
272
|
-
x = (x & 52428) >> 2 | (x & 13107) << 2;
|
|
273
|
-
x = (x & 61680) >> 4 | (x & 3855) << 4;
|
|
274
|
-
rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1;
|
|
275
|
-
}
|
|
276
|
-
var x;
|
|
277
|
-
var i;
|
|
278
|
-
var hMap = function(cd, mb, r) {
|
|
279
|
-
var s = cd.length;
|
|
280
|
-
var i = 0;
|
|
281
|
-
var l = new u16(mb);
|
|
282
|
-
for (; i < s; ++i) {
|
|
283
|
-
if (cd[i])
|
|
284
|
-
++l[cd[i] - 1];
|
|
285
|
-
}
|
|
286
|
-
var le = new u16(mb);
|
|
287
|
-
for (i = 1; i < mb; ++i) {
|
|
288
|
-
le[i] = le[i - 1] + l[i - 1] << 1;
|
|
289
|
-
}
|
|
290
|
-
var co;
|
|
291
|
-
if (r) {
|
|
292
|
-
co = new u16(1 << mb);
|
|
293
|
-
var rvb = 15 - mb;
|
|
294
|
-
for (i = 0; i < s; ++i) {
|
|
295
|
-
if (cd[i]) {
|
|
296
|
-
var sv = i << 4 | cd[i];
|
|
297
|
-
var r_1 = mb - cd[i];
|
|
298
|
-
var v = le[cd[i] - 1]++ << r_1;
|
|
299
|
-
for (var m = v | (1 << r_1) - 1; v <= m; ++v) {
|
|
300
|
-
co[rev[v] >> rvb] = sv;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
} else {
|
|
305
|
-
co = new u16(s);
|
|
306
|
-
for (i = 0; i < s; ++i) {
|
|
307
|
-
if (cd[i]) {
|
|
308
|
-
co[i] = rev[le[cd[i] - 1]++] >> 15 - cd[i];
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
return co;
|
|
313
|
-
};
|
|
314
|
-
var flt = new u8(288);
|
|
315
|
-
for (i = 0; i < 144; ++i)
|
|
316
|
-
flt[i] = 8;
|
|
317
|
-
var i;
|
|
318
|
-
for (i = 144; i < 256; ++i)
|
|
319
|
-
flt[i] = 9;
|
|
320
|
-
var i;
|
|
321
|
-
for (i = 256; i < 280; ++i)
|
|
322
|
-
flt[i] = 7;
|
|
323
|
-
var i;
|
|
324
|
-
for (i = 280; i < 288; ++i)
|
|
325
|
-
flt[i] = 8;
|
|
326
|
-
var i;
|
|
327
|
-
var fdt = new u8(32);
|
|
328
|
-
for (i = 0; i < 32; ++i)
|
|
329
|
-
fdt[i] = 5;
|
|
330
|
-
var i;
|
|
331
|
-
var flrm = /* @__PURE__ */ hMap(flt, 9, 1);
|
|
332
|
-
var fdrm = /* @__PURE__ */ hMap(fdt, 5, 1);
|
|
333
|
-
var max = function(a2) {
|
|
334
|
-
var m = a2[0];
|
|
335
|
-
for (var i = 1; i < a2.length; ++i) {
|
|
336
|
-
if (a2[i] > m)
|
|
337
|
-
m = a2[i];
|
|
338
|
-
}
|
|
339
|
-
return m;
|
|
340
|
-
};
|
|
341
|
-
var bits = function(d, p, m) {
|
|
342
|
-
var o = p / 8 | 0;
|
|
343
|
-
return (d[o] | d[o + 1] << 8) >> (p & 7) & m;
|
|
344
|
-
};
|
|
345
|
-
var bits16 = function(d, p) {
|
|
346
|
-
var o = p / 8 | 0;
|
|
347
|
-
return (d[o] | d[o + 1] << 8 | d[o + 2] << 16) >> (p & 7);
|
|
348
|
-
};
|
|
349
|
-
var shft = function(p) {
|
|
350
|
-
return (p + 7) / 8 | 0;
|
|
351
|
-
};
|
|
352
|
-
var slc = function(v, s, e) {
|
|
353
|
-
if (s == null || s < 0)
|
|
354
|
-
s = 0;
|
|
355
|
-
if (e == null || e > v.length)
|
|
356
|
-
e = v.length;
|
|
357
|
-
return new u8(v.subarray(s, e));
|
|
358
|
-
};
|
|
359
|
-
var ec = [
|
|
360
|
-
"unexpected EOF",
|
|
361
|
-
"invalid block type",
|
|
362
|
-
"invalid length/literal",
|
|
363
|
-
"invalid distance",
|
|
364
|
-
"stream finished",
|
|
365
|
-
"no stream handler",
|
|
366
|
-
,
|
|
367
|
-
"no callback",
|
|
368
|
-
"invalid UTF-8 data",
|
|
369
|
-
"extra field too long",
|
|
370
|
-
"date not in range 1980-2099",
|
|
371
|
-
"filename too long",
|
|
372
|
-
"stream finishing",
|
|
373
|
-
"invalid zip data"
|
|
374
|
-
// determined by unknown compression method
|
|
375
|
-
];
|
|
376
|
-
var err = function(ind, msg, nt) {
|
|
377
|
-
var e = new Error(msg || ec[ind]);
|
|
378
|
-
e.code = ind;
|
|
379
|
-
if (Error.captureStackTrace)
|
|
380
|
-
Error.captureStackTrace(e, err);
|
|
381
|
-
if (!nt)
|
|
382
|
-
throw e;
|
|
383
|
-
return e;
|
|
384
|
-
};
|
|
385
|
-
var inflt = function(dat, st, buf, dict) {
|
|
386
|
-
var sl = dat.length, dl = dict ? dict.length : 0;
|
|
387
|
-
if (!sl || st.f && !st.l)
|
|
388
|
-
return buf || new u8(0);
|
|
389
|
-
var noBuf = !buf;
|
|
390
|
-
var resize = noBuf || st.i != 2;
|
|
391
|
-
var noSt = st.i;
|
|
392
|
-
if (noBuf)
|
|
393
|
-
buf = new u8(sl * 3);
|
|
394
|
-
var cbuf = function(l2) {
|
|
395
|
-
var bl = buf.length;
|
|
396
|
-
if (l2 > bl) {
|
|
397
|
-
var nbuf = new u8(Math.max(bl * 2, l2));
|
|
398
|
-
nbuf.set(buf);
|
|
399
|
-
buf = nbuf;
|
|
400
|
-
}
|
|
401
|
-
};
|
|
402
|
-
var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n;
|
|
403
|
-
var tbts = sl * 8;
|
|
404
|
-
do {
|
|
405
|
-
if (!lm) {
|
|
406
|
-
final = bits(dat, pos, 1);
|
|
407
|
-
var type = bits(dat, pos + 1, 3);
|
|
408
|
-
pos += 3;
|
|
409
|
-
if (!type) {
|
|
410
|
-
var s = shft(pos) + 4, l = dat[s - 4] | dat[s - 3] << 8, t = s + l;
|
|
411
|
-
if (t > sl) {
|
|
412
|
-
if (noSt)
|
|
413
|
-
err(0);
|
|
414
|
-
break;
|
|
415
|
-
}
|
|
416
|
-
if (resize)
|
|
417
|
-
cbuf(bt + l);
|
|
418
|
-
buf.set(dat.subarray(s, t), bt);
|
|
419
|
-
st.b = bt += l, st.p = pos = t * 8, st.f = final;
|
|
420
|
-
continue;
|
|
421
|
-
} else if (type == 1)
|
|
422
|
-
lm = flrm, dm = fdrm, lbt = 9, dbt = 5;
|
|
423
|
-
else if (type == 2) {
|
|
424
|
-
var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4;
|
|
425
|
-
var tl = hLit + bits(dat, pos + 5, 31) + 1;
|
|
426
|
-
pos += 14;
|
|
427
|
-
var ldt = new u8(tl);
|
|
428
|
-
var clt = new u8(19);
|
|
429
|
-
for (var i = 0; i < hcLen; ++i) {
|
|
430
|
-
clt[clim[i]] = bits(dat, pos + i * 3, 7);
|
|
431
|
-
}
|
|
432
|
-
pos += hcLen * 3;
|
|
433
|
-
var clb = max(clt), clbmsk = (1 << clb) - 1;
|
|
434
|
-
var clm = hMap(clt, clb, 1);
|
|
435
|
-
for (var i = 0; i < tl; ) {
|
|
436
|
-
var r = clm[bits(dat, pos, clbmsk)];
|
|
437
|
-
pos += r & 15;
|
|
438
|
-
var s = r >> 4;
|
|
439
|
-
if (s < 16) {
|
|
440
|
-
ldt[i++] = s;
|
|
441
|
-
} else {
|
|
442
|
-
var c = 0, n = 0;
|
|
443
|
-
if (s == 16)
|
|
444
|
-
n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1];
|
|
445
|
-
else if (s == 17)
|
|
446
|
-
n = 3 + bits(dat, pos, 7), pos += 3;
|
|
447
|
-
else if (s == 18)
|
|
448
|
-
n = 11 + bits(dat, pos, 127), pos += 7;
|
|
449
|
-
while (n--)
|
|
450
|
-
ldt[i++] = c;
|
|
174
|
+
// src/utils/zipDecoder.ts
|
|
175
|
+
var getEOCDStart = (buf) => {
|
|
176
|
+
for (let i = buf.length - 1; i > 0; --i) {
|
|
177
|
+
if (buf[i] === 6) {
|
|
178
|
+
if (buf[i - 1] === 5) {
|
|
179
|
+
if (buf[i - 2] === 75) {
|
|
180
|
+
if (buf[i - 3] === 80) {
|
|
181
|
+
return i - 3;
|
|
451
182
|
}
|
|
452
183
|
}
|
|
453
|
-
var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit);
|
|
454
|
-
lbt = max(lt);
|
|
455
|
-
dbt = max(dt);
|
|
456
|
-
lm = hMap(lt, lbt, 1);
|
|
457
|
-
dm = hMap(dt, dbt, 1);
|
|
458
|
-
} else
|
|
459
|
-
err(1);
|
|
460
|
-
if (pos > tbts) {
|
|
461
|
-
if (noSt)
|
|
462
|
-
err(0);
|
|
463
|
-
break;
|
|
464
184
|
}
|
|
465
185
|
}
|
|
466
|
-
if (resize)
|
|
467
|
-
cbuf(bt + 131072);
|
|
468
|
-
var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1;
|
|
469
|
-
var lpos = pos;
|
|
470
|
-
for (; ; lpos = pos) {
|
|
471
|
-
var c = lm[bits16(dat, pos) & lms], sym = c >> 4;
|
|
472
|
-
pos += c & 15;
|
|
473
|
-
if (pos > tbts) {
|
|
474
|
-
if (noSt)
|
|
475
|
-
err(0);
|
|
476
|
-
break;
|
|
477
|
-
}
|
|
478
|
-
if (!c)
|
|
479
|
-
err(2);
|
|
480
|
-
if (sym < 256)
|
|
481
|
-
buf[bt++] = sym;
|
|
482
|
-
else if (sym == 256) {
|
|
483
|
-
lpos = pos, lm = null;
|
|
484
|
-
break;
|
|
485
|
-
} else {
|
|
486
|
-
var add = sym - 254;
|
|
487
|
-
if (sym > 264) {
|
|
488
|
-
var i = sym - 257, b = fleb[i];
|
|
489
|
-
add = bits(dat, pos, (1 << b) - 1) + fl[i];
|
|
490
|
-
pos += b;
|
|
491
|
-
}
|
|
492
|
-
var d = dm[bits16(dat, pos) & dms], dsym = d >> 4;
|
|
493
|
-
if (!d)
|
|
494
|
-
err(3);
|
|
495
|
-
pos += d & 15;
|
|
496
|
-
var dt = fd[dsym];
|
|
497
|
-
if (dsym > 3) {
|
|
498
|
-
var b = fdeb[dsym];
|
|
499
|
-
dt += bits16(dat, pos) & (1 << b) - 1, pos += b;
|
|
500
|
-
}
|
|
501
|
-
if (pos > tbts) {
|
|
502
|
-
if (noSt)
|
|
503
|
-
err(0);
|
|
504
|
-
break;
|
|
505
|
-
}
|
|
506
|
-
if (resize)
|
|
507
|
-
cbuf(bt + 131072);
|
|
508
|
-
var end = bt + add;
|
|
509
|
-
if (bt < dt) {
|
|
510
|
-
var shift = dl - dt, dend = Math.min(dt, end);
|
|
511
|
-
if (shift + bt < 0)
|
|
512
|
-
err(3);
|
|
513
|
-
for (; bt < dend; ++bt)
|
|
514
|
-
buf[bt] = dict[shift + bt];
|
|
515
|
-
}
|
|
516
|
-
for (; bt < end; ++bt)
|
|
517
|
-
buf[bt] = buf[bt - dt];
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
st.l = lm, st.p = lpos, st.b = bt, st.f = final;
|
|
521
|
-
if (lm)
|
|
522
|
-
final = 1, st.m = lbt, st.d = dm, st.n = dbt;
|
|
523
|
-
} while (!final);
|
|
524
|
-
return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt);
|
|
525
|
-
};
|
|
526
|
-
var et = /* @__PURE__ */ new u8(0);
|
|
527
|
-
var b2 = function(d, b) {
|
|
528
|
-
return d[b] | d[b + 1] << 8;
|
|
529
|
-
};
|
|
530
|
-
var b4 = function(d, b) {
|
|
531
|
-
return (d[b] | d[b + 1] << 8 | d[b + 2] << 16 | d[b + 3] << 24) >>> 0;
|
|
532
|
-
};
|
|
533
|
-
var b8 = function(d, b) {
|
|
534
|
-
return b4(d, b) + b4(d, b + 4) * 4294967296;
|
|
535
|
-
};
|
|
536
|
-
var Inflate = /* @__PURE__ */ function() {
|
|
537
|
-
function Inflate2(opts, cb) {
|
|
538
|
-
if (typeof opts == "function")
|
|
539
|
-
cb = opts, opts = {};
|
|
540
|
-
this.ondata = cb;
|
|
541
|
-
var dict = opts && opts.dictionary && opts.dictionary.subarray(-32768);
|
|
542
|
-
this.s = { i: 0, b: dict ? dict.length : 0 };
|
|
543
|
-
this.o = new u8(32768);
|
|
544
|
-
this.p = new u8(0);
|
|
545
|
-
if (dict)
|
|
546
|
-
this.o.set(dict);
|
|
547
186
|
}
|
|
548
|
-
|
|
549
|
-
if (!this.ondata)
|
|
550
|
-
err(5);
|
|
551
|
-
if (this.d)
|
|
552
|
-
err(4);
|
|
553
|
-
if (!this.p.length)
|
|
554
|
-
this.p = c;
|
|
555
|
-
else if (c.length) {
|
|
556
|
-
var n = new u8(this.p.length + c.length);
|
|
557
|
-
n.set(this.p), n.set(c, this.p.length), this.p = n;
|
|
558
|
-
}
|
|
559
|
-
};
|
|
560
|
-
Inflate2.prototype.c = function(final) {
|
|
561
|
-
this.s.i = +(this.d = final || false);
|
|
562
|
-
var bts = this.s.b;
|
|
563
|
-
var dt = inflt(this.p, this.s, this.o);
|
|
564
|
-
this.ondata(slc(dt, bts, this.s.b), this.d);
|
|
565
|
-
this.o = slc(dt, this.s.b - 32768), this.s.b = this.o.length;
|
|
566
|
-
this.p = slc(this.p, this.s.p / 8 | 0), this.s.p &= 7;
|
|
567
|
-
};
|
|
568
|
-
Inflate2.prototype.push = function(chunk, final) {
|
|
569
|
-
this.e(chunk), this.c(final);
|
|
570
|
-
};
|
|
571
|
-
return Inflate2;
|
|
572
|
-
}();
|
|
573
|
-
var td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder();
|
|
574
|
-
var tds = 0;
|
|
575
|
-
try {
|
|
576
|
-
td.decode(et, { stream: true });
|
|
577
|
-
tds = 1;
|
|
578
|
-
} catch (e) {
|
|
579
|
-
}
|
|
580
|
-
var dutf8 = function(d) {
|
|
581
|
-
for (var r = "", i = 0; ; ) {
|
|
582
|
-
var c = d[i++];
|
|
583
|
-
var eb = (c > 127) + (c > 223) + (c > 239);
|
|
584
|
-
if (i + eb > d.length)
|
|
585
|
-
return { s: r, r: slc(d, i - 1) };
|
|
586
|
-
if (!eb)
|
|
587
|
-
r += String.fromCharCode(c);
|
|
588
|
-
else if (eb == 3) {
|
|
589
|
-
c = ((c & 15) << 18 | (d[i++] & 63) << 12 | (d[i++] & 63) << 6 | d[i++] & 63) - 65536, r += String.fromCharCode(55296 | c >> 10, 56320 | c & 1023);
|
|
590
|
-
} else if (eb & 1)
|
|
591
|
-
r += String.fromCharCode((c & 31) << 6 | d[i++] & 63);
|
|
592
|
-
else
|
|
593
|
-
r += String.fromCharCode((c & 15) << 12 | (d[i++] & 63) << 6 | d[i++] & 63);
|
|
594
|
-
}
|
|
595
|
-
};
|
|
596
|
-
function strFromU8(dat, latin1) {
|
|
597
|
-
if (latin1) {
|
|
598
|
-
var r = "";
|
|
599
|
-
for (var i = 0; i < dat.length; i += 16384)
|
|
600
|
-
r += String.fromCharCode.apply(null, dat.subarray(i, i + 16384));
|
|
601
|
-
return r;
|
|
602
|
-
} else if (td) {
|
|
603
|
-
return td.decode(dat);
|
|
604
|
-
} else {
|
|
605
|
-
var _a2 = dutf8(dat), s = _a2.s, r = _a2.r;
|
|
606
|
-
if (r.length)
|
|
607
|
-
err(8);
|
|
608
|
-
return s;
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
var z64e = function(d, b) {
|
|
612
|
-
for (; b2(d, b) != 1; b += 4 + b2(d, b + 2))
|
|
613
|
-
;
|
|
614
|
-
return [b8(d, b + 12), b8(d, b + 4), b8(d, b + 20)];
|
|
187
|
+
throw new Error("failed to read EOCDstart");
|
|
615
188
|
};
|
|
616
|
-
var
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
};
|
|
622
|
-
UnzipPassThrough2.compression = 0;
|
|
623
|
-
return UnzipPassThrough2;
|
|
624
|
-
}();
|
|
625
|
-
var UnzipInflate = /* @__PURE__ */ function() {
|
|
626
|
-
function UnzipInflate2() {
|
|
627
|
-
var _this = this;
|
|
628
|
-
this.i = new Inflate(function(dat, final) {
|
|
629
|
-
_this.ondata(null, dat, final);
|
|
630
|
-
});
|
|
189
|
+
var readIndex = (buf, offset, nBytes) => {
|
|
190
|
+
let idx = 0;
|
|
191
|
+
for (let i = 0; i < nBytes; ++i) {
|
|
192
|
+
const next = buf[offset + i] * 256 ** i;
|
|
193
|
+
idx += next;
|
|
631
194
|
}
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
};
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
this.o = {
|
|
647
|
-
0: UnzipPassThrough
|
|
195
|
+
return idx;
|
|
196
|
+
};
|
|
197
|
+
var getSOCDStart = (buf, eocdIdx) => {
|
|
198
|
+
return readIndex(buf, eocdIdx + 16, 4);
|
|
199
|
+
};
|
|
200
|
+
var readEntryNames = (buf, socdIdx, nRecords) => {
|
|
201
|
+
const records = Array.from({ length: nRecords });
|
|
202
|
+
for (let i = 0; i < nRecords; ++i) {
|
|
203
|
+
const n = readIndex(buf, socdIdx + 28, 2);
|
|
204
|
+
const m = readIndex(buf, socdIdx + 30, 2);
|
|
205
|
+
const k = readIndex(buf, socdIdx + 32, 2);
|
|
206
|
+
records[i] = {
|
|
207
|
+
sofh: readIndex(buf, socdIdx + 42, 4),
|
|
208
|
+
name: buf.slice(socdIdx + 46, socdIdx + 46 + n)
|
|
648
209
|
};
|
|
649
|
-
|
|
210
|
+
socdIdx += 46 + n + m + k;
|
|
650
211
|
}
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
if (chunk.length)
|
|
667
|
-
return this.push(chunk, final);
|
|
668
|
-
} else {
|
|
669
|
-
var f = 0, i = 0, is = void 0, buf = void 0;
|
|
670
|
-
if (!this.p.length)
|
|
671
|
-
buf = chunk;
|
|
672
|
-
else if (!chunk.length)
|
|
673
|
-
buf = this.p;
|
|
674
|
-
else {
|
|
675
|
-
buf = new u8(this.p.length + chunk.length);
|
|
676
|
-
buf.set(this.p), buf.set(chunk, this.p.length);
|
|
677
|
-
}
|
|
678
|
-
var l = buf.length, oc = this.c, add = oc && this.d;
|
|
679
|
-
var _loop_2 = function() {
|
|
680
|
-
var _a2;
|
|
681
|
-
var sig = b4(buf, i);
|
|
682
|
-
if (sig == 67324752) {
|
|
683
|
-
f = 1, is = i;
|
|
684
|
-
this_1.d = null;
|
|
685
|
-
this_1.c = 0;
|
|
686
|
-
var bf = b2(buf, i + 6), cmp_1 = b2(buf, i + 8), u = bf & 2048, dd = bf & 8, fnl = b2(buf, i + 26), es = b2(buf, i + 28);
|
|
687
|
-
if (l > i + 30 + fnl + es) {
|
|
688
|
-
var chks_3 = [];
|
|
689
|
-
this_1.k.unshift(chks_3);
|
|
690
|
-
f = 2;
|
|
691
|
-
var sc_1 = b4(buf, i + 18), su_1 = b4(buf, i + 22);
|
|
692
|
-
var fn_1 = strFromU8(buf.subarray(i + 30, i += 30 + fnl), !u);
|
|
693
|
-
if (sc_1 == 4294967295) {
|
|
694
|
-
_a2 = dd ? [-2] : z64e(buf, i), sc_1 = _a2[0], su_1 = _a2[1];
|
|
695
|
-
} else if (dd)
|
|
696
|
-
sc_1 = -1;
|
|
697
|
-
i += es;
|
|
698
|
-
this_1.c = sc_1;
|
|
699
|
-
var d_1;
|
|
700
|
-
var file_1 = {
|
|
701
|
-
name: fn_1,
|
|
702
|
-
compression: cmp_1,
|
|
703
|
-
start: function() {
|
|
704
|
-
if (!file_1.ondata)
|
|
705
|
-
err(5);
|
|
706
|
-
if (!sc_1)
|
|
707
|
-
file_1.ondata(null, et, true);
|
|
708
|
-
else {
|
|
709
|
-
var ctr = _this.o[cmp_1];
|
|
710
|
-
if (!ctr)
|
|
711
|
-
file_1.ondata(err(14, "unknown compression type " + cmp_1, 1), null, false);
|
|
712
|
-
d_1 = sc_1 < 0 ? new ctr(fn_1) : new ctr(fn_1, sc_1, su_1);
|
|
713
|
-
d_1.ondata = function(err2, dat3, final2) {
|
|
714
|
-
file_1.ondata(err2, dat3, final2);
|
|
715
|
-
};
|
|
716
|
-
for (var _i = 0, chks_4 = chks_3; _i < chks_4.length; _i++) {
|
|
717
|
-
var dat2 = chks_4[_i];
|
|
718
|
-
d_1.push(dat2, false);
|
|
719
|
-
}
|
|
720
|
-
if (_this.k[0] == chks_3 && _this.c)
|
|
721
|
-
_this.d = d_1;
|
|
722
|
-
else
|
|
723
|
-
d_1.push(et, true);
|
|
724
|
-
}
|
|
725
|
-
},
|
|
726
|
-
terminate: function() {
|
|
727
|
-
if (d_1 && d_1.terminate)
|
|
728
|
-
d_1.terminate();
|
|
729
|
-
}
|
|
730
|
-
};
|
|
731
|
-
if (sc_1 >= 0)
|
|
732
|
-
file_1.size = sc_1, file_1.originalSize = su_1;
|
|
733
|
-
this_1.onfile(file_1);
|
|
734
|
-
}
|
|
735
|
-
return "break";
|
|
736
|
-
} else if (oc) {
|
|
737
|
-
if (sig == 134695760) {
|
|
738
|
-
is = i += 12 + (oc == -2 && 8), f = 3, this_1.c = 0;
|
|
739
|
-
return "break";
|
|
740
|
-
} else if (sig == 33639248) {
|
|
741
|
-
is = i -= 4, f = 3, this_1.c = 0;
|
|
742
|
-
return "break";
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
};
|
|
746
|
-
var this_1 = this;
|
|
747
|
-
for (; i < l - 4; ++i) {
|
|
748
|
-
var state_1 = _loop_2();
|
|
749
|
-
if (state_1 === "break")
|
|
750
|
-
break;
|
|
751
|
-
}
|
|
752
|
-
this.p = et;
|
|
753
|
-
if (oc < 0) {
|
|
754
|
-
var dat = f ? buf.subarray(0, is - 12 - (oc == -2 && 8) - (b4(buf, is - 16) == 134695760 && 4)) : buf.subarray(0, i);
|
|
755
|
-
if (add)
|
|
756
|
-
add.push(dat, !!f);
|
|
757
|
-
else
|
|
758
|
-
this.k[+(f == 2)].push(dat);
|
|
759
|
-
}
|
|
760
|
-
if (f & 2)
|
|
761
|
-
return this.push(buf.subarray(i), final);
|
|
762
|
-
this.p = buf.subarray(i);
|
|
763
|
-
}
|
|
764
|
-
if (final) {
|
|
765
|
-
if (this.c)
|
|
766
|
-
err(13);
|
|
767
|
-
this.p = null;
|
|
768
|
-
}
|
|
769
|
-
};
|
|
770
|
-
Unzip2.prototype.register = function(decoder) {
|
|
771
|
-
this.o[decoder.compression] = decoder;
|
|
772
|
-
};
|
|
773
|
-
return Unzip2;
|
|
774
|
-
}();
|
|
212
|
+
return records;
|
|
213
|
+
};
|
|
214
|
+
var readRecordData = (buf, { sofh }) => {
|
|
215
|
+
const dataSize = readIndex(buf, sofh + 22, 4);
|
|
216
|
+
const n = readIndex(buf, sofh + 26, 2);
|
|
217
|
+
const m = readIndex(buf, sofh + 28, 2);
|
|
218
|
+
return buf.slice(sofh + 30 + n + m, sofh + 30 + n + m + dataSize);
|
|
219
|
+
};
|
|
220
|
+
var getHeaders = (buf) => {
|
|
221
|
+
const eocdIdx = getEOCDStart(buf);
|
|
222
|
+
const nbRecords = readIndex(buf, eocdIdx + 10, 2);
|
|
223
|
+
const socdIdx = getSOCDStart(buf, eocdIdx);
|
|
224
|
+
const records = readEntryNames(buf, socdIdx, nbRecords);
|
|
225
|
+
return records;
|
|
226
|
+
};
|
|
775
227
|
|
|
776
228
|
// src/worker/wwZip.ts
|
|
777
229
|
var key = new Uint8Array([..."4c6520636f6e74656e7520646573206c".matchAll(/../g)].map(([c]) => Number(`0x${c}`)));
|
|
778
230
|
var iv = new Uint8Array(16).fill(0);
|
|
779
231
|
async function decryptData(encryptedData, key2, iv2) {
|
|
780
|
-
const cryptoKey = await crypto.subtle.importKey("raw", key2.buffer, { name: "AES-CBC" }, false, [
|
|
781
|
-
|
|
232
|
+
const cryptoKey = await crypto.subtle.importKey("raw", key2.buffer, { name: "AES-CBC" }, false, [
|
|
233
|
+
"decrypt"
|
|
234
|
+
]);
|
|
235
|
+
const decryptedData = await crypto.subtle.decrypt(
|
|
236
|
+
{ name: "AES-CBC", iv: iv2.buffer },
|
|
237
|
+
cryptoKey,
|
|
238
|
+
encryptedData
|
|
239
|
+
);
|
|
782
240
|
return decryptedData;
|
|
783
241
|
}
|
|
784
242
|
var BOOKS = {};
|
|
@@ -802,12 +260,14 @@ var readZipEntry = async ({
|
|
|
802
260
|
const originalName = manifest.medias[zipName];
|
|
803
261
|
overridenName = `medias/${originalName}`;
|
|
804
262
|
} else {
|
|
805
|
-
|
|
263
|
+
if (entryName !== "manifest.json") {
|
|
264
|
+
console.error("any media should exist in manifest", zipName, entryName, bookId);
|
|
265
|
+
}
|
|
806
266
|
}
|
|
807
267
|
}
|
|
808
268
|
const bookEntry = BOOKS[bookId].map.get(overridenName);
|
|
809
269
|
if (!bookEntry) {
|
|
810
|
-
console.info("no bookEntry", entryName, "
|
|
270
|
+
console.info("no bookEntry", entryName, "overridingName:", overridenName, "for book", bookId);
|
|
811
271
|
return null;
|
|
812
272
|
}
|
|
813
273
|
if (!bookEntry.decoded) {
|
|
@@ -820,43 +280,19 @@ var hasZip = (bookId) => {
|
|
|
820
280
|
};
|
|
821
281
|
var loadZip = async (buf, bookId) => {
|
|
822
282
|
const m = /* @__PURE__ */ new Map();
|
|
823
|
-
const
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
if (!
|
|
827
|
-
|
|
283
|
+
const headers = getHeaders(buf);
|
|
284
|
+
for (const header of headers) {
|
|
285
|
+
const name = new TextDecoder().decode(header.name);
|
|
286
|
+
if (!name.includes(".")) {
|
|
287
|
+
continue;
|
|
828
288
|
}
|
|
829
|
-
m.set(
|
|
289
|
+
m.set(name, {
|
|
830
290
|
decoded: null,
|
|
831
291
|
zipEntry: {
|
|
832
|
-
getData: () =>
|
|
833
|
-
return new Promise((resolve) => {
|
|
834
|
-
const buffers = [];
|
|
835
|
-
file.ondata = (err2, data, final) => {
|
|
836
|
-
if (err2) {
|
|
837
|
-
console.error("failed to read zip data", file.name, err2);
|
|
838
|
-
}
|
|
839
|
-
if (data.byteLength) {
|
|
840
|
-
buffers.push(data);
|
|
841
|
-
}
|
|
842
|
-
if (final) {
|
|
843
|
-
return resolve(concatArrayBuffers(buffers));
|
|
844
|
-
}
|
|
845
|
-
};
|
|
846
|
-
file.start();
|
|
847
|
-
});
|
|
848
|
-
}
|
|
292
|
+
getData: async () => readRecordData(buf, header).buffer
|
|
849
293
|
}
|
|
850
294
|
});
|
|
851
|
-
};
|
|
852
|
-
const chunkSize = 32 * 1024 * 1024;
|
|
853
|
-
const nChunks = Math.max(1, Math.floor(buf.byteLength / chunkSize));
|
|
854
|
-
const sleep = new Promise((resolve) => setTimeout(resolve, 0));
|
|
855
|
-
for (let i = 0; i < nChunks - 1; ++i) {
|
|
856
|
-
unzipper.push(buf.slice(i * chunkSize, (i + 1) * chunkSize));
|
|
857
|
-
await sleep;
|
|
858
295
|
}
|
|
859
|
-
unzipper.push(buf.slice((nChunks - 1) * chunkSize, buf.byteLength), true);
|
|
860
296
|
BOOKS[bookId] = {
|
|
861
297
|
map: m,
|
|
862
298
|
manifest: null
|
|
@@ -886,7 +322,8 @@ var fetchZipFile = async (zipUrl, { forceRefresh } = {}) => {
|
|
|
886
322
|
return back;
|
|
887
323
|
}
|
|
888
324
|
if (STORAGE === "cache") {
|
|
889
|
-
const
|
|
325
|
+
const cache = await openCache(CONF_ENV);
|
|
326
|
+
const response = await cache.match(zipUrl);
|
|
890
327
|
if (!response) {
|
|
891
328
|
throw new Error(`missing zip ${zipUrl}`);
|
|
892
329
|
}
|
|
@@ -910,7 +347,11 @@ var fetchZipFile = async (zipUrl, { forceRefresh } = {}) => {
|
|
|
910
347
|
const buf = await readArrayBuffer();
|
|
911
348
|
if (CHECK_UPDATES) {
|
|
912
349
|
const response = await fetch(zipUrl, { method: "HEAD" });
|
|
913
|
-
|
|
350
|
+
let remoteSize = Number.parseInt(response.headers.get("content-length") ?? "");
|
|
351
|
+
if (!remoteSize) {
|
|
352
|
+
console.info("remoteSize not found. will skip update. Is the server up at", zipUrl);
|
|
353
|
+
remoteSize = buf.byteLength;
|
|
354
|
+
}
|
|
914
355
|
if (remoteSize !== buf.byteLength) {
|
|
915
356
|
const error = `new ${fileName} available, refetching (opfs:${buf.byteLength} vs remote:${remoteSize})`;
|
|
916
357
|
console.debug(error);
|
|
@@ -918,6 +359,7 @@ var fetchZipFile = async (zipUrl, { forceRefresh } = {}) => {
|
|
|
918
359
|
throw new Error(`new ${fileName} available, refetching`);
|
|
919
360
|
}
|
|
920
361
|
}
|
|
362
|
+
self.postMessage({ methodName: "opfsProgress", arg: { total: buf.byteLength, bytes: buf.byteLength } });
|
|
921
363
|
return buf;
|
|
922
364
|
} catch (e) {
|
|
923
365
|
if (e instanceof Error && e.message !== "forceRefresh" && !e.message.includes("refetching")) {
|
|
@@ -947,6 +389,7 @@ var fetchZipFile = async (zipUrl, { forceRefresh } = {}) => {
|
|
|
947
389
|
self.postMessage({ methodName: "opfsProgress", arg: { total: contentLength, bytes: position } });
|
|
948
390
|
}
|
|
949
391
|
}
|
|
392
|
+
console.debug("zip loaded:", arrayBuffer.byteLength);
|
|
950
393
|
if (STORAGE === "native") {
|
|
951
394
|
await sender.nativeWriteFile({ fname: fileName, buffer: arrayBuffer });
|
|
952
395
|
} else if (STORAGE === "opfs") {
|
|
@@ -991,8 +434,15 @@ var loadBook2 = async ({ id: bookId, forceRefresh }) => {
|
|
|
991
434
|
tryCatch(async () => {
|
|
992
435
|
const buf = await fetchZipFile(`${ZIP_BASE_URL}/${bookId}.zip`, { forceRefresh });
|
|
993
436
|
try {
|
|
437
|
+
console.time("loadzip");
|
|
994
438
|
const entryNames = await loadZip(new Uint8Array(buf), bookId);
|
|
995
|
-
|
|
439
|
+
console.timeEnd("loadzip");
|
|
440
|
+
const eventId = `setKnownLinks:${Date.now()}-${Math.random().toFixed(5)}`;
|
|
441
|
+
const responseForEventId = new Promise((resolve, reject) => {
|
|
442
|
+
dicFetchWorkerCallback[eventId] = { resolve, reject };
|
|
443
|
+
});
|
|
444
|
+
fetchWorker.postMessage({ methodName: "setKnownLinks", arg: { entryNames, bookId, eventId } });
|
|
445
|
+
await responseForEventId;
|
|
996
446
|
if (isOldZip(bookId)) {
|
|
997
447
|
const json = await readZipEntry({
|
|
998
448
|
entryName: `preload/${bookId}.json`,
|
|
@@ -1000,6 +450,13 @@ var loadBook2 = async ({ id: bookId, forceRefresh }) => {
|
|
|
1000
450
|
asJson: true
|
|
1001
451
|
});
|
|
1002
452
|
loadBook(json);
|
|
453
|
+
} else {
|
|
454
|
+
try {
|
|
455
|
+
const { createdAt } = await readZipEntry({ bookId, entryName: "manifest.json", asJson: true });
|
|
456
|
+
console.debug("zipversion", createdAt);
|
|
457
|
+
} catch (e) {
|
|
458
|
+
console.debug("failed to read manifest.json", e);
|
|
459
|
+
}
|
|
1003
460
|
}
|
|
1004
461
|
return true;
|
|
1005
462
|
} catch (e) {
|
|
@@ -1029,6 +486,14 @@ var loadPageContent2 = async ({
|
|
|
1029
486
|
return await loadPageContent({ chapterId, json });
|
|
1030
487
|
};
|
|
1031
488
|
var fetchWorker;
|
|
489
|
+
var dicFetchWorkerCallback = {};
|
|
490
|
+
var handleFetchWorkerCallback = ({ data: { eventId } }) => {
|
|
491
|
+
if (dicFetchWorkerCallback[eventId]) {
|
|
492
|
+
dicFetchWorkerCallback[eventId].resolve();
|
|
493
|
+
} else {
|
|
494
|
+
console.debug("unknown eventId", eventId);
|
|
495
|
+
}
|
|
496
|
+
};
|
|
1032
497
|
var initChannel = (__, { ports }) => {
|
|
1033
498
|
fetchWorker = ports[0];
|
|
1034
499
|
const { canHandle, handle } = makeSyncHandler(fetchWorker, {
|
|
@@ -1043,6 +508,14 @@ var initChannel = (__, { ports }) => {
|
|
|
1043
508
|
self.postMessage({ methodName: "ready" });
|
|
1044
509
|
return;
|
|
1045
510
|
}
|
|
511
|
+
if (dataObj.data?.methodName === "setKnownLinks:back") {
|
|
512
|
+
if (typeof dataObj?.data?.eventId !== "string") {
|
|
513
|
+
console.debug("missing eventId to get response back for setKnownLinks:back");
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
handleFetchWorkerCallback(dataObj);
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
1046
519
|
if (canHandle(dataObj.data?.methodName || "")) {
|
|
1047
520
|
return handle(dataObj);
|
|
1048
521
|
}
|
|
@@ -1116,13 +589,18 @@ var loadPreload2 = async () => {
|
|
|
1116
589
|
console.error("failed to load preload", e);
|
|
1117
590
|
}
|
|
1118
591
|
};
|
|
592
|
+
var reset = async () => {
|
|
593
|
+
await (await navigator.storage.getDirectory()).remove({ recursive: true });
|
|
594
|
+
console.info("opfs cleared");
|
|
595
|
+
};
|
|
1119
596
|
var mainHandle = makeSyncHandler(self, {
|
|
1120
597
|
initChannel,
|
|
1121
598
|
loadPreload: loadPreload2,
|
|
1122
599
|
readZipEntry,
|
|
1123
600
|
loadBooks,
|
|
1124
601
|
loadBook: loadBook2,
|
|
1125
|
-
configure
|
|
602
|
+
configure,
|
|
603
|
+
reset
|
|
1126
604
|
});
|
|
1127
605
|
var { handler, ...sender } = makeSyncWorker(self, ["nativeWriteFile", "nativeReadFile", "nativeListZips"]);
|
|
1128
606
|
self.onmessage = combineHandlers(mainHandle, handler);
|
package/lib/index.js
CHANGED
|
@@ -31,7 +31,18 @@ var makeSyncWorker = (offlineWorker2, methodNames, dbg) => {
|
|
|
31
31
|
return ({ ports, ...arg } = {}) => {
|
|
32
32
|
return new Promise((resolve, reject) => {
|
|
33
33
|
const eventId = `${methodName}:${Date.now()}-${Math.random().toFixed(5)}`;
|
|
34
|
-
|
|
34
|
+
let resolved = false;
|
|
35
|
+
const timeout = setTimeout(() => {
|
|
36
|
+
console.warn("slow request for", methodName, arg);
|
|
37
|
+
}, 3e3);
|
|
38
|
+
const doResolve = (arg2) => {
|
|
39
|
+
if (!resolved) {
|
|
40
|
+
resolved = true;
|
|
41
|
+
clearTimeout(timeout);
|
|
42
|
+
resolve(arg2);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
dic[eventId] = { resolve: doResolve, reject };
|
|
35
46
|
offlineWorker2.postMessage({ eventId, methodName, arg }, ports);
|
|
36
47
|
});
|
|
37
48
|
};
|
|
@@ -82,13 +93,14 @@ var combineHandlers = (...handlers) => {
|
|
|
82
93
|
console.error("no handlers matched", methodName);
|
|
83
94
|
};
|
|
84
95
|
};
|
|
96
|
+
var clearCache = async (mode) => caches.delete(`LLS_OFFLINE_${mode}`);
|
|
85
97
|
|
|
86
98
|
// src/hooks/useOfflineWorker.ts
|
|
87
99
|
import { useCallback, useEffect, useState } from "react";
|
|
88
100
|
var offlineWorker = new Worker("/src/worker/offline-worker.js", { type: "module" });
|
|
89
101
|
var { handler, ...offlineWorkerSync } = makeSyncWorker(
|
|
90
102
|
offlineWorker,
|
|
91
|
-
["initChannel", "readZipEntry", "configure", "loadPreload", "loadBooks", "loadBook"],
|
|
103
|
+
["initChannel", "readZipEntry", "configure", "loadPreload", "loadBooks", "loadBook", "reset"],
|
|
92
104
|
"app:offlineWorker"
|
|
93
105
|
);
|
|
94
106
|
var fetchWorkerPromise = new Promise(
|
|
@@ -160,6 +172,7 @@ var installWorker = async ({
|
|
|
160
172
|
setBooksLoaded();
|
|
161
173
|
};
|
|
162
174
|
var useOfflineWorker_default = ({
|
|
175
|
+
skipLoadBooks,
|
|
163
176
|
primaryOnly = false,
|
|
164
177
|
nativeReadFile,
|
|
165
178
|
nativeWriteFile,
|
|
@@ -173,6 +186,7 @@ var useOfflineWorker_default = ({
|
|
|
173
186
|
useEffect(() => {
|
|
174
187
|
const fn = async () => {
|
|
175
188
|
await installWorker({
|
|
189
|
+
skipLoadBooks,
|
|
176
190
|
primaryOnly,
|
|
177
191
|
nativeReadFile,
|
|
178
192
|
nativeWriteFile,
|
|
@@ -187,19 +201,69 @@ var useOfflineWorker_default = ({
|
|
|
187
201
|
setReady(true);
|
|
188
202
|
};
|
|
189
203
|
fn();
|
|
190
|
-
}, [
|
|
204
|
+
}, [
|
|
205
|
+
skipLoadBooks,
|
|
206
|
+
primaryOnly,
|
|
207
|
+
nativeReadFile,
|
|
208
|
+
nativeWriteFile,
|
|
209
|
+
nativeListZips,
|
|
210
|
+
storage,
|
|
211
|
+
zipBaseUrl,
|
|
212
|
+
checkUpdates,
|
|
213
|
+
confEnv
|
|
214
|
+
]);
|
|
191
215
|
const loadBook = useCallback(
|
|
192
|
-
async ({
|
|
193
|
-
offlineWorkerSync.on("opfsProgress", cbk);
|
|
194
|
-
return await offlineWorkerSync.loadBook({ id, forceRefresh });
|
|
216
|
+
async ({ forceRefresh, ...idOrUri }, cbk) => {
|
|
217
|
+
cbk && offlineWorkerSync.on("opfsProgress", cbk);
|
|
218
|
+
return await offlineWorkerSync.loadBook({ id: "id" in idOrUri ? idOrUri.id : idOrUri.uri, forceRefresh });
|
|
195
219
|
},
|
|
196
220
|
[]
|
|
197
221
|
);
|
|
222
|
+
const reset = useCallback(async () => {
|
|
223
|
+
await offlineWorkerSync.reset();
|
|
224
|
+
await clearCache(confEnv || "development");
|
|
225
|
+
console.debug("reset: keys:", await caches.keys());
|
|
226
|
+
}, [confEnv]);
|
|
198
227
|
return {
|
|
199
228
|
ready,
|
|
200
|
-
loadBook
|
|
229
|
+
loadBook,
|
|
230
|
+
reset
|
|
201
231
|
};
|
|
202
232
|
};
|
|
233
|
+
|
|
234
|
+
// src/store/index.ts
|
|
235
|
+
import { persistReducer } from "redux-persist";
|
|
236
|
+
var persistEntitiesReducer = (entitiesReducer, CONF_ENV) => {
|
|
237
|
+
const getKey = (key) => `store:${CONF_ENV}:${key}`;
|
|
238
|
+
return persistReducer(
|
|
239
|
+
{
|
|
240
|
+
key: "entities",
|
|
241
|
+
storage: {
|
|
242
|
+
getItem: async (key) => localStorage.getItem(getKey(key)) || "{}",
|
|
243
|
+
setItem: async (key, item) => localStorage.setItem(getKey(key), item),
|
|
244
|
+
removeItem: async (key) => localStorage.removeItem(getKey(key))
|
|
245
|
+
},
|
|
246
|
+
whitelist: ["lexicalFlowers"],
|
|
247
|
+
version: 1,
|
|
248
|
+
debug: true,
|
|
249
|
+
throttle: 1e3
|
|
250
|
+
// lexicalFlowers is small, we may persist it fast
|
|
251
|
+
},
|
|
252
|
+
entitiesReducer
|
|
253
|
+
);
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
// src/store/offlinePersist.tsx
|
|
257
|
+
import { persistStore } from "redux-persist";
|
|
258
|
+
import { PersistGate } from "redux-persist/integration/react";
|
|
259
|
+
import { useMemo } from "react";
|
|
260
|
+
import { jsx } from "react/jsx-runtime";
|
|
261
|
+
var OfflinePersist = ({ store, children }) => {
|
|
262
|
+
const persistor = useMemo(() => persistStore(store), [store]);
|
|
263
|
+
return /* @__PURE__ */ jsx(PersistGate, { loading: null, persistor, children });
|
|
264
|
+
};
|
|
203
265
|
export {
|
|
266
|
+
OfflinePersist,
|
|
267
|
+
persistEntitiesReducer,
|
|
204
268
|
useOfflineWorker_default as useOfflineWorker
|
|
205
269
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lls/offline",
|
|
3
|
-
"version": "24.
|
|
3
|
+
"version": "24.28.0-12ba1b40",
|
|
4
4
|
"description": "offline",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"module": "./lib/index.js",
|
|
@@ -48,14 +48,15 @@
|
|
|
48
48
|
"nock": "14.0.5",
|
|
49
49
|
"react": "18.3.1",
|
|
50
50
|
"react-dom": "18.3.1",
|
|
51
|
+
"redux": "5.0.1",
|
|
51
52
|
"typescript": "5.8.3",
|
|
52
53
|
"vite": "7.0.7",
|
|
53
54
|
"vite-tsconfig-paths": "5.1.4",
|
|
54
55
|
"zod": "3.25.50",
|
|
55
|
-
"@lls/vitescripts": "24.
|
|
56
|
+
"@lls/vitescripts": "24.28.0-12ba1b40"
|
|
56
57
|
},
|
|
57
58
|
"dependencies": {
|
|
58
|
-
"
|
|
59
|
+
"redux-persist": "6.0.0"
|
|
59
60
|
},
|
|
60
61
|
"scripts": {
|
|
61
62
|
"start": "pnpm ladle serve",
|