zip-peek 0.6.1 → 0.6.3-beta.1
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/dist/index.js +145 -6
- package/dist/types.d.ts +6 -1
- package/dist/zip-utils.js +14 -7
- package/dist/zipServiceWorker.js +1 -1
- package/dist/zipServiceWorker.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10,6 +10,16 @@ var zip_utils_2 = require("./zip-utils");
|
|
|
10
10
|
Object.defineProperty(exports, "getPresignedUrlExpiryMs", { enumerable: true, get: function () { return zip_utils_2.getPresignedUrlExpiryMs; } });
|
|
11
11
|
/** Default lead time before presigned URL expiry when scheduling renewal. */
|
|
12
12
|
const URL_EXPIRY_LEAD_MS = 10000;
|
|
13
|
+
/** Retry delay when onUrlExpiry runs but the URL is still tracked (renew failed / skipped). */
|
|
14
|
+
const URL_EXPIRY_RETRY_MS = 5000;
|
|
15
|
+
/** Avoid delayMs=0 tight loops while a renewal is already in flight. */
|
|
16
|
+
const URL_EXPIRY_MIN_DELAY_MS = 1000;
|
|
17
|
+
/** Warn if the service worker does not reply within this window. */
|
|
18
|
+
const WORKER_MESSAGE_HANG_WARN_MS = 5000;
|
|
19
|
+
const logPeek = (step, details) => {
|
|
20
|
+
console.log(`[zip-peek] ${step}`, details ?? "");
|
|
21
|
+
};
|
|
22
|
+
const previewUrl = (url, max = 100) => !url ? url : url.length <= max ? url : `${url.slice(0, max)}…`;
|
|
13
23
|
let currentOnError;
|
|
14
24
|
let currentOnUrlExpiry;
|
|
15
25
|
let clientMessageListenerInstalled = false;
|
|
@@ -20,6 +30,14 @@ const urlExpiryTimers = new Map();
|
|
|
20
30
|
const trackedZipUrls = new Map();
|
|
21
31
|
/** Guard concurrent onUrlExpiry invocations per zip URL. */
|
|
22
32
|
const urlExpiryInFlight = new Set();
|
|
33
|
+
function zipPackagePathname(zipUrl) {
|
|
34
|
+
try {
|
|
35
|
+
return new URL(zipUrl).pathname;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return zipUrl.split("?")[0].split("#")[0];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
23
41
|
const sessionManifests = new Map();
|
|
24
42
|
function normalizeScopePath(href) {
|
|
25
43
|
let p = new URL(href).pathname;
|
|
@@ -125,16 +143,32 @@ function scheduleUrlExpiry(normalizedZipUrl, originalUrlForExpiry) {
|
|
|
125
143
|
clearUrlExpiryTimer(normalizedZipUrl);
|
|
126
144
|
trackedZipUrls.set(normalizedZipUrl, originalUrlForExpiry);
|
|
127
145
|
if (!currentOnUrlExpiry) {
|
|
146
|
+
logPeek("scheduleUrlExpiry skipped: no onUrlExpiry handler", {
|
|
147
|
+
url: previewUrl(normalizedZipUrl),
|
|
148
|
+
});
|
|
128
149
|
return;
|
|
129
150
|
}
|
|
130
151
|
const expiryMs = (0, zip_utils_1.getPresignedUrlExpiryMs)(originalUrlForExpiry);
|
|
131
152
|
if (expiryMs == null) {
|
|
153
|
+
logPeek("scheduleUrlExpiry DROPPED: could not parse expiry (no timer armed)", {
|
|
154
|
+
url: previewUrl(originalUrlForExpiry),
|
|
155
|
+
trackedCount: trackedZipUrls.size,
|
|
156
|
+
});
|
|
132
157
|
trackedZipUrls.delete(normalizedZipUrl);
|
|
133
158
|
return;
|
|
134
159
|
}
|
|
135
|
-
const delayMs = Math.max(
|
|
160
|
+
const delayMs = Math.max(URL_EXPIRY_MIN_DELAY_MS, expiryMs - Date.now() - URL_EXPIRY_LEAD_MS);
|
|
161
|
+
logPeek("scheduleUrlExpiry armed", {
|
|
162
|
+
url: previewUrl(normalizedZipUrl),
|
|
163
|
+
expiryMs,
|
|
164
|
+
delayMs,
|
|
165
|
+
delaySec: Math.round(delayMs / 1000),
|
|
166
|
+
msUntilExpiry: expiryMs - Date.now(),
|
|
167
|
+
trackedCount: trackedZipUrls.size,
|
|
168
|
+
});
|
|
136
169
|
const timerId = setTimeout(() => {
|
|
137
170
|
urlExpiryTimers.delete(normalizedZipUrl);
|
|
171
|
+
logPeek("expiry timer fired", { url: previewUrl(normalizedZipUrl) });
|
|
138
172
|
void invokeUrlExpiry(normalizedZipUrl);
|
|
139
173
|
}, delayMs);
|
|
140
174
|
urlExpiryTimers.set(normalizedZipUrl, timerId);
|
|
@@ -153,8 +187,13 @@ function checkExpiryOnWake() {
|
|
|
153
187
|
if (!currentOnUrlExpiry) {
|
|
154
188
|
return;
|
|
155
189
|
}
|
|
190
|
+
logPeek("checkExpiryOnWake", {
|
|
191
|
+
trackedCount: trackedZipUrls.size,
|
|
192
|
+
visibilityState: typeof document !== "undefined" ? document.visibilityState : "n/a",
|
|
193
|
+
});
|
|
156
194
|
for (const [normalized, original] of trackedZipUrls) {
|
|
157
195
|
if (isZipUrlDueForRenewal(original)) {
|
|
196
|
+
logPeek("checkExpiryOnWake: URL due, invoking expiry", { url: previewUrl(normalized) });
|
|
158
197
|
void invokeUrlExpiry(normalized);
|
|
159
198
|
return;
|
|
160
199
|
}
|
|
@@ -170,19 +209,63 @@ function ensureExpiryWakeListeners() {
|
|
|
170
209
|
window.addEventListener("pageshow", checkExpiryOnWake);
|
|
171
210
|
window.addEventListener("focus", checkExpiryOnWake);
|
|
172
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
* If onUrlExpiry did not replace this URL via renewPresignedUrl, re-arm a timer
|
|
214
|
+
* so renewal is not one-shot when the host renew fails or is skipped.
|
|
215
|
+
*/
|
|
216
|
+
function rearmExpiryIfStillTracked(normalizedZipUrl) {
|
|
217
|
+
const original = trackedZipUrls.get(normalizedZipUrl);
|
|
218
|
+
if (!original) {
|
|
219
|
+
logPeek("rearm skipped: URL no longer tracked (renew likely succeeded)", {
|
|
220
|
+
url: previewUrl(normalizedZipUrl),
|
|
221
|
+
trackedCount: trackedZipUrls.size,
|
|
222
|
+
trackedUrls: Array.from(trackedZipUrls.keys()).map((u) => previewUrl(u)),
|
|
223
|
+
});
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
if (urlExpiryTimers.has(normalizedZipUrl)) {
|
|
227
|
+
logPeek("rearm skipped: timer already armed", { url: previewUrl(normalizedZipUrl) });
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
logPeek("rearm: scheduling retry", {
|
|
231
|
+
url: previewUrl(normalizedZipUrl),
|
|
232
|
+
retryMs: URL_EXPIRY_RETRY_MS,
|
|
233
|
+
});
|
|
234
|
+
const timerId = setTimeout(() => {
|
|
235
|
+
urlExpiryTimers.delete(normalizedZipUrl);
|
|
236
|
+
logPeek("rearm retry timer fired", { url: previewUrl(normalizedZipUrl) });
|
|
237
|
+
void invokeUrlExpiry(normalizedZipUrl);
|
|
238
|
+
}, URL_EXPIRY_RETRY_MS);
|
|
239
|
+
urlExpiryTimers.set(normalizedZipUrl, timerId);
|
|
240
|
+
}
|
|
173
241
|
async function invokeUrlExpiry(normalizedZipUrl) {
|
|
174
|
-
if (!currentOnUrlExpiry
|
|
242
|
+
if (!currentOnUrlExpiry) {
|
|
243
|
+
logPeek("invokeUrlExpiry skipped: no handler");
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (urlExpiryInFlight.has(normalizedZipUrl)) {
|
|
247
|
+
logPeek("invokeUrlExpiry skipped: already in flight", {
|
|
248
|
+
url: previewUrl(normalizedZipUrl),
|
|
249
|
+
inFlight: Array.from(urlExpiryInFlight).map((u) => previewUrl(u)),
|
|
250
|
+
});
|
|
175
251
|
return;
|
|
176
252
|
}
|
|
177
253
|
urlExpiryInFlight.add(normalizedZipUrl);
|
|
254
|
+
logPeek("invokeUrlExpiry calling onUrlExpiry handler", {
|
|
255
|
+
url: previewUrl(normalizedZipUrl),
|
|
256
|
+
original: previewUrl(trackedZipUrls.get(normalizedZipUrl)),
|
|
257
|
+
});
|
|
178
258
|
try {
|
|
179
259
|
await currentOnUrlExpiry();
|
|
260
|
+
logPeek("invokeUrlExpiry handler finished", { url: previewUrl(normalizedZipUrl) });
|
|
180
261
|
}
|
|
181
262
|
catch (error) {
|
|
263
|
+
console.error("[zip-peek] invokeUrlExpiry handler error", error);
|
|
182
264
|
reportZipPeekError(currentOnError, error, "onUrlExpiry handler failed");
|
|
183
265
|
}
|
|
184
266
|
finally {
|
|
185
267
|
urlExpiryInFlight.delete(normalizedZipUrl);
|
|
268
|
+
rearmExpiryIfStillTracked(normalizedZipUrl);
|
|
186
269
|
}
|
|
187
270
|
}
|
|
188
271
|
function ensureClientMessageListener() {
|
|
@@ -239,14 +322,35 @@ function normalizeAllowedZipUrls(allowedZipUrls) {
|
|
|
239
322
|
}
|
|
240
323
|
function postWorkerMessage(message) {
|
|
241
324
|
const controller = navigator.serviceWorker.controller;
|
|
325
|
+
const messageType = message && typeof message === "object" && "type" in message
|
|
326
|
+
? String(message.type)
|
|
327
|
+
: "unknown";
|
|
242
328
|
if (!controller) {
|
|
329
|
+
logPeek("postWorkerMessage rejected: no SW controller", { messageType });
|
|
243
330
|
return Promise.reject((0, types_1.createZipPeekError)("No active service worker controller. Reload the page after first install, or pass reloadOnFirstInstall: true."));
|
|
244
331
|
}
|
|
332
|
+
logPeek("postWorkerMessage sending", {
|
|
333
|
+
messageType,
|
|
334
|
+
controllerScript: controller.scriptURL,
|
|
335
|
+
});
|
|
245
336
|
return new Promise((resolve, reject) => {
|
|
246
337
|
const channel = new MessageChannel();
|
|
338
|
+
const hangTimer = setTimeout(() => {
|
|
339
|
+
console.warn("[zip-peek] postWorkerMessage still waiting for SW reply", {
|
|
340
|
+
messageType,
|
|
341
|
+
waitedMs: WORKER_MESSAGE_HANG_WARN_MS,
|
|
342
|
+
controllerScript: controller.scriptURL,
|
|
343
|
+
});
|
|
344
|
+
}, WORKER_MESSAGE_HANG_WARN_MS);
|
|
247
345
|
channel.port1.onmessage = (event) => {
|
|
346
|
+
clearTimeout(hangTimer);
|
|
248
347
|
const response = event.data;
|
|
249
348
|
channel.port1.close();
|
|
349
|
+
logPeek("postWorkerMessage reply received", {
|
|
350
|
+
messageType,
|
|
351
|
+
ok: response?.ok,
|
|
352
|
+
error: response?.error,
|
|
353
|
+
});
|
|
250
354
|
if (!response || response.ok) {
|
|
251
355
|
resolve();
|
|
252
356
|
}
|
|
@@ -255,7 +359,9 @@ function postWorkerMessage(message) {
|
|
|
255
359
|
}
|
|
256
360
|
};
|
|
257
361
|
channel.port1.onmessageerror = () => {
|
|
362
|
+
clearTimeout(hangTimer);
|
|
258
363
|
channel.port1.close();
|
|
364
|
+
console.error("[zip-peek] postWorkerMessage onmessageerror", { messageType });
|
|
259
365
|
reject((0, types_1.createZipPeekError)("Failed to deserialize the service worker response on MessageChannel."));
|
|
260
366
|
};
|
|
261
367
|
controller.postMessage(message, [channel.port2]);
|
|
@@ -374,27 +480,60 @@ async function initZipPeek({ workerUrl, scopeUrl, reloadOnFirstInstall = true, c
|
|
|
374
480
|
* continue serving assets with the new credentials.
|
|
375
481
|
*/
|
|
376
482
|
async function renewPresignedUrl({ previousUrl, nextUrl }) {
|
|
483
|
+
logPeek("renewPresignedUrl start", {
|
|
484
|
+
previousUrl: previewUrl(previousUrl),
|
|
485
|
+
nextUrl: previewUrl(nextUrl),
|
|
486
|
+
trackedBefore: Array.from(trackedZipUrls.keys()).map((u) => previewUrl(u)),
|
|
487
|
+
});
|
|
377
488
|
if (!("serviceWorker" in navigator)) {
|
|
378
489
|
throw (0, types_1.createZipPeekError)("Service Worker API not supported in this browser.");
|
|
379
490
|
}
|
|
380
|
-
|
|
381
|
-
|
|
491
|
+
// Prefer the host-provided absolute strings as-is so SigV4 query encoding is
|
|
492
|
+
// preserved; only resolve relative URLs against the page location.
|
|
493
|
+
const resolvedPrevious = /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(previousUrl)
|
|
494
|
+
? previousUrl
|
|
495
|
+
: new URL(previousUrl, window.location.href).href;
|
|
496
|
+
const resolvedNext = /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(nextUrl)
|
|
497
|
+
? nextUrl
|
|
498
|
+
: new URL(nextUrl, window.location.href).href;
|
|
382
499
|
if (!(0, zip_utils_1.isZipPackage)(resolvedPrevious) || !(0, zip_utils_1.isZipPackage)(resolvedNext)) {
|
|
383
500
|
throw (0, types_1.createZipPeekError)("renewPresignedUrl requires both previousUrl and nextUrl to be ZIP package URLs.");
|
|
384
501
|
}
|
|
385
502
|
const previous = (0, zip_utils_1.normalizeZipUrl)(resolvedPrevious);
|
|
386
503
|
const next = (0, zip_utils_1.normalizeZipUrl)(resolvedNext);
|
|
504
|
+
logPeek("renewPresignedUrl normalized", {
|
|
505
|
+
previous: previewUrl(previous),
|
|
506
|
+
next: previewUrl(next),
|
|
507
|
+
sameUrl: previous === next,
|
|
508
|
+
nextExpiryMs: (0, zip_utils_1.getPresignedUrlExpiryMs)(resolvedNext),
|
|
509
|
+
});
|
|
510
|
+
logPeek("renewPresignedUrl awaiting SW RENEW_ZIP_URL...");
|
|
387
511
|
await postWorkerMessageOrThrow({
|
|
388
512
|
type: "RENEW_ZIP_URL",
|
|
389
513
|
previousUrl: previous,
|
|
390
514
|
nextUrl: next,
|
|
391
515
|
}, "Failed to renew ZIP URL in service worker");
|
|
516
|
+
logPeek("renewPresignedUrl SW RENEW_ZIP_URL done");
|
|
392
517
|
const files = sessionManifests.get(previous);
|
|
393
518
|
if (files) {
|
|
394
519
|
sessionManifests.set(next, files);
|
|
395
520
|
sessionManifests.delete(previous);
|
|
396
521
|
}
|
|
397
|
-
|
|
398
|
-
|
|
522
|
+
// Drop the previous URL and any orphaned tracked URLs for the same zip path
|
|
523
|
+
// (e.g. when a prior renew used a mismatched previousUrl and left a timer-less entry).
|
|
524
|
+
const nextPath = zipPackagePathname(next);
|
|
525
|
+
const removed = [];
|
|
526
|
+
for (const [normalized] of [...trackedZipUrls]) {
|
|
527
|
+
if (normalized === previous || zipPackagePathname(normalized) === nextPath) {
|
|
528
|
+
trackedZipUrls.delete(normalized);
|
|
529
|
+
clearUrlExpiryTimer(normalized);
|
|
530
|
+
removed.push(previewUrl(normalized) ?? normalized);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
logPeek("renewPresignedUrl cleared tracked URLs", { removed, nextPath });
|
|
399
534
|
scheduleUrlExpiry(next, resolvedNext);
|
|
535
|
+
logPeek("renewPresignedUrl complete", {
|
|
536
|
+
trackedAfter: Array.from(trackedZipUrls.keys()).map((u) => previewUrl(u)),
|
|
537
|
+
timersArmed: urlExpiryTimers.size,
|
|
538
|
+
});
|
|
400
539
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -5,6 +5,9 @@ export type ZipWorkerConfig = {
|
|
|
5
5
|
};
|
|
6
6
|
export type ZipCacheClearingStrategy = 'keep-all' | 'keep-allowed-urls' | 'clear-all';
|
|
7
7
|
export type ZipPeekErrorHandler = (error: Error, info?: string) => void;
|
|
8
|
+
/**
|
|
9
|
+
* Invoked shortly before a tracked presigned ZIP URL expires.
|
|
10
|
+
*/
|
|
8
11
|
export type ZipPeekUrlExpiryHandler = () => void | Promise<void>;
|
|
9
12
|
export type RenewPresignedUrlOptions = {
|
|
10
13
|
previousUrl: string;
|
|
@@ -25,7 +28,9 @@ export type InitZipPeekOptions = {
|
|
|
25
28
|
* Called shortly before a recognized presigned URL expires (CloudFront
|
|
26
29
|
* `Expires` or S3 `X-Amz-Date` + `X-Amz-Expires`). Also invoked after tab
|
|
27
30
|
* wake when a timer was missed due to sleep or background throttling.
|
|
28
|
-
* Not scheduled for non-presigned ZIP URLs.
|
|
31
|
+
* Not scheduled for non-presigned ZIP URLs. If the handler does not call
|
|
32
|
+
* `renewPresignedUrl`, zip-peek re-arms a retry timer so renewal is not
|
|
33
|
+
* one-shot.
|
|
29
34
|
*/
|
|
30
35
|
onUrlExpiry?: ZipPeekUrlExpiryHandler;
|
|
31
36
|
};
|
package/dist/zip-utils.js
CHANGED
|
@@ -120,8 +120,15 @@ function canonicalZipAssetRequestUrl(zipUrl, manifestKey) {
|
|
|
120
120
|
/**
|
|
121
121
|
* Read a raw query param value without `URLSearchParams` so SigV4 `%2F`
|
|
122
122
|
* credentials are not re-encoded.
|
|
123
|
+
*
|
|
124
|
+
* When `stopAtPathSeparator` is true (default), stops at the first raw `/` so
|
|
125
|
+
* presigned asset URLs (`pkg.zip?sig…/asset.png`) only parse the signed query.
|
|
126
|
+
* Bare package URLs used for expiry parsing should pass `false` so a decoded
|
|
127
|
+
* `/` inside SigV4 values (e.g. `X-Amz-Credential`) cannot truncate
|
|
128
|
+
* `X-Amz-Date` / `X-Amz-Expires`.
|
|
123
129
|
*/
|
|
124
|
-
function getRawQueryParam(urlString, name) {
|
|
130
|
+
function getRawQueryParam(urlString, name, options = {}) {
|
|
131
|
+
const { stopAtPathSeparator = true } = options;
|
|
125
132
|
const qIdx = urlString.indexOf("?");
|
|
126
133
|
if (qIdx === -1)
|
|
127
134
|
return null;
|
|
@@ -129,9 +136,7 @@ function getRawQueryParam(urlString, name) {
|
|
|
129
136
|
const querySection = hashIdx === -1
|
|
130
137
|
? urlString.substring(qIdx + 1)
|
|
131
138
|
: urlString.substring(qIdx + 1, hashIdx);
|
|
132
|
-
|
|
133
|
-
// (`pkg.zip?sig…/asset.png`). Stop at the first raw `/`.
|
|
134
|
-
const slashIdx = querySection.indexOf("/");
|
|
139
|
+
const slashIdx = stopAtPathSeparator ? querySection.indexOf("/") : -1;
|
|
135
140
|
const signedQuery = slashIdx === -1 ? querySection : querySection.substring(0, slashIdx);
|
|
136
141
|
for (const part of signedQuery.split("&")) {
|
|
137
142
|
const eqIdx = part.indexOf("=");
|
|
@@ -148,15 +153,17 @@ function getRawQueryParam(urlString, name) {
|
|
|
148
153
|
* as a time-limited presigned URL.
|
|
149
154
|
*/
|
|
150
155
|
function getPresignedUrlExpiryMs(url) {
|
|
151
|
-
|
|
156
|
+
// Bare package URLs only — do not truncate at `/` (SigV4 values may contain it).
|
|
157
|
+
const param = (name) => getRawQueryParam(url, name, { stopAtPathSeparator: false });
|
|
158
|
+
const expiresRaw = param("Expires");
|
|
152
159
|
if (expiresRaw != null && expiresRaw !== "") {
|
|
153
160
|
const expiresSec = Number(expiresRaw);
|
|
154
161
|
if (Number.isFinite(expiresSec) && expiresSec > 0) {
|
|
155
162
|
return expiresSec * 1000;
|
|
156
163
|
}
|
|
157
164
|
}
|
|
158
|
-
const amzDate =
|
|
159
|
-
const amzExpires =
|
|
165
|
+
const amzDate = param("X-Amz-Date");
|
|
166
|
+
const amzExpires = param("X-Amz-Expires");
|
|
160
167
|
if (amzDate && amzExpires) {
|
|
161
168
|
// X-Amz-Date is YYYYMMDD'T'HHMMSS'Z'
|
|
162
169
|
const match = /^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})Z$/.exec(amzDate);
|
package/dist/zipServiceWorker.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(()=>{"use strict";var e={553(e,t){function n(e){const n=e.trim();return n.startsWith(t.ZIP_PEEK_ERROR_PREFIX)?n:`${t.ZIP_PEEK_ERROR_PREFIX} ${n}`}t.ZIP_PEEK_ERROR_PREFIX=void 0,t.formatZipPeekError=n,t.createZipPeekError=function(e){return new Error(n(e))},t.toZipPeekError=function(e){const r=e instanceof Error?e:new Error(String(e));return r.message.startsWith(t.ZIP_PEEK_ERROR_PREFIX)||(r.message=n(r.message)),r},t.errorMessage=function(e){return e instanceof Error?e.message:String(e)},t.ZIP_PEEK_ERROR_PREFIX="[zip-peek-error]"},314(e,t,n){t.persistAllowedZipUrlsConfig=a,t.ensureAllowedZipUrlsLoaded=async function(){if(i.allowedZipUrlsLoaded)return i.allowedZipUrlsLoaded;const e=(async()=>{try{const e=await caches.open(i.CONFIG_CACHE_NAME),t=await e.match(i.CONFIG_CACHE_KEY);if(!t)return;const n=await t.json();Array.isArray(n.allowedZipUrls)?(0,i.setAllowedZipUrls)(new Set(n.allowedZipUrls.filter(e=>"string"==typeof e).map(e=>(0,r.normalizeZipUrl)(e)))):(0,i.setAllowedZipUrls)(null)}catch(e){(0,s.warn)("failed to load runtime config",e)}})();return(0,i.setAllowedZipUrlsLoaded)(e),e},t.applyRuntimeConfig=async function(e){if(!e)return;let t={...i.runtimeConfig},n=!1;if("string"==typeof e.zipAssetCacheName&&e.zipAssetCacheName.trim()&&(t.zipAssetCacheName=e.zipAssetCacheName,n=!0),"number"==typeof e.assetCacheTtlMs&&Number.isFinite(e.assetCacheTtlMs)&&(t.assetCacheTtlMs=e.assetCacheTtlMs,n=!0),"string"==typeof e.logPrefix&&e.logPrefix.trim()&&(t.logPrefix=e.logPrefix,n=!0),"boolean"==typeof e.requireExactManifestPath&&(t.requireExactManifestPath=e.requireExactManifestPath,n=!0),n&&(0,i.setRuntimeConfig)(t),"allowedZipUrls"in e){const t=Array.isArray(e.allowedZipUrls)?e.allowedZipUrls.map(e=>(0,r.normalizeZipUrl)(e)):null;(0,i.setAllowedZipUrls)(t?new Set(t):null),(0,i.setAllowedZipUrlsLoaded)(Promise.resolve()),await a(t)}},t.isZipUrlAllowed=function(e){return null===i.allowedZipUrls||i.allowedZipUrls.has(e)};const r=n(343),i=n(262),s=n(266);async function a(e){try{const t=await caches.open(i.CONFIG_CACHE_NAME);await t.put(new Request(i.CONFIG_CACHE_KEY),new Response(JSON.stringify({allowedZipUrls:e}),{headers:{"Content-Type":"application/json"}}))}catch(e){(0,s.warn)("failed to persist runtime config",e)}}},800(e,t,n){t.canonicalAssetRequest=function(e,t){return new Request((0,i.canonicalZipAssetRequestUrl)(e,t),{method:"GET"})},t.clearAllZipAssets=async function(){const e=await caches.open(a.runtimeConfig.zipAssetCacheName),t=await e.keys();await Promise.all(t.map(t=>e.delete(t))),await caches.delete(a.CONFIG_CACHE_NAME),a.zipManifests.clear(),a.pendingManifestLoads.clear(),(0,a.setAllowedZipUrlsLoaded)(Promise.resolve())},t.clearZipAssetsExceptAllowed=async function(e){try{const t=new Set(e),n=await caches.open(a.runtimeConfig.zipAssetCacheName),r=await n.keys();for(const e of r){const r=e.url;if(r.includes(a.MANIFEST_CACHE_KEY)){const i=(0,l.zipUrlFromManifestCacheKey)(r);i&&!t.has(i)&&await n.delete(e);continue}const s=(0,i.parseZipAssetRequest)(r);s&&!t.has(s.zipUrl)&&await n.delete(e)}for(const e of a.zipManifests.keys())t.has(e)||a.zipManifests.delete(e)}catch(e){throw(0,r.createZipPeekError)(`Failed to clear zip assets except allowed URLs: ${(0,r.errorMessage)(e)}`)}},t.putCachedFullAssetIfAbsent=async function(e,t){try{const n=await caches.open(a.runtimeConfig.zipAssetCacheName),r=await n.match(e);if(r&&!c(r))return;const i=t.type||"application/octet-stream";await n.put(e,new Response(t,{status:200,headers:{"Content-Type":i,"Content-Length":String(t.size),"Access-Control-Allow-Origin":"*",[a.ASSET_CACHED_AT_HEADER]:String(Date.now())}}))}catch(e){(0,o.warn)("asset cache put failed",e)}},t.readCachedZipAssetIfFresh=async function(e){let t=null,n="network";try{const r=await caches.open(a.runtimeConfig.zipAssetCacheName),i=await r.match(e);if(i)if(c(i))try{await r.delete(e)}catch(e){(0,o.warn)("asset cache delete expired failed",e)}else t=await i.blob(),n="cache-api"}catch(e){(0,o.warn)("asset cache read failed",e)}return{blob:t,assetSource:n}},t.renewZipUrl=async function(e,t){const n=(0,i.normalizeZipUrl)(e),o=(0,i.normalizeZipUrl)(t);if(n===o)return;if(a.allowedZipUrls){const e=new Set(a.allowedZipUrls);e.delete(n),e.add(o),(0,a.setAllowedZipUrls)(e),(0,a.setAllowedZipUrlsLoaded)(Promise.resolve()),await(0,s.persistAllowedZipUrlsConfig)(Array.from(e))}const c=a.zipManifests.get(n);c&&(a.zipManifests.set(o,c),a.zipManifests.delete(n));const f=a.pendingManifestLoads.get(n);f&&(a.pendingManifestLoads.set(o,f),a.pendingManifestLoads.delete(n));try{const e=await caches.open(a.runtimeConfig.zipAssetCacheName),t=await e.keys();for(const r of t){const t=r.url;if(t.includes(a.MANIFEST_CACHE_KEY)){(0,l.zipUrlFromManifestCacheKey)(t)===n&&await e.delete(r);continue}const s=(0,i.parseZipAssetRequest)(t);s&&(0,i.normalizeZipUrl)(s.zipUrl)===n&&await e.delete(r)}}catch(e){throw(0,r.createZipPeekError)(`Failed to clear cached assets for renewed ZIP URL: ${(0,r.errorMessage)(e)}`)}};const r=n(553),i=n(343),s=n(314),a=n(262),o=n(266),l=n(346);function c(e){const t=e.headers.get(a.ASSET_CACHED_AT_HEADER);if(!t)return!0;const n=parseInt(t,10);return!Number.isFinite(n)||Date.now()-n>a.runtimeConfig.assetCacheTtlMs}},982(e,t,n){t.installFetchHandler=function(){self.addEventListener("fetch",e=>{const t=e.request.method;if("GET"!==t&&"HEAD"!==t)return;const n="HEAD"===t,d=(0,i.parseZipAssetRequest)(e.request.url);if(!d)return;const m=(0,i.normalizeZipUrl)(d.zipUrl),g=d.internalPath,w=(0,i.normalizeZipEntryPath)(g);e.respondWith((async()=>{try{if(await(0,s.ensureAllowedZipUrlsLoaded)(),!(0,s.isZipUrlAllowed)(m))return(0,l.warn)("zip URL not allowed",{requestedZipUrl:m}),(0,f.corsErrorResponse)(`ZIP URL not allowed (not in allowedZipUrls): ${m}`,403);let t=o.zipManifests.get(m);if(t||(t=await(0,c.ensureManifestAvailable)(m,e.clientId||void 0)??void 0),!t){const e=Array.from(o.zipManifests.keys());return(0,l.warn)("manifest missing for zipUrl",{requestedZipUrl:m,knownZipUrls:e}),(0,f.corsErrorResponse)(`ZIP manifest not loaded for ${m}. Ensure the ZIP is reachable and supports byte-range requests.`,404)}const i=(0,c.resolveManifestEntry)(t,w,m,o.runtimeConfig.requireExactManifestPath);if(!i){const e=Array.from(t.keys()).slice(0,50);return(0,l.warn)("file not in manifest",{zipUrl:m,internalPathRaw:g,internalPathNormalized:w,requireExactManifestPath:o.runtimeConfig.requireExactManifestPath,manifestSize:t.size,sampleKeys:e}),(0,f.corsErrorResponse)(`File "${g}" not found in ZIP manifest for ${m}`,404)}const{key:d,info:h,matchKind:E}=i;"zipBasenameFallback"===E&&((0,l.log)("resolved via zip-basename folder fallback",{requested:w,manifestKey:d}),(0,l.reportClientError)(new Error((0,r.formatZipPeekError)("Exact manifest path not found; resolved via zip-basename folder fallback")),`Exact manifest key "${w}" not found in ${m}; resolved using "${d}"`));const A=(0,a.canonicalAssetRequest)(m,d);if(n)return function(e,t,n){const r=(0,f.getMimeType)(t),i=(0,c.entryUncompressedSize)(n),s=e.headers.get("range");if(null!==i&&s)return u(null,r,i,"manifest",s);const a={"Content-Type":r,...p("manifest")};return null!==i&&(a["Content-Length"]=i.toString()),new Response(null,{status:200,headers:a})}(e.request,d,h);let{blob:y,assetSource:C}=await(0,a.readCachedZipAssetIfFresh)(A);if(!y){const e=await(0,f.fetchUncompressedZipEntryFromNetwork)(m,d,h,A);if(!e.ok)return e.response;y=e.blob,C="network"}return u(y,y.type,y.size,C,e.request.headers.get("range"))}catch(e){return(0,l.error)("fetch handler failed",{zipUrl:m,internalPath:g,message:(0,r.errorMessage)(e)}),(0,f.corsErrorResponse)(`Failed to serve "${g}" from ${m}: ${(0,r.errorMessage)(e)}`,500)}})())})};const r=n(553),i=n(343),s=n(314),a=n(800),o=n(262),l=n(266),c=n(346),f=n(254);function p(e){return{"Access-Control-Allow-Origin":"*","Access-Control-Expose-Headers":o.ASSET_SOURCE_HEADER,[o.ASSET_SOURCE_HEADER]:e}}function u(e,t,n,r,i){if(i){const s=i.replace(/^bytes=/,"");if(s.includes(","))return new Response(null,{status:416,headers:{"Content-Range":`bytes */${n}`,...p(r)}});const[a,o]=s.split("-"),l=""!==a?parseInt(a,10):NaN,c=""!==o?parseInt(o,10):n-1;if(isNaN(l)||isNaN(c)||l<0||c<l||l>=n)return new Response(null,{status:416,headers:{"Content-Range":`bytes */${n}`,...p(r)}});const f=Math.min(c,n-1),u=f-l+1,d=null===e?null:e.slice(l,f+1);return new Response(d,{status:206,headers:{"Content-Type":t,"Content-Range":`bytes ${l}-${f}/${n}`,"Content-Length":u.toString(),"Accept-Ranges":"bytes",...p(r)}})}return new Response(e,{status:200,headers:{"Content-Type":t,"Content-Length":n.toString(),...p(r)}})}},262(e,t){t.CONFIG_CACHE_KEY=t.allowedZipUrlsLoaded=t.allowedZipUrls=t.runtimeConfig=t.pendingManifestLoads=t.zipManifests=t.MANIFEST_CACHE_KEY=t.LOCAL_FILE_HEADER_SIG=t.MIME_TYPES=t.ASSET_SOURCE_HEADER=t.ASSET_CACHED_AT_HEADER=t.CONFIG_CACHE_NAME=t.kF=t.o2=void 0,t.setRuntimeConfig=function(e){t.runtimeConfig=e},t.setAllowedZipUrls=function(e){t.allowedZipUrls=e},t.setAllowedZipUrlsLoaded=function(e){t.allowedZipUrlsLoaded=e},t.o2="zip-cache-v1",t.kF=72e5,t.CONFIG_CACHE_NAME="zip-peek-config-v1",t.o2,t.CONFIG_CACHE_NAME,t.ASSET_CACHED_AT_HEADER="X-ZipSW-Cached-At",t.ASSET_SOURCE_HEADER="X-ZipSW-Asset-Source",t.MIME_TYPES={png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",webp:"image/webp",svg:"image/svg+xml",json:"application/json",js:"application/javascript",css:"text/css; charset=utf-8",html:"text/html; charset=utf-8",txt:"text/plain; charset=utf-8",mp4:"video/mp4",webm:"video/webm",mp3:"audio/mpeg",wav:"audio/wav",oga:"audio/ogg",ogg:"audio/ogg",xml:"application/xml",wasm:"application/wasm"},t.LOCAL_FILE_HEADER_SIG=67324752,t.MANIFEST_CACHE_KEY="__zipsw_manifest__=1",t.zipManifests=new Map,t.pendingManifestLoads=new Map,t.runtimeConfig={zipAssetCacheName:t.o2,assetCacheTtlMs:t.kF,logPrefix:"[zipSW]",requireExactManifestPath:!1},t.allowedZipUrls=null,t.allowedZipUrlsLoaded=null,t.CONFIG_CACHE_KEY=new URL("__zip_peek_runtime_config__",self.registration.scope).href},266(e,t,n){t.log=function(...e){console.log(i.runtimeConfig.logPrefix,...e)},t.warn=function(...e){console.warn(i.runtimeConfig.logPrefix,...e)},t.error=function(...e){console.error(i.runtimeConfig.logPrefix,r.ZIP_PEEK_ERROR_PREFIX,...e)},t.reportClientError=s,t.installClientErrorReporting=function(){self.addEventListener("error",e=>{s(e.error??e.message,"Service worker uncaught error")}),self.addEventListener("unhandledrejection",e=>{s(e.reason,"Service worker unhandled promise rejection")})};const r=n(553),i=n(262);function s(e,t){const n=(0,r.toZipPeekError)(e);self.clients.matchAll({type:"window",includeUncontrolled:!0}).then(e=>{const i={type:"ZIP_SW_ERROR",error:{message:n.message,stack:n.stack},info:t?(0,r.formatZipPeekError)(t):void 0};for(const t of e)t.postMessage(i)})}},346(e,t,n){t.manifestFilesToMap=a,t.sendManifestToClientId=l,t.ensureManifestAvailable=function(e,t){const n=i.zipManifests.get(e);if(n)return Promise.resolve(n);let c=i.pendingManifestLoads.get(e);return c||(c=(async()=>{const n=await async function(e,t){const n=await o(t);return n?function(e,t){return new Promise(n=>{const r=new MessageChannel,i=setTimeout(()=>{r.port1.close(),n(null)},500);r.port1.onmessage=e=>{clearTimeout(i),r.port1.close();const t=e.data;t?.ok&&Array.isArray(t.files)?n(a(t.files)):n(null)},r.port1.onmessageerror=()=>{clearTimeout(i),r.port1.close(),n(null)};try{e.postMessage({type:"ZIP_SW_MANIFEST_REQUEST",zipUrl:t},[r.port2])}catch(e){clearTimeout(i),r.port1.close(),(0,s.warn)("failed to request manifest from client",e),n(null)}})}(n,e):null}(e,t);if(n)return i.zipManifests.set(e,n),(0,s.log)("restored manifest from client memory",{zipUrl:e,entryCount:n.size}),n;const c=await async function(e){const t=await fetch(e,{headers:{Range:"bytes=-65536"}});if(206!==t.status)return(0,s.error)("range requests not supported for ZIP manifest",{zipUrl:e,status:t.status}),null;const n=await t.arrayBuffer(),i=new DataView(n);let a=-1;for(let e=n.byteLength-22;e>=0;e--)if(101010256===i.getUint32(e,!0)){a=e;break}if(-1===a)return(0,s.error)("EOCD not found in last 64KB of ZIP file",e),null;const o=i.getUint32(a+16,!0),l=i.getUint32(a+12,!0);let c=n,f=-1;const p=t.headers.get("Content-Range");let u=0;if(p){const e=p.match(/\/(\d+)$/);e&&(u=parseInt(e[1],10))}if(u<=0)return(0,s.error)("could not determine ZIP file size from Content-Range header",{zipUrl:e,contentRange:p}),null;const d=u-n.byteLength;if(o>=d)f=o-d;else{const t=await fetch(e,{headers:{Range:`bytes=${o}-${o+l-1}`}});if(206!==t.status)return(0,s.error)("failed to fetch ZIP central directory",{zipUrl:e,status:t.status,cdOffset:o,cdSize:l}),null;c=await t.arrayBuffer(),f=0}return function(e,t,n,i){const a=new DataView(e);let o=t;const l=[];for(;o+46<=e.byteLength&&33639248===a.getUint32(o,!0);){const t=a.getUint16(o+10,!0),n=a.getUint32(o+20,!0),i=a.getUint32(o+24,!0),s=a.getUint16(o+28,!0),c=a.getUint16(o+30,!0),f=a.getUint16(o+32,!0),p=a.getUint32(o+42,!0),u=new TextDecoder;if(o+46+s>e.byteLength)break;const d=new Uint8Array(e,o+46,s),m=u.decode(d),g=(0,r.normalizeZipEntryPath)(m);""!==g&&l.push({filename:g,offset:p,compressedSize:n,uncompressedSize:i,compression:t}),o+=46+s+c+f}if(0===l.length)return(0,s.error)("no files parsed from central directory",i),null;l.sort((e,t)=>e.offset-t.offset);const c=new Map;for(let e=0;e<l.length;e++){const t=l[e],i=(0,r.normalizeZipEntryPath)(t.filename);""!==i&&(c.has(i)&&(0,s.warn)("duplicate manifest key after normalize; overwriting",i),c.set(i,{filename:t.filename,offset:t.offset,compressedSize:t.compressedSize,uncompressedSize:t.uncompressedSize,compression:t.compression,nextOffset:e<l.length-1?l[e+1].offset:n}))}return c.size>0?c:null}(c,f,o,e)}(e);return c&&(i.zipManifests.set(e,c),await l(e,c,t),(0,s.log)("manifest fetched and stored in memory",{zipUrl:e,entryCount:c.size})),c})().finally(()=>{i.pendingManifestLoads.delete(e)}),i.pendingManifestLoads.set(e,c),c)},t.entryUncompressedSize=function(e){return void 0!==e.uncompressedSize?e.uncompressedSize:0===e.compression?e.compressedSize:null},t.resolveManifestEntry=function(e,t,n,i){if(e.has(t))return{key:t,info:e.get(t),matchKind:"exact"};if(i)return null;const s=(0,r.zipBasenameWithoutExtension)(n);if(!s)return null;const a=`${s}/${t}`;return e.has(a)?{key:a,info:e.get(a),matchKind:"zipBasenameFallback"}:null},t.zipUrlFromManifestCacheKey=function(e){const t=i.MANIFEST_CACHE_KEY;if(!e.endsWith(t))return null;let n=e.slice(0,-t.length);return(n.endsWith("?")||n.endsWith("&"))&&(n=n.slice(0,-1)),n};const r=n(343),i=n(262),s=n(266);function a(e){const t=new Map;for(const n of e){const e=(0,r.normalizeZipEntryPath)(n.filename);""!==e&&(t.has(e)&&(0,s.warn)("duplicate manifest key after normalize; overwriting",e),t.set(e,n))}return t.size>0?t:null}async function o(e){if(!e)return null;const t=await self.clients.get(e);return"window"===t?.type?t:null}async function l(e,t,n){const r=await o(n);if(!r)return;const i=Array.from(t.values());try{r.postMessage({type:"ZIP_SW_MANIFEST_CREATED",zipUrl:e,files:i})}catch(e){(0,s.warn)("failed to send manifest to client",e)}}},993(e,t,n){t.installMessageHandler=function(){self.addEventListener("message",e=>{if(!e.data)return;const{type:t,zipUrl:n,files:u,config:d,allowedZipUrls:m,previousUrl:g,nextUrl:w}=e.data,h=function(e){if(!e||!("id"in e))return;const t=e.id;return"string"==typeof t?t:void 0}(e.source);if("ZIP_SW_CONFIG"===t){const t=(0,s.applyRuntimeConfig)(d).then(()=>p(e,{ok:!0})).catch(t=>p(e,f(t)));return void e.waitUntil(t)}if("ZIP_MANIFEST"===t){if(n&&u){const t=(0,i.normalizeZipUrl)(n),r=(0,c.manifestFilesToMap)(u),s=o.zipManifests.get(t);if(!r)return void(0,l.warn)("rejecting empty manifest; keeping existing",{zipUrl:t,existingSize:s?s.size:0});if(s&&s.size>r.size)return void(0,l.warn)("rejecting smaller manifest; keeping existing",{zipUrl:t,incomingSize:r.size,existingSize:s.size});o.zipManifests.set(t,r),e.waitUntil((0,c.sendManifestToClientId)(t,r,h));const a=Array.from(r.keys()).slice(0,40);(0,l.log)("ZIP_MANIFEST loaded",{zipUrl:t,entryCount:r.size,sampleKeys:a,replacedExistingSize:s?s.size:0})}}else if("CLEAR_ZIP_ASSETS_EXCEPT_ALLOWED"===t&&m){const t=(0,a.clearZipAssetsExceptAllowed)(m).then(()=>p(e,{ok:!0})).catch(t=>p(e,f(t)));e.waitUntil(t)}else if("CLEAR_ALL_ZIP_ASSETS"===t){const t=(0,a.clearAllZipAssets)().then(()=>p(e,{ok:!0})).catch(t=>p(e,f(t)));e.waitUntil(t)}else if("PRELOAD_ZIP_MANIFESTS"===t&&m){const t=async function(e,t){const n=await Promise.all(e.map(async e=>({zipUrl:e,manifest:await(0,c.ensureManifestAvailable)(e,t)}))),i=n.filter(e=>!e.manifest).map(e=>e.zipUrl);if(i.length>0)throw(0,r.createZipPeekError)(`Failed to preload ZIP manifest(s): ${i.join(", ")}`)}(m,h).then(()=>p(e,{ok:!0})).catch(t=>p(e,f(t)));e.waitUntil(t)}else if("RENEW_ZIP_URL"===t&&g&&w){const t=(0,a.renewZipUrl)(g,w).then(()=>p(e,{ok:!0})).catch(t=>p(e,f(t)));e.waitUntil(t)}})};const r=n(553),i=n(343),s=n(314),a=n(800),o=n(262),l=n(266),c=n(346);function f(e){const t=(0,r.toZipPeekError)(e);return{ok:!1,error:t.message,errorStack:t.stack}}function p(e,t){e.ports[0]?.postMessage(t)}},254(e,t,n){t.corsErrorResponse=l,t.getMimeType=c,t.fetchUncompressedZipEntryFromNetwork=async function(e,t,n,i){const f=n.offset,p=n.nextOffset-1;(0,a.log)("fetching zip chunk from",{zipUrl:e,rangeStart:f,rangeEnd:p});const u=await fetch(e,{headers:{Range:`bytes=${f}-${p}`}});if(206!==u.status)return{ok:!1,response:l(`ZIP entry fetch for "${t}" expected HTTP 206 Partial Content from ${e}, got ${u.status}`,u.status>=400?u.status:502)};const d=await u.arrayBuffer(),m=new DataView(d);if(m.getUint32(0,!0)!==s.LOCAL_FILE_HEADER_SIG)return{ok:!1,response:l(`Invalid local file header for "${t}" in ${e} (expected ZIP signature 0x04034b50)`,500)};const g=30+m.getUint16(26,!0)+m.getUint16(28,!0);if(g>d.byteLength||g+n.compressedSize>d.byteLength)return{ok:!1,response:l(`Corrupt ZIP entry "${t}" in ${e}: dataStart=${g}, compressedSize=${n.compressedSize}, bufferLength=${d.byteLength}`,500)};const w=new Uint8Array(d,g,n.compressedSize);let h;if(8===n.compression)try{h=(0,r.inflateSync)(w)}catch(n){return(0,a.warn)("inflateSync failed",{zipUrl:e,manifestKey:t,error:n}),{ok:!1,response:l(`Failed to inflate DEFLATE-compressed entry "${t}" in ${e}`,500)}}else{if(0!==n.compression)return{ok:!1,response:l(`Unsupported compression method ${n.compression} for "${t}" in ${e} (only stored/0 and DEFLATE/8 are supported)`,500)};h=w}const E=c(t),A=new Blob([h],{type:E});return await(0,o.putCachedFullAssetIfAbsent)(i,A),{ok:!0,blob:A}};const r=n(612),i=n(553),s=n(262),a=n(266),o=n(800);function l(e,t){return new Response((0,i.formatZipPeekError)(e),{status:t,headers:{"Access-Control-Allow-Origin":"*"}})}function c(e){const t=e.split(".").pop()?.toLowerCase();return t?s.MIME_TYPES[t]??"application/octet-stream":"application/octet-stream"}},343(e,t){function n(e){try{return decodeURIComponent(e)}catch{return e}}t.normalizeZipUrl=function(e,t={}){const{stripCacheBuster:n=!0,stripHash:r=!0}=t,i=e=>r?e.split("#")[0]:e;if(!n)return i(e);const s=e.indexOf("?");if(-1===s)return i(e);const a=e.indexOf("#",s),o=e.substring(0,s),l=-1===a?e.substring(s+1):e.substring(s+1,a),c=r||-1===a?"":e.substring(a),f=l.split("&").filter(e=>{const t=e.indexOf("=");return"t"!==(-1===t?e:e.substring(0,t))});return 0===f.length?o+c:o+"?"+f.join("&")+c},t.zipBasenameWithoutExtension=function(e){try{const t=new URL(e,"http://local").pathname.split("/").pop()??"";return t.endsWith(".zip")?t.slice(0,-4):t}catch{const t=e.split("?")[0].split("#")[0].split("/").pop()??"";return t.endsWith(".zip")?t.slice(0,-4):t}},t.normalizeZipEntryPath=function(e){let t=e.replace(/\\/g,"/");for(;t.startsWith("/");)t=t.slice(1);return t},t.parseZipAssetRequest=function(e){const t=/\.zip([/?])/.exec(e);if(!t)return null;const r=t.index+4,i=t[1],s=e.substring(0,r);if("/"===i){const t=e.substring(r+1),i=t.indexOf("?"),a=-1===i?t:t.substring(0,i);return""===a?null:{zipUrl:s,internalPath:n(a)}}const a=e.substring(r),o=a.indexOf("/");if(-1===o)return null;const l=a.substring(0,o),c=a.substring(o+1),f=c.indexOf("?"),p=-1===f?c:c.substring(0,f);return""===p?null:{zipUrl:s+l,internalPath:n(p)}},t.canonicalZipAssetRequestUrl=function(e,t){return e+"/"+encodeURIComponent(t)}},612(e,t){t.inflateSync=b;var n=Uint8Array,r=Uint16Array,i=Int32Array,s=new n([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0,0]),a=new n([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,0,0]),o=new n([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]),l=function(e,t){for(var n=new r(31),s=0;s<31;++s)n[s]=t+=1<<e[s-1];var a=new i(n[30]);for(s=1;s<30;++s)for(var o=n[s];o<n[s+1];++o)a[o]=o-n[s]<<5|s;return{b:n,r:a}},c=l(s,2),f=c.b,p=c.r;f[28]=258,p[258]=28;for(var u=l(a,0),d=u.b,m=(u.r,new r(32768)),g=0;g<32768;++g){var w=(43690&g)>>1|(21845&g)<<1;w=(61680&(w=(52428&w)>>2|(13107&w)<<2))>>4|(3855&w)<<4,m[g]=((65280&w)>>8|(255&w)<<8)>>1}var h=function(e,t,n){for(var i=e.length,s=0,a=new r(t);s<i;++s)e[s]&&++a[e[s]-1];var o,l=new r(t);for(s=1;s<t;++s)l[s]=l[s-1]+a[s-1]<<1;if(n){o=new r(1<<t);var c=15-t;for(s=0;s<i;++s)if(e[s])for(var f=s<<4|e[s],p=t-e[s],u=l[e[s]-1]++<<p,d=u|(1<<p)-1;u<=d;++u)o[m[u]>>c]=f}else for(o=new r(i),s=0;s<i;++s)e[s]&&(o[s]=m[l[e[s]-1]++]>>15-e[s]);return o},E=new n(288);for(g=0;g<144;++g)E[g]=8;for(g=144;g<256;++g)E[g]=9;for(g=256;g<280;++g)E[g]=7;for(g=280;g<288;++g)E[g]=8;var A=new n(32);for(g=0;g<32;++g)A[g]=5;var y=h(E,9,1),C=h(A,5,1),U=function(e){for(var t=e[0],n=1;n<e.length;++n)e[n]>t&&(t=e[n]);return t},z=function(e,t,n){var r=t/8|0;return(e[r]|e[r+1]<<8)>>(7&t)&n},_=function(e,t){var n=t/8|0;return(e[n]|e[n+1]<<8|e[n+2]<<16)>>(7&t)},Z=function(e){return(e+7)/8|0},R=function(e,t,r){return(null==t||t<0)&&(t=0),(null==r||r>e.length)&&(r=e.length),new n(e.subarray(t,r))},S=["unexpected EOF","invalid block type","invalid length/literal","invalid distance","stream finished","no stream handler",,"no callback","invalid UTF-8 data","extra field too long","date not in range 1980-2099","filename too long","stream finishing","invalid zip data"],M=function(e,t,n){var r=new Error(t||S[e]);if(r.code=e,Error.captureStackTrace&&Error.captureStackTrace(r,M),!n)throw r;return r},v=function(e,t,r,i){var l=e.length,c=i?i.length:0;if(!l||t.f&&!t.l)return r||new n(0);var p=!r,u=p||2!=t.i,m=t.i;p&&(r=new n(3*l));var g=function(e){var t=r.length;if(e>t){var i=new n(Math.max(2*t,e));i.set(r),r=i}},w=t.f||0,E=t.p||0,A=t.b||0,S=t.l,v=t.d,P=t.m,b=t.n,I=8*l;do{if(!S){w=z(e,E,1);var k=z(e,E+1,3);if(E+=3,!k){var L=e[(W=Z(E)+4)-4]|e[W-3]<<8,T=W+L;if(T>l){m&&M(0);break}u&&g(A+L),r.set(e.subarray(W,T),A),t.b=A+=L,t.p=E=8*T,t.f=w;continue}if(1==k)S=y,v=C,P=9,b=5;else if(2==k){var x=z(e,E,31)+257,F=z(e,E+10,15)+4,N=x+z(e,E+5,31)+1;E+=14;for(var O=new n(N),$=new n(19),H=0;H<F;++H)$[o[H]]=z(e,E+3*H,7);E+=3*F;var D=U($),q=(1<<D)-1,K=h($,D,1);for(H=0;H<N;){var W,j=K[z(e,E,q)];if(E+=15&j,(W=j>>4)<16)O[H++]=W;else{var G=0,Y=0;for(16==W?(Y=3+z(e,E,3),E+=2,G=O[H-1]):17==W?(Y=3+z(e,E,7),E+=3):18==W&&(Y=11+z(e,E,127),E+=7);Y--;)O[H++]=G}}var B=O.subarray(0,x),X=O.subarray(x);P=U(B),b=U(X),S=h(B,P,1),v=h(X,b,1)}else M(1);if(E>I){m&&M(0);break}}u&&g(A+131072);for(var V=(1<<P)-1,J=(1<<b)-1,Q=E;;Q=E){var ee=(G=S[_(e,E)&V])>>4;if((E+=15&G)>I){m&&M(0);break}if(G||M(2),ee<256)r[A++]=ee;else{if(256==ee){Q=E,S=null;break}var te=ee-254;if(ee>264){var ne=s[H=ee-257];te=z(e,E,(1<<ne)-1)+f[H],E+=ne}var re=v[_(e,E)&J],ie=re>>4;if(re||M(3),E+=15&re,X=d[ie],ie>3&&(ne=a[ie],X+=_(e,E)&(1<<ne)-1,E+=ne),E>I){m&&M(0);break}u&&g(A+131072);var se=A+te;if(A<X){var ae=c-X,oe=Math.min(X,se);for(ae+A<0&&M(3);A<oe;++A)r[A]=i[ae+A]}for(;A<se;++A)r[A]=r[A-X]}}t.l=S,t.p=Q,t.b=A,t.f=w,S&&(w=1,t.m=P,t.d=v,t.n=b)}while(!w);return A!=r.length&&p?R(r,0,A):r.subarray(0,A)},P=new n(0);function b(e,t){return v(e,{i:2},t&&t.out,t&&t.dictionary)}var I="undefined"!=typeof TextDecoder&&new TextDecoder;try{I.decode(P,{stream:!0})}catch(e){}"function"==typeof queueMicrotask?queueMicrotask:"function"==typeof setTimeout&&setTimeout}};const t={};function n(r){const i=t[r];if(void 0!==i)return i.exports;const s=t[r]={exports:{}};return e[r](s,s.exports,n),s.exports}(()=>{const e=n(266),t=n(982),r=n(993);self.addEventListener("install",()=>{self.skipWaiting()}),self.addEventListener("activate",e=>{e.waitUntil(self.clients.claim())}),(0,e.installClientErrorReporting)(),(0,r.installMessageHandler)(),(0,t.installFetchHandler)()})()})();
|
|
1
|
+
(()=>{"use strict";var e={553(e,t){function n(e){const n=e.trim();return n.startsWith(t.ZIP_PEEK_ERROR_PREFIX)?n:`${t.ZIP_PEEK_ERROR_PREFIX} ${n}`}t.ZIP_PEEK_ERROR_PREFIX=void 0,t.formatZipPeekError=n,t.createZipPeekError=function(e){return new Error(n(e))},t.toZipPeekError=function(e){const r=e instanceof Error?e:new Error(String(e));return r.message.startsWith(t.ZIP_PEEK_ERROR_PREFIX)||(r.message=n(r.message)),r},t.errorMessage=function(e){return e instanceof Error?e.message:String(e)},t.ZIP_PEEK_ERROR_PREFIX="[zip-peek-error]"},314(e,t,n){t.persistAllowedZipUrlsConfig=o,t.ensureAllowedZipUrlsLoaded=async function(){if(s.allowedZipUrlsLoaded)return s.allowedZipUrlsLoaded;const e=(async()=>{try{const e=await caches.open(s.CONFIG_CACHE_NAME),t=await e.match(s.CONFIG_CACHE_KEY);if(!t)return;const n=await t.json();Array.isArray(n.allowedZipUrls)?(0,s.setAllowedZipUrls)(new Set(n.allowedZipUrls.filter(e=>"string"==typeof e).map(e=>(0,r.normalizeZipUrl)(e)))):(0,s.setAllowedZipUrls)(null)}catch(e){(0,i.warn)("failed to load runtime config",e)}})();return(0,s.setAllowedZipUrlsLoaded)(e),e},t.applyRuntimeConfig=async function(e){if(!e)return;let t={...s.runtimeConfig},n=!1;if("string"==typeof e.zipAssetCacheName&&e.zipAssetCacheName.trim()&&(t.zipAssetCacheName=e.zipAssetCacheName,n=!0),"number"==typeof e.assetCacheTtlMs&&Number.isFinite(e.assetCacheTtlMs)&&(t.assetCacheTtlMs=e.assetCacheTtlMs,n=!0),"string"==typeof e.logPrefix&&e.logPrefix.trim()&&(t.logPrefix=e.logPrefix,n=!0),"boolean"==typeof e.requireExactManifestPath&&(t.requireExactManifestPath=e.requireExactManifestPath,n=!0),n&&(0,s.setRuntimeConfig)(t),"allowedZipUrls"in e){const t=Array.isArray(e.allowedZipUrls)?e.allowedZipUrls.map(e=>(0,r.normalizeZipUrl)(e)):null;(0,s.setAllowedZipUrls)(t?new Set(t):null),(0,s.setAllowedZipUrlsLoaded)(Promise.resolve()),await o(t)}},t.isZipUrlAllowed=function(e){return null===s.allowedZipUrls||s.allowedZipUrls.has(e)};const r=n(343),s=n(262),i=n(266);async function o(e){try{const t=await caches.open(s.CONFIG_CACHE_NAME);await t.put(new Request(s.CONFIG_CACHE_KEY),new Response(JSON.stringify({allowedZipUrls:e}),{headers:{"Content-Type":"application/json"}}))}catch(e){(0,i.warn)("failed to persist runtime config",e)}}},800(e,t,n){t.canonicalAssetRequest=function(e,t){return new Request((0,s.canonicalZipAssetRequestUrl)(e,t),{method:"GET"})},t.clearAllZipAssets=async function(){const e=await caches.open(o.runtimeConfig.zipAssetCacheName),t=await e.keys();await Promise.all(t.map(t=>e.delete(t))),await caches.delete(o.CONFIG_CACHE_NAME),o.zipManifests.clear(),o.pendingManifestLoads.clear(),(0,o.setAllowedZipUrlsLoaded)(Promise.resolve())},t.clearZipAssetsExceptAllowed=async function(e){try{const t=new Set(e),n=await caches.open(o.runtimeConfig.zipAssetCacheName),r=await n.keys();for(const e of r){const r=e.url;if(r.includes(o.MANIFEST_CACHE_KEY)){const s=(0,l.zipUrlFromManifestCacheKey)(r);s&&!t.has(s)&&await n.delete(e);continue}const i=(0,s.parseZipAssetRequest)(r);i&&!t.has(i.zipUrl)&&await n.delete(e)}for(const e of o.zipManifests.keys())t.has(e)||o.zipManifests.delete(e)}catch(e){throw(0,r.createZipPeekError)(`Failed to clear zip assets except allowed URLs: ${(0,r.errorMessage)(e)}`)}},t.putCachedFullAssetIfAbsent=async function(e,t){try{const n=await caches.open(o.runtimeConfig.zipAssetCacheName),r=await n.match(e);if(r&&!c(r))return;const s=t.type||"application/octet-stream";await n.put(e,new Response(t,{status:200,headers:{"Content-Type":s,"Content-Length":String(t.size),"Access-Control-Allow-Origin":"*",[o.ASSET_CACHED_AT_HEADER]:String(Date.now())}}))}catch(e){(0,a.warn)("asset cache put failed",e)}},t.readCachedZipAssetIfFresh=async function(e){let t=null,n="network";try{const r=await caches.open(o.runtimeConfig.zipAssetCacheName),s=await r.match(e);if(s)if(c(s))try{await r.delete(e)}catch(e){(0,a.warn)("asset cache delete expired failed",e)}else t=await s.blob(),n="cache-api"}catch(e){(0,a.warn)("asset cache read failed",e)}return{blob:t,assetSource:n}},t.renewZipUrl=async function(e,t){const n=(0,s.normalizeZipUrl)(e),a=(0,s.normalizeZipUrl)(t);if(console.log("[zip-peek-sw] renewZipUrl start",{previous:n.slice(0,100),next:a.slice(0,100),sameUrl:n===a,allowListSize:o.allowedZipUrls?.size??null}),n===a)return void console.log("[zip-peek-sw] renewZipUrl no-op: previous === next");if(o.allowedZipUrls){const e=new Set(o.allowedZipUrls),t=e.has(n);e.delete(n),e.add(a),(0,o.setAllowedZipUrls)(e),(0,o.setAllowedZipUrlsLoaded)(Promise.resolve()),console.log("[zip-peek-sw] renewZipUrl allow-list updated",{hadPrevious:t,allowListSize:e.size}),await(0,i.persistAllowedZipUrlsConfig)(Array.from(e))}const c=o.zipManifests.get(n);c&&(o.zipManifests.set(a,c),o.zipManifests.delete(n),console.log("[zip-peek-sw] renewZipUrl remapped in-memory manifest"));const f=o.pendingManifestLoads.get(n);f&&(o.pendingManifestLoads.set(a,f),o.pendingManifestLoads.delete(n));try{const e=await caches.open(o.runtimeConfig.zipAssetCacheName),t=await e.keys();console.log("[zip-peek-sw] renewZipUrl clearing cache entries",{keyCount:t.length});let r=0;for(const i of t){const t=i.url;if(t.includes(o.MANIFEST_CACHE_KEY)){(0,l.zipUrlFromManifestCacheKey)(t)===n&&(await e.delete(i),r+=1);continue}const a=(0,s.parseZipAssetRequest)(t);a&&(0,s.normalizeZipUrl)(a.zipUrl)===n&&(await e.delete(i),r+=1)}console.log("[zip-peek-sw] renewZipUrl cache clear done",{deleted:r})}catch(e){throw console.error("[zip-peek-sw] renewZipUrl cache clear failed",e),(0,r.createZipPeekError)(`Failed to clear cached assets for renewed ZIP URL: ${(0,r.errorMessage)(e)}`)}console.log("[zip-peek-sw] renewZipUrl complete")};const r=n(553),s=n(343),i=n(314),o=n(262),a=n(266),l=n(346);function c(e){const t=e.headers.get(o.ASSET_CACHED_AT_HEADER);if(!t)return!0;const n=parseInt(t,10);return!Number.isFinite(n)||Date.now()-n>o.runtimeConfig.assetCacheTtlMs}},982(e,t,n){t.installFetchHandler=function(){self.addEventListener("fetch",e=>{const t=e.request.method;if("GET"!==t&&"HEAD"!==t)return;const n="HEAD"===t,d=(0,s.parseZipAssetRequest)(e.request.url);if(!d)return;const g=(0,s.normalizeZipUrl)(d.zipUrl),m=d.internalPath,w=(0,s.normalizeZipEntryPath)(m);e.respondWith((async()=>{try{if(await(0,i.ensureAllowedZipUrlsLoaded)(),!(0,i.isZipUrlAllowed)(g))return(0,l.warn)("zip URL not allowed",{requestedZipUrl:g}),(0,f.corsErrorResponse)(`ZIP URL not allowed (not in allowedZipUrls): ${g}`,403);let t=a.zipManifests.get(g);if(t||(t=await(0,c.ensureManifestAvailable)(g,e.clientId||void 0)??void 0),!t){const e=Array.from(a.zipManifests.keys());return(0,l.warn)("manifest missing for zipUrl",{requestedZipUrl:g,knownZipUrls:e}),(0,f.corsErrorResponse)(`ZIP manifest not loaded for ${g}. Ensure the ZIP is reachable and supports byte-range requests.`,404)}const s=(0,c.resolveManifestEntry)(t,w,g,a.runtimeConfig.requireExactManifestPath);if(!s){const e=Array.from(t.keys()).slice(0,50);return(0,l.warn)("file not in manifest",{zipUrl:g,internalPathRaw:m,internalPathNormalized:w,requireExactManifestPath:a.runtimeConfig.requireExactManifestPath,manifestSize:t.size,sampleKeys:e}),(0,f.corsErrorResponse)(`File "${m}" not found in ZIP manifest for ${g}`,404)}const{key:d,info:h,matchKind:E}=s;"zipBasenameFallback"===E&&((0,l.log)("resolved via zip-basename folder fallback",{requested:w,manifestKey:d}),(0,l.reportClientError)(new Error((0,r.formatZipPeekError)("Exact manifest path not found; resolved via zip-basename folder fallback")),`Exact manifest key "${w}" not found in ${g}; resolved using "${d}"`));const y=(0,o.canonicalAssetRequest)(g,d);if(n)return function(e,t,n){const r=(0,f.getMimeType)(t),s=(0,c.entryUncompressedSize)(n),i=e.headers.get("range");if(null!==s&&i)return u(null,r,s,"manifest",i);const o={"Content-Type":r,...p("manifest")};return null!==s&&(o["Content-Length"]=s.toString()),new Response(null,{status:200,headers:o})}(e.request,d,h);let{blob:A,assetSource:U}=await(0,o.readCachedZipAssetIfFresh)(y);if(!A){const e=await(0,f.fetchUncompressedZipEntryFromNetwork)(g,d,h,y);if(!e.ok)return e.response;A=e.blob,U="network"}return u(A,A.type,A.size,U,e.request.headers.get("range"))}catch(e){return(0,l.error)("fetch handler failed",{zipUrl:g,internalPath:m,message:(0,r.errorMessage)(e)}),(0,f.corsErrorResponse)(`Failed to serve "${m}" from ${g}: ${(0,r.errorMessage)(e)}`,500)}})())})};const r=n(553),s=n(343),i=n(314),o=n(800),a=n(262),l=n(266),c=n(346),f=n(254);function p(e){return{"Access-Control-Allow-Origin":"*","Access-Control-Expose-Headers":a.ASSET_SOURCE_HEADER,[a.ASSET_SOURCE_HEADER]:e}}function u(e,t,n,r,s){if(s){const i=s.replace(/^bytes=/,"");if(i.includes(","))return new Response(null,{status:416,headers:{"Content-Range":`bytes */${n}`,...p(r)}});const[o,a]=i.split("-"),l=""!==o?parseInt(o,10):NaN,c=""!==a?parseInt(a,10):n-1;if(isNaN(l)||isNaN(c)||l<0||c<l||l>=n)return new Response(null,{status:416,headers:{"Content-Range":`bytes */${n}`,...p(r)}});const f=Math.min(c,n-1),u=f-l+1,d=null===e?null:e.slice(l,f+1);return new Response(d,{status:206,headers:{"Content-Type":t,"Content-Range":`bytes ${l}-${f}/${n}`,"Content-Length":u.toString(),"Accept-Ranges":"bytes",...p(r)}})}return new Response(e,{status:200,headers:{"Content-Type":t,"Content-Length":n.toString(),...p(r)}})}},262(e,t){t.CONFIG_CACHE_KEY=t.allowedZipUrlsLoaded=t.allowedZipUrls=t.runtimeConfig=t.pendingManifestLoads=t.zipManifests=t.MANIFEST_CACHE_KEY=t.LOCAL_FILE_HEADER_SIG=t.MIME_TYPES=t.ASSET_SOURCE_HEADER=t.ASSET_CACHED_AT_HEADER=t.CONFIG_CACHE_NAME=t.kF=t.o2=void 0,t.setRuntimeConfig=function(e){t.runtimeConfig=e},t.setAllowedZipUrls=function(e){t.allowedZipUrls=e},t.setAllowedZipUrlsLoaded=function(e){t.allowedZipUrlsLoaded=e},t.o2="zip-cache-v1",t.kF=72e5,t.CONFIG_CACHE_NAME="zip-peek-config-v1",t.o2,t.CONFIG_CACHE_NAME,t.ASSET_CACHED_AT_HEADER="X-ZipSW-Cached-At",t.ASSET_SOURCE_HEADER="X-ZipSW-Asset-Source",t.MIME_TYPES={png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",webp:"image/webp",svg:"image/svg+xml",json:"application/json",js:"application/javascript",css:"text/css; charset=utf-8",html:"text/html; charset=utf-8",txt:"text/plain; charset=utf-8",mp4:"video/mp4",webm:"video/webm",mp3:"audio/mpeg",wav:"audio/wav",oga:"audio/ogg",ogg:"audio/ogg",xml:"application/xml",wasm:"application/wasm"},t.LOCAL_FILE_HEADER_SIG=67324752,t.MANIFEST_CACHE_KEY="__zipsw_manifest__=1",t.zipManifests=new Map,t.pendingManifestLoads=new Map,t.runtimeConfig={zipAssetCacheName:t.o2,assetCacheTtlMs:t.kF,logPrefix:"[zipSW]",requireExactManifestPath:!1},t.allowedZipUrls=null,t.allowedZipUrlsLoaded=null,t.CONFIG_CACHE_KEY=new URL("__zip_peek_runtime_config__",self.registration.scope).href},266(e,t,n){t.log=function(...e){console.log(s.runtimeConfig.logPrefix,...e)},t.warn=function(...e){console.warn(s.runtimeConfig.logPrefix,...e)},t.error=function(...e){console.error(s.runtimeConfig.logPrefix,r.ZIP_PEEK_ERROR_PREFIX,...e)},t.reportClientError=i,t.installClientErrorReporting=function(){self.addEventListener("error",e=>{i(e.error??e.message,"Service worker uncaught error")}),self.addEventListener("unhandledrejection",e=>{i(e.reason,"Service worker unhandled promise rejection")})};const r=n(553),s=n(262);function i(e,t){const n=(0,r.toZipPeekError)(e);self.clients.matchAll({type:"window",includeUncontrolled:!0}).then(e=>{const s={type:"ZIP_SW_ERROR",error:{message:n.message,stack:n.stack},info:t?(0,r.formatZipPeekError)(t):void 0};for(const t of e)t.postMessage(s)})}},346(e,t,n){t.manifestFilesToMap=o,t.sendManifestToClientId=l,t.ensureManifestAvailable=function(e,t){const n=s.zipManifests.get(e);if(n)return Promise.resolve(n);let c=s.pendingManifestLoads.get(e);return c||(c=(async()=>{const n=await async function(e,t){const n=await a(t);return n?function(e,t){return new Promise(n=>{const r=new MessageChannel,s=setTimeout(()=>{r.port1.close(),n(null)},500);r.port1.onmessage=e=>{clearTimeout(s),r.port1.close();const t=e.data;t?.ok&&Array.isArray(t.files)?n(o(t.files)):n(null)},r.port1.onmessageerror=()=>{clearTimeout(s),r.port1.close(),n(null)};try{e.postMessage({type:"ZIP_SW_MANIFEST_REQUEST",zipUrl:t},[r.port2])}catch(e){clearTimeout(s),r.port1.close(),(0,i.warn)("failed to request manifest from client",e),n(null)}})}(n,e):null}(e,t);if(n)return s.zipManifests.set(e,n),(0,i.log)("restored manifest from client memory",{zipUrl:e,entryCount:n.size}),n;const c=await async function(e){const t=await fetch(e,{headers:{Range:"bytes=-65536"}});if(206!==t.status)return(0,i.error)("range requests not supported for ZIP manifest",{zipUrl:e,status:t.status}),null;const n=await t.arrayBuffer(),s=new DataView(n);let o=-1;for(let e=n.byteLength-22;e>=0;e--)if(101010256===s.getUint32(e,!0)){o=e;break}if(-1===o)return(0,i.error)("EOCD not found in last 64KB of ZIP file",e),null;const a=s.getUint32(o+16,!0),l=s.getUint32(o+12,!0);let c=n,f=-1;const p=t.headers.get("Content-Range");let u=0;if(p){const e=p.match(/\/(\d+)$/);e&&(u=parseInt(e[1],10))}if(u<=0)return(0,i.error)("could not determine ZIP file size from Content-Range header",{zipUrl:e,contentRange:p}),null;const d=u-n.byteLength;if(a>=d)f=a-d;else{const t=await fetch(e,{headers:{Range:`bytes=${a}-${a+l-1}`}});if(206!==t.status)return(0,i.error)("failed to fetch ZIP central directory",{zipUrl:e,status:t.status,cdOffset:a,cdSize:l}),null;c=await t.arrayBuffer(),f=0}return function(e,t,n,s){const o=new DataView(e);let a=t;const l=[];for(;a+46<=e.byteLength&&33639248===o.getUint32(a,!0);){const t=o.getUint16(a+10,!0),n=o.getUint32(a+20,!0),s=o.getUint32(a+24,!0),i=o.getUint16(a+28,!0),c=o.getUint16(a+30,!0),f=o.getUint16(a+32,!0),p=o.getUint32(a+42,!0),u=new TextDecoder;if(a+46+i>e.byteLength)break;const d=new Uint8Array(e,a+46,i),g=u.decode(d),m=(0,r.normalizeZipEntryPath)(g);""!==m&&l.push({filename:m,offset:p,compressedSize:n,uncompressedSize:s,compression:t}),a+=46+i+c+f}if(0===l.length)return(0,i.error)("no files parsed from central directory",s),null;l.sort((e,t)=>e.offset-t.offset);const c=new Map;for(let e=0;e<l.length;e++){const t=l[e],s=(0,r.normalizeZipEntryPath)(t.filename);""!==s&&(c.has(s)&&(0,i.warn)("duplicate manifest key after normalize; overwriting",s),c.set(s,{filename:t.filename,offset:t.offset,compressedSize:t.compressedSize,uncompressedSize:t.uncompressedSize,compression:t.compression,nextOffset:e<l.length-1?l[e+1].offset:n}))}return c.size>0?c:null}(c,f,a,e)}(e);return c&&(s.zipManifests.set(e,c),await l(e,c,t),(0,i.log)("manifest fetched and stored in memory",{zipUrl:e,entryCount:c.size})),c})().finally(()=>{s.pendingManifestLoads.delete(e)}),s.pendingManifestLoads.set(e,c),c)},t.entryUncompressedSize=function(e){return void 0!==e.uncompressedSize?e.uncompressedSize:0===e.compression?e.compressedSize:null},t.resolveManifestEntry=function(e,t,n,s){if(e.has(t))return{key:t,info:e.get(t),matchKind:"exact"};if(s)return null;const i=(0,r.zipBasenameWithoutExtension)(n);if(!i)return null;const o=`${i}/${t}`;return e.has(o)?{key:o,info:e.get(o),matchKind:"zipBasenameFallback"}:null},t.zipUrlFromManifestCacheKey=function(e){const t=s.MANIFEST_CACHE_KEY;if(!e.endsWith(t))return null;let n=e.slice(0,-t.length);return(n.endsWith("?")||n.endsWith("&"))&&(n=n.slice(0,-1)),n};const r=n(343),s=n(262),i=n(266);function o(e){const t=new Map;for(const n of e){const e=(0,r.normalizeZipEntryPath)(n.filename);""!==e&&(t.has(e)&&(0,i.warn)("duplicate manifest key after normalize; overwriting",e),t.set(e,n))}return t.size>0?t:null}async function a(e){if(!e)return null;const t=await self.clients.get(e);return"window"===t?.type?t:null}async function l(e,t,n){const r=await a(n);if(!r)return;const s=Array.from(t.values());try{r.postMessage({type:"ZIP_SW_MANIFEST_CREATED",zipUrl:e,files:s})}catch(e){(0,i.warn)("failed to send manifest to client",e)}}},993(e,t,n){t.installMessageHandler=function(){self.addEventListener("message",e=>{if(!e.data)return;const{type:t,zipUrl:n,files:u,config:d,allowedZipUrls:g,previousUrl:m,nextUrl:w}=e.data,h=function(e){if(!e||!("id"in e))return;const t=e.id;return"string"==typeof t?t:void 0}(e.source);if("ZIP_SW_CONFIG"===t){const t=(0,i.applyRuntimeConfig)(d).then(()=>p(e,{ok:!0})).catch(t=>p(e,f(t)));return void e.waitUntil(t)}if("ZIP_MANIFEST"===t){if(n&&u){const t=(0,s.normalizeZipUrl)(n),r=(0,c.manifestFilesToMap)(u),i=a.zipManifests.get(t);if(!r)return void(0,l.warn)("rejecting empty manifest; keeping existing",{zipUrl:t,existingSize:i?i.size:0});if(i&&i.size>r.size)return void(0,l.warn)("rejecting smaller manifest; keeping existing",{zipUrl:t,incomingSize:r.size,existingSize:i.size});a.zipManifests.set(t,r),e.waitUntil((0,c.sendManifestToClientId)(t,r,h));const o=Array.from(r.keys()).slice(0,40);(0,l.log)("ZIP_MANIFEST loaded",{zipUrl:t,entryCount:r.size,sampleKeys:o,replacedExistingSize:i?i.size:0})}}else if("CLEAR_ZIP_ASSETS_EXCEPT_ALLOWED"===t&&g){const t=(0,o.clearZipAssetsExceptAllowed)(g).then(()=>p(e,{ok:!0})).catch(t=>p(e,f(t)));e.waitUntil(t)}else if("CLEAR_ALL_ZIP_ASSETS"===t){const t=(0,o.clearAllZipAssets)().then(()=>p(e,{ok:!0})).catch(t=>p(e,f(t)));e.waitUntil(t)}else if("PRELOAD_ZIP_MANIFESTS"===t&&g){const t=async function(e,t){const n=await Promise.all(e.map(async e=>({zipUrl:e,manifest:await(0,c.ensureManifestAvailable)(e,t)}))),s=n.filter(e=>!e.manifest).map(e=>e.zipUrl);if(s.length>0)throw(0,r.createZipPeekError)(`Failed to preload ZIP manifest(s): ${s.join(", ")}`)}(g,h).then(()=>p(e,{ok:!0})).catch(t=>p(e,f(t)));e.waitUntil(t)}else if("RENEW_ZIP_URL"===t&&m&&w){console.log("[zip-peek-sw] RENEW_ZIP_URL received",{previousUrl:m.slice(0,100),nextUrl:w.slice(0,100)});const t=(0,o.renewZipUrl)(m,w).then(()=>{console.log("[zip-peek-sw] RENEW_ZIP_URL done ok"),p(e,{ok:!0})}).catch(t=>{console.error("[zip-peek-sw] RENEW_ZIP_URL failed",t),p(e,f(t))});e.waitUntil(t)}else"RENEW_ZIP_URL"===t&&console.error("[zip-peek-sw] RENEW_ZIP_URL missing previousUrl/nextUrl — no reply will be sent",{hasPrevious:Boolean(m),hasNext:Boolean(w)})})};const r=n(553),s=n(343),i=n(314),o=n(800),a=n(262),l=n(266),c=n(346);function f(e){const t=(0,r.toZipPeekError)(e);return{ok:!1,error:t.message,errorStack:t.stack}}function p(e,t){e.ports[0]?.postMessage(t)}},254(e,t,n){t.corsErrorResponse=l,t.getMimeType=c,t.fetchUncompressedZipEntryFromNetwork=async function(e,t,n,s){const f=n.offset,p=n.nextOffset-1;(0,o.log)("fetching zip chunk from",{zipUrl:e,rangeStart:f,rangeEnd:p});const u=await fetch(e,{headers:{Range:`bytes=${f}-${p}`}});if(206!==u.status)return{ok:!1,response:l(`ZIP entry fetch for "${t}" expected HTTP 206 Partial Content from ${e}, got ${u.status}`,u.status>=400?u.status:502)};const d=await u.arrayBuffer(),g=new DataView(d);if(g.getUint32(0,!0)!==i.LOCAL_FILE_HEADER_SIG)return{ok:!1,response:l(`Invalid local file header for "${t}" in ${e} (expected ZIP signature 0x04034b50)`,500)};const m=30+g.getUint16(26,!0)+g.getUint16(28,!0);if(m>d.byteLength||m+n.compressedSize>d.byteLength)return{ok:!1,response:l(`Corrupt ZIP entry "${t}" in ${e}: dataStart=${m}, compressedSize=${n.compressedSize}, bufferLength=${d.byteLength}`,500)};const w=new Uint8Array(d,m,n.compressedSize);let h;if(8===n.compression)try{h=(0,r.inflateSync)(w)}catch(n){return(0,o.warn)("inflateSync failed",{zipUrl:e,manifestKey:t,error:n}),{ok:!1,response:l(`Failed to inflate DEFLATE-compressed entry "${t}" in ${e}`,500)}}else{if(0!==n.compression)return{ok:!1,response:l(`Unsupported compression method ${n.compression} for "${t}" in ${e} (only stored/0 and DEFLATE/8 are supported)`,500)};h=w}const E=c(t),y=new Blob([h],{type:E});return await(0,a.putCachedFullAssetIfAbsent)(s,y),{ok:!0,blob:y}};const r=n(612),s=n(553),i=n(262),o=n(266),a=n(800);function l(e,t){return new Response((0,s.formatZipPeekError)(e),{status:t,headers:{"Access-Control-Allow-Origin":"*"}})}function c(e){const t=e.split(".").pop()?.toLowerCase();return t?i.MIME_TYPES[t]??"application/octet-stream":"application/octet-stream"}},343(e,t){function n(e){try{return decodeURIComponent(e)}catch{return e}}t.normalizeZipUrl=function(e,t={}){const{stripCacheBuster:n=!0,stripHash:r=!0}=t,s=e=>r?e.split("#")[0]:e;if(!n)return s(e);const i=e.indexOf("?");if(-1===i)return s(e);const o=e.indexOf("#",i),a=e.substring(0,i),l=-1===o?e.substring(i+1):e.substring(i+1,o),c=r||-1===o?"":e.substring(o),f=l.split("&").filter(e=>{const t=e.indexOf("=");return"t"!==(-1===t?e:e.substring(0,t))});return 0===f.length?a+c:a+"?"+f.join("&")+c},t.zipBasenameWithoutExtension=function(e){try{const t=new URL(e,"http://local").pathname.split("/").pop()??"";return t.endsWith(".zip")?t.slice(0,-4):t}catch{const t=e.split("?")[0].split("#")[0].split("/").pop()??"";return t.endsWith(".zip")?t.slice(0,-4):t}},t.normalizeZipEntryPath=function(e){let t=e.replace(/\\/g,"/");for(;t.startsWith("/");)t=t.slice(1);return t},t.parseZipAssetRequest=function(e){const t=/\.zip([/?])/.exec(e);if(!t)return null;const r=t.index+4,s=t[1],i=e.substring(0,r);if("/"===s){const t=e.substring(r+1),s=t.indexOf("?"),o=-1===s?t:t.substring(0,s);return""===o?null:{zipUrl:i,internalPath:n(o)}}const o=e.substring(r),a=o.indexOf("/");if(-1===a)return null;const l=o.substring(0,a),c=o.substring(a+1),f=c.indexOf("?"),p=-1===f?c:c.substring(0,f);return""===p?null:{zipUrl:i+l,internalPath:n(p)}},t.canonicalZipAssetRequestUrl=function(e,t){return e+"/"+encodeURIComponent(t)}},612(e,t){t.inflateSync=k;var n=Uint8Array,r=Uint16Array,s=Int32Array,i=new n([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0,0]),o=new n([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,0,0]),a=new n([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]),l=function(e,t){for(var n=new r(31),i=0;i<31;++i)n[i]=t+=1<<e[i-1];var o=new s(n[30]);for(i=1;i<30;++i)for(var a=n[i];a<n[i+1];++a)o[a]=a-n[i]<<5|i;return{b:n,r:o}},c=l(i,2),f=c.b,p=c.r;f[28]=258,p[258]=28;for(var u=l(o,0),d=u.b,g=(u.r,new r(32768)),m=0;m<32768;++m){var w=(43690&m)>>1|(21845&m)<<1;w=(61680&(w=(52428&w)>>2|(13107&w)<<2))>>4|(3855&w)<<4,g[m]=((65280&w)>>8|(255&w)<<8)>>1}var h=function(e,t,n){for(var s=e.length,i=0,o=new r(t);i<s;++i)e[i]&&++o[e[i]-1];var a,l=new r(t);for(i=1;i<t;++i)l[i]=l[i-1]+o[i-1]<<1;if(n){a=new r(1<<t);var c=15-t;for(i=0;i<s;++i)if(e[i])for(var f=i<<4|e[i],p=t-e[i],u=l[e[i]-1]++<<p,d=u|(1<<p)-1;u<=d;++u)a[g[u]>>c]=f}else for(a=new r(s),i=0;i<s;++i)e[i]&&(a[i]=g[l[e[i]-1]++]>>15-e[i]);return a},E=new n(288);for(m=0;m<144;++m)E[m]=8;for(m=144;m<256;++m)E[m]=9;for(m=256;m<280;++m)E[m]=7;for(m=280;m<288;++m)E[m]=8;var y=new n(32);for(m=0;m<32;++m)y[m]=5;var A=h(E,9,1),U=h(y,5,1),C=function(e){for(var t=e[0],n=1;n<e.length;++n)e[n]>t&&(t=e[n]);return t},z=function(e,t,n){var r=t/8|0;return(e[r]|e[r+1]<<8)>>(7&t)&n},_=function(e,t){var n=t/8|0;return(e[n]|e[n+1]<<8|e[n+2]<<16)>>(7&t)},Z=function(e){return(e+7)/8|0},R=function(e,t,r){return(null==t||t<0)&&(t=0),(null==r||r>e.length)&&(r=e.length),new n(e.subarray(t,r))},v=["unexpected EOF","invalid block type","invalid length/literal","invalid distance","stream finished","no stream handler",,"no callback","invalid UTF-8 data","extra field too long","date not in range 1980-2099","filename too long","stream finishing","invalid zip data"],P=function(e,t,n){var r=new Error(t||v[e]);if(r.code=e,Error.captureStackTrace&&Error.captureStackTrace(r,P),!n)throw r;return r},S=function(e,t,r,s){var l=e.length,c=s?s.length:0;if(!l||t.f&&!t.l)return r||new n(0);var p=!r,u=p||2!=t.i,g=t.i;p&&(r=new n(3*l));var m=function(e){var t=r.length;if(e>t){var s=new n(Math.max(2*t,e));s.set(r),r=s}},w=t.f||0,E=t.p||0,y=t.b||0,v=t.l,S=t.d,M=t.m,k=t.n,I=8*l;do{if(!v){w=z(e,E,1);var b=z(e,E+1,3);if(E+=3,!b){var L=e[(W=Z(E)+4)-4]|e[W-3]<<8,x=W+L;if(x>l){g&&P(0);break}u&&m(y+L),r.set(e.subarray(W,x),y),t.b=y+=L,t.p=E=8*x,t.f=w;continue}if(1==b)v=A,S=U,M=9,k=5;else if(2==b){var T=z(e,E,31)+257,F=z(e,E+10,15)+4,N=T+z(e,E+5,31)+1;E+=14;for(var O=new n(N),$=new n(19),H=0;H<F;++H)$[a[H]]=z(e,E+3*H,7);E+=3*F;var D=C($),q=(1<<D)-1,K=h($,D,1);for(H=0;H<N;){var W,j=K[z(e,E,q)];if(E+=15&j,(W=j>>4)<16)O[H++]=W;else{var G=0,B=0;for(16==W?(B=3+z(e,E,3),E+=2,G=O[H-1]):17==W?(B=3+z(e,E,7),E+=3):18==W&&(B=11+z(e,E,127),E+=7);B--;)O[H++]=G}}var Y=O.subarray(0,T),X=O.subarray(T);M=C(Y),k=C(X),v=h(Y,M,1),S=h(X,k,1)}else P(1);if(E>I){g&&P(0);break}}u&&m(y+131072);for(var V=(1<<M)-1,J=(1<<k)-1,Q=E;;Q=E){var ee=(G=v[_(e,E)&V])>>4;if((E+=15&G)>I){g&&P(0);break}if(G||P(2),ee<256)r[y++]=ee;else{if(256==ee){Q=E,v=null;break}var te=ee-254;if(ee>264){var ne=i[H=ee-257];te=z(e,E,(1<<ne)-1)+f[H],E+=ne}var re=S[_(e,E)&J],se=re>>4;if(re||P(3),E+=15&re,X=d[se],se>3&&(ne=o[se],X+=_(e,E)&(1<<ne)-1,E+=ne),E>I){g&&P(0);break}u&&m(y+131072);var ie=y+te;if(y<X){var oe=c-X,ae=Math.min(X,ie);for(oe+y<0&&P(3);y<ae;++y)r[y]=s[oe+y]}for(;y<ie;++y)r[y]=r[y-X]}}t.l=v,t.p=Q,t.b=y,t.f=w,v&&(w=1,t.m=M,t.d=S,t.n=k)}while(!w);return y!=r.length&&p?R(r,0,y):r.subarray(0,y)},M=new n(0);function k(e,t){return S(e,{i:2},t&&t.out,t&&t.dictionary)}var I="undefined"!=typeof TextDecoder&&new TextDecoder;try{I.decode(M,{stream:!0})}catch(e){}"function"==typeof queueMicrotask?queueMicrotask:"function"==typeof setTimeout&&setTimeout}};const t={};function n(r){const s=t[r];if(void 0!==s)return s.exports;const i=t[r]={exports:{}};return e[r](i,i.exports,n),i.exports}(()=>{const e=n(266),t=n(982),r=n(993);self.addEventListener("install",()=>{self.skipWaiting()}),self.addEventListener("activate",e=>{e.waitUntil(self.clients.claim())}),(0,e.installClientErrorReporting)(),(0,r.installMessageHandler)(),(0,t.installFetchHandler)()})()})();
|
|
2
2
|
//# sourceMappingURL=zipServiceWorker.js.map
|