zip-peek 0.5.1 → 0.6.2
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.d.ts +13 -3
- package/dist/index.js +174 -2
- package/dist/types.d.ts +17 -0
- package/dist/zip-utils.d.ts +6 -0
- package/dist/zip-utils.js +63 -0
- package/dist/zipServiceWorker.js +1 -1
- package/dist/zipServiceWorker.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { InitZipPeekOptions, InitZipPeekResult } from "./types";
|
|
1
|
+
import type { InitZipPeekOptions, InitZipPeekResult, RenewPresignedUrlOptions } from "./types";
|
|
2
2
|
import { isZipPackage } from "./zip-utils";
|
|
3
|
-
export type { InitZipPeekOptions, InitZipPeekResult, ZipCacheClearingStrategy, ZipPeekErrorHandler, ZipWorkerConfig, } from "./types";
|
|
3
|
+
export type { InitZipPeekOptions, InitZipPeekResult, RenewPresignedUrlOptions, ZipCacheClearingStrategy, ZipPeekErrorHandler, ZipPeekUrlExpiryHandler, ZipWorkerConfig, } from "./types";
|
|
4
|
+
export { getPresignedUrlExpiryMs } from "./zip-utils";
|
|
4
5
|
/**
|
|
5
6
|
* Registers the zip-peek service worker and configures lazy ZIP asset loading.
|
|
6
7
|
*
|
|
@@ -10,6 +11,15 @@ export type { InitZipPeekOptions, InitZipPeekResult, ZipCacheClearingStrategy, Z
|
|
|
10
11
|
* package URLs and warm their manifests during initialization. Use
|
|
11
12
|
* `cacheClearingStrategy` to keep existing cache entries, keep only allowed
|
|
12
13
|
* ZIP URLs, or clear all zip-peek cache entries before use.
|
|
14
|
+
*
|
|
15
|
+
* When `onUrlExpiry` is provided and an allowed URL is a recognized presigned
|
|
16
|
+
* URL, zip-peek invokes the handler shortly before expiry and re-checks on tab
|
|
17
|
+
* wake (`visibilitychange`, `pageshow`, `focus`) after sleep or backgrounding.
|
|
18
|
+
*/
|
|
19
|
+
export declare function initZipPeek({ workerUrl, scopeUrl, reloadOnFirstInstall, cacheClearingStrategy, allowedZipUrls, requireExactManifestPath, zipAssetCacheName, assetCacheTtlMs, logPrefix, onError, onUrlExpiry, }: InitZipPeekOptions): Promise<InitZipPeekResult>;
|
|
20
|
+
/**
|
|
21
|
+
* Replace a presigned ZIP package URL after renewal so the service worker
|
|
22
|
+
* continue serving assets with the new credentials.
|
|
13
23
|
*/
|
|
14
|
-
export declare function
|
|
24
|
+
export declare function renewPresignedUrl({ previousUrl, nextUrl }: RenewPresignedUrlOptions): Promise<void>;
|
|
15
25
|
export { isZipPackage };
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isZipPackage = void 0;
|
|
3
|
+
exports.isZipPackage = exports.getPresignedUrlExpiryMs = void 0;
|
|
4
4
|
exports.initZipPeek = initZipPeek;
|
|
5
|
+
exports.renewPresignedUrl = renewPresignedUrl;
|
|
5
6
|
const types_1 = require("./types");
|
|
6
7
|
const zip_utils_1 = require("./zip-utils");
|
|
7
8
|
Object.defineProperty(exports, "isZipPackage", { enumerable: true, get: function () { return zip_utils_1.isZipPackage; } });
|
|
9
|
+
var zip_utils_2 = require("./zip-utils");
|
|
10
|
+
Object.defineProperty(exports, "getPresignedUrlExpiryMs", { enumerable: true, get: function () { return zip_utils_2.getPresignedUrlExpiryMs; } });
|
|
11
|
+
/** Default lead time before presigned URL expiry when scheduling renewal. */
|
|
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;
|
|
8
17
|
let currentOnError;
|
|
18
|
+
let currentOnUrlExpiry;
|
|
9
19
|
let clientMessageListenerInstalled = false;
|
|
20
|
+
let expiryWakeListenersInstalled = false;
|
|
21
|
+
/** Timers keyed by normalized zip URL. */
|
|
22
|
+
const urlExpiryTimers = new Map();
|
|
23
|
+
/** Original resolved URLs for expiry parsing, keyed by normalized zip URL. */
|
|
24
|
+
const trackedZipUrls = new Map();
|
|
25
|
+
/** Guard concurrent onUrlExpiry invocations per zip URL. */
|
|
26
|
+
const urlExpiryInFlight = new Set();
|
|
27
|
+
function zipPackagePathname(zipUrl) {
|
|
28
|
+
try {
|
|
29
|
+
return new URL(zipUrl).pathname;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return zipUrl.split("?")[0].split("#")[0];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
10
35
|
const sessionManifests = new Map();
|
|
11
36
|
function normalizeScopePath(href) {
|
|
12
37
|
let p = new URL(href).pathname;
|
|
@@ -101,6 +126,93 @@ function errorFromWorkerResponse(response) {
|
|
|
101
126
|
}
|
|
102
127
|
return error;
|
|
103
128
|
}
|
|
129
|
+
function clearUrlExpiryTimer(normalizedZipUrl) {
|
|
130
|
+
const existing = urlExpiryTimers.get(normalizedZipUrl);
|
|
131
|
+
if (existing !== undefined) {
|
|
132
|
+
clearTimeout(existing);
|
|
133
|
+
urlExpiryTimers.delete(normalizedZipUrl);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function scheduleUrlExpiry(normalizedZipUrl, originalUrlForExpiry) {
|
|
137
|
+
clearUrlExpiryTimer(normalizedZipUrl);
|
|
138
|
+
trackedZipUrls.set(normalizedZipUrl, originalUrlForExpiry);
|
|
139
|
+
if (!currentOnUrlExpiry) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const expiryMs = (0, zip_utils_1.getPresignedUrlExpiryMs)(originalUrlForExpiry);
|
|
143
|
+
if (expiryMs == null) {
|
|
144
|
+
trackedZipUrls.delete(normalizedZipUrl);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const delayMs = Math.max(URL_EXPIRY_MIN_DELAY_MS, expiryMs - Date.now() - URL_EXPIRY_LEAD_MS);
|
|
148
|
+
const timerId = setTimeout(() => {
|
|
149
|
+
urlExpiryTimers.delete(normalizedZipUrl);
|
|
150
|
+
void invokeUrlExpiry(normalizedZipUrl);
|
|
151
|
+
}, delayMs);
|
|
152
|
+
urlExpiryTimers.set(normalizedZipUrl, timerId);
|
|
153
|
+
}
|
|
154
|
+
function isZipUrlDueForRenewal(originalUrl) {
|
|
155
|
+
const expiryMs = (0, zip_utils_1.getPresignedUrlExpiryMs)(originalUrl);
|
|
156
|
+
if (expiryMs == null) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
return expiryMs - Date.now() <= URL_EXPIRY_LEAD_MS;
|
|
160
|
+
}
|
|
161
|
+
function checkExpiryOnWake() {
|
|
162
|
+
if (typeof document !== "undefined" && document.visibilityState !== "visible") {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (!currentOnUrlExpiry) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
for (const [normalized, original] of trackedZipUrls) {
|
|
169
|
+
if (isZipUrlDueForRenewal(original)) {
|
|
170
|
+
void invokeUrlExpiry(normalized);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
scheduleUrlExpiry(normalized, original);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
function ensureExpiryWakeListeners() {
|
|
177
|
+
if (expiryWakeListenersInstalled || typeof document === "undefined") {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
expiryWakeListenersInstalled = true;
|
|
181
|
+
document.addEventListener("visibilitychange", checkExpiryOnWake);
|
|
182
|
+
window.addEventListener("pageshow", checkExpiryOnWake);
|
|
183
|
+
window.addEventListener("focus", checkExpiryOnWake);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* If onUrlExpiry did not replace this URL via renewPresignedUrl, re-arm a timer
|
|
187
|
+
* so renewal is not one-shot when the host renew fails or is skipped.
|
|
188
|
+
*/
|
|
189
|
+
function rearmExpiryIfStillTracked(normalizedZipUrl) {
|
|
190
|
+
const original = trackedZipUrls.get(normalizedZipUrl);
|
|
191
|
+
if (!original || urlExpiryTimers.has(normalizedZipUrl)) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const timerId = setTimeout(() => {
|
|
195
|
+
urlExpiryTimers.delete(normalizedZipUrl);
|
|
196
|
+
void invokeUrlExpiry(normalizedZipUrl);
|
|
197
|
+
}, URL_EXPIRY_RETRY_MS);
|
|
198
|
+
urlExpiryTimers.set(normalizedZipUrl, timerId);
|
|
199
|
+
}
|
|
200
|
+
async function invokeUrlExpiry(normalizedZipUrl) {
|
|
201
|
+
if (!currentOnUrlExpiry || urlExpiryInFlight.has(normalizedZipUrl)) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
urlExpiryInFlight.add(normalizedZipUrl);
|
|
205
|
+
try {
|
|
206
|
+
await currentOnUrlExpiry();
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
reportZipPeekError(currentOnError, error, "onUrlExpiry handler failed");
|
|
210
|
+
}
|
|
211
|
+
finally {
|
|
212
|
+
urlExpiryInFlight.delete(normalizedZipUrl);
|
|
213
|
+
rearmExpiryIfStillTracked(normalizedZipUrl);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
104
216
|
function ensureClientMessageListener() {
|
|
105
217
|
if (clientMessageListenerInstalled || !("serviceWorker" in navigator)) {
|
|
106
218
|
return;
|
|
@@ -194,11 +306,18 @@ async function postWorkerMessageOrThrow(message, info) {
|
|
|
194
306
|
* package URLs and warm their manifests during initialization. Use
|
|
195
307
|
* `cacheClearingStrategy` to keep existing cache entries, keep only allowed
|
|
196
308
|
* ZIP URLs, or clear all zip-peek cache entries before use.
|
|
309
|
+
*
|
|
310
|
+
* When `onUrlExpiry` is provided and an allowed URL is a recognized presigned
|
|
311
|
+
* URL, zip-peek invokes the handler shortly before expiry and re-checks on tab
|
|
312
|
+
* wake (`visibilitychange`, `pageshow`, `focus`) after sleep or backgrounding.
|
|
197
313
|
*/
|
|
198
|
-
async function initZipPeek({ workerUrl, scopeUrl, reloadOnFirstInstall = true, cacheClearingStrategy = "keep-all", allowedZipUrls, requireExactManifestPath = false, zipAssetCacheName, assetCacheTtlMs, logPrefix, onError, }) {
|
|
314
|
+
async function initZipPeek({ workerUrl, scopeUrl, reloadOnFirstInstall = true, cacheClearingStrategy = "keep-all", allowedZipUrls, requireExactManifestPath = false, zipAssetCacheName, assetCacheTtlMs, logPrefix, onError, onUrlExpiry, }) {
|
|
199
315
|
if (onError) {
|
|
200
316
|
currentOnError = onError;
|
|
201
317
|
}
|
|
318
|
+
if (onUrlExpiry) {
|
|
319
|
+
currentOnUrlExpiry = onUrlExpiry;
|
|
320
|
+
}
|
|
202
321
|
try {
|
|
203
322
|
const normalizedAllowedZipUrls = normalizeAllowedZipUrls(allowedZipUrls);
|
|
204
323
|
if (cacheClearingStrategy === "keep-allowed-urls" && !normalizedAllowedZipUrls) {
|
|
@@ -260,6 +379,17 @@ async function initZipPeek({ workerUrl, scopeUrl, reloadOnFirstInstall = true, c
|
|
|
260
379
|
allowedZipUrls: normalizedAllowedZipUrls,
|
|
261
380
|
}, "Failed to preload ZIP manifests");
|
|
262
381
|
}
|
|
382
|
+
if (onUrlExpiry && allowedZipUrls) {
|
|
383
|
+
ensureExpiryWakeListeners();
|
|
384
|
+
// Schedule from the original (pre-set-dedupe) URLs so query params used
|
|
385
|
+
// for expiry parsing are retained; timers are keyed by normalized form.
|
|
386
|
+
for (const zipUrl of allowedZipUrls) {
|
|
387
|
+
const resolvedZipUrl = new URL(zipUrl, window.location.href).href;
|
|
388
|
+
if ((0, zip_utils_1.isZipPackage)(resolvedZipUrl)) {
|
|
389
|
+
scheduleUrlExpiry((0, zip_utils_1.normalizeZipUrl)(resolvedZipUrl), resolvedZipUrl);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
263
393
|
return { reloaded: false, initialized: true };
|
|
264
394
|
}
|
|
265
395
|
catch (error) {
|
|
@@ -267,3 +397,45 @@ async function initZipPeek({ workerUrl, scopeUrl, reloadOnFirstInstall = true, c
|
|
|
267
397
|
throw error;
|
|
268
398
|
}
|
|
269
399
|
}
|
|
400
|
+
/**
|
|
401
|
+
* Replace a presigned ZIP package URL after renewal so the service worker
|
|
402
|
+
* continue serving assets with the new credentials.
|
|
403
|
+
*/
|
|
404
|
+
async function renewPresignedUrl({ previousUrl, nextUrl }) {
|
|
405
|
+
if (!("serviceWorker" in navigator)) {
|
|
406
|
+
throw (0, types_1.createZipPeekError)("Service Worker API not supported in this browser.");
|
|
407
|
+
}
|
|
408
|
+
// Prefer the host-provided absolute strings as-is so SigV4 query encoding is
|
|
409
|
+
// preserved; only resolve relative URLs against the page location.
|
|
410
|
+
const resolvedPrevious = /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(previousUrl)
|
|
411
|
+
? previousUrl
|
|
412
|
+
: new URL(previousUrl, window.location.href).href;
|
|
413
|
+
const resolvedNext = /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(nextUrl)
|
|
414
|
+
? nextUrl
|
|
415
|
+
: new URL(nextUrl, window.location.href).href;
|
|
416
|
+
if (!(0, zip_utils_1.isZipPackage)(resolvedPrevious) || !(0, zip_utils_1.isZipPackage)(resolvedNext)) {
|
|
417
|
+
throw (0, types_1.createZipPeekError)("renewPresignedUrl requires both previousUrl and nextUrl to be ZIP package URLs.");
|
|
418
|
+
}
|
|
419
|
+
const previous = (0, zip_utils_1.normalizeZipUrl)(resolvedPrevious);
|
|
420
|
+
const next = (0, zip_utils_1.normalizeZipUrl)(resolvedNext);
|
|
421
|
+
await postWorkerMessageOrThrow({
|
|
422
|
+
type: "RENEW_ZIP_URL",
|
|
423
|
+
previousUrl: previous,
|
|
424
|
+
nextUrl: next,
|
|
425
|
+
}, "Failed to renew ZIP URL in service worker");
|
|
426
|
+
const files = sessionManifests.get(previous);
|
|
427
|
+
if (files) {
|
|
428
|
+
sessionManifests.set(next, files);
|
|
429
|
+
sessionManifests.delete(previous);
|
|
430
|
+
}
|
|
431
|
+
// Drop the previous URL and any orphaned tracked URLs for the same zip path
|
|
432
|
+
// (e.g. when a prior renew used a mismatched previousUrl and left a timer-less entry).
|
|
433
|
+
const nextPath = zipPackagePathname(next);
|
|
434
|
+
for (const [normalized] of [...trackedZipUrls]) {
|
|
435
|
+
if (normalized === previous || zipPackagePathname(normalized) === nextPath) {
|
|
436
|
+
trackedZipUrls.delete(normalized);
|
|
437
|
+
clearUrlExpiryTimer(normalized);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
scheduleUrlExpiry(next, resolvedNext);
|
|
441
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -5,6 +5,14 @@ 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
|
+
*/
|
|
11
|
+
export type ZipPeekUrlExpiryHandler = () => void | Promise<void>;
|
|
12
|
+
export type RenewPresignedUrlOptions = {
|
|
13
|
+
previousUrl: string;
|
|
14
|
+
nextUrl: string;
|
|
15
|
+
};
|
|
8
16
|
export type InitZipPeekOptions = {
|
|
9
17
|
workerUrl: string;
|
|
10
18
|
scopeUrl: string;
|
|
@@ -16,6 +24,15 @@ export type InitZipPeekOptions = {
|
|
|
16
24
|
assetCacheTtlMs?: number;
|
|
17
25
|
logPrefix?: string;
|
|
18
26
|
onError?: ZipPeekErrorHandler;
|
|
27
|
+
/**
|
|
28
|
+
* Called shortly before a recognized presigned URL expires (CloudFront
|
|
29
|
+
* `Expires` or S3 `X-Amz-Date` + `X-Amz-Expires`). Also invoked after tab
|
|
30
|
+
* wake when a timer was missed due to sleep or background throttling.
|
|
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.
|
|
34
|
+
*/
|
|
35
|
+
onUrlExpiry?: ZipPeekUrlExpiryHandler;
|
|
19
36
|
};
|
|
20
37
|
export type InitZipPeekResult = {
|
|
21
38
|
reloaded: boolean;
|
package/dist/zip-utils.d.ts
CHANGED
|
@@ -32,3 +32,9 @@ export type ParsedZipAssetRequest = {
|
|
|
32
32
|
export declare function parseZipAssetRequest(urlString: string): ParsedZipAssetRequest | null;
|
|
33
33
|
/** Cache key for a zip asset (decoded manifest key + normalized zip URL). */
|
|
34
34
|
export declare function canonicalZipAssetRequestUrl(zipUrl: string, manifestKey: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Parse CloudFront `Expires` or S3 `X-Amz-Date` + `X-Amz-Expires` into an
|
|
37
|
+
* absolute expiry time in ms. Returns `null` when the URL is not recognized
|
|
38
|
+
* as a time-limited presigned URL.
|
|
39
|
+
*/
|
|
40
|
+
export declare function getPresignedUrlExpiryMs(url: string): number | null;
|
package/dist/zip-utils.js
CHANGED
|
@@ -6,6 +6,7 @@ exports.zipBasenameWithoutExtension = zipBasenameWithoutExtension;
|
|
|
6
6
|
exports.normalizeZipEntryPath = normalizeZipEntryPath;
|
|
7
7
|
exports.parseZipAssetRequest = parseZipAssetRequest;
|
|
8
8
|
exports.canonicalZipAssetRequestUrl = canonicalZipAssetRequestUrl;
|
|
9
|
+
exports.getPresignedUrlExpiryMs = getPresignedUrlExpiryMs;
|
|
9
10
|
/** True when the URL points at a `.zip` package (path ends with `.zip`). */
|
|
10
11
|
function isZipPackage(url) {
|
|
11
12
|
try {
|
|
@@ -116,3 +117,65 @@ function parseZipAssetRequest(urlString) {
|
|
|
116
117
|
function canonicalZipAssetRequestUrl(zipUrl, manifestKey) {
|
|
117
118
|
return zipUrl + "/" + encodeURIComponent(manifestKey);
|
|
118
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Read a raw query param value without `URLSearchParams` so SigV4 `%2F`
|
|
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`.
|
|
129
|
+
*/
|
|
130
|
+
function getRawQueryParam(urlString, name, options = {}) {
|
|
131
|
+
const { stopAtPathSeparator = true } = options;
|
|
132
|
+
const qIdx = urlString.indexOf("?");
|
|
133
|
+
if (qIdx === -1)
|
|
134
|
+
return null;
|
|
135
|
+
const hashIdx = urlString.indexOf("#", qIdx);
|
|
136
|
+
const querySection = hashIdx === -1
|
|
137
|
+
? urlString.substring(qIdx + 1)
|
|
138
|
+
: urlString.substring(qIdx + 1, hashIdx);
|
|
139
|
+
const slashIdx = stopAtPathSeparator ? querySection.indexOf("/") : -1;
|
|
140
|
+
const signedQuery = slashIdx === -1 ? querySection : querySection.substring(0, slashIdx);
|
|
141
|
+
for (const part of signedQuery.split("&")) {
|
|
142
|
+
const eqIdx = part.indexOf("=");
|
|
143
|
+
const k = eqIdx === -1 ? part : part.substring(0, eqIdx);
|
|
144
|
+
if (k === name) {
|
|
145
|
+
return eqIdx === -1 ? "" : part.substring(eqIdx + 1);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Parse CloudFront `Expires` or S3 `X-Amz-Date` + `X-Amz-Expires` into an
|
|
152
|
+
* absolute expiry time in ms. Returns `null` when the URL is not recognized
|
|
153
|
+
* as a time-limited presigned URL.
|
|
154
|
+
*/
|
|
155
|
+
function getPresignedUrlExpiryMs(url) {
|
|
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");
|
|
159
|
+
if (expiresRaw != null && expiresRaw !== "") {
|
|
160
|
+
const expiresSec = Number(expiresRaw);
|
|
161
|
+
if (Number.isFinite(expiresSec) && expiresSec > 0) {
|
|
162
|
+
return expiresSec * 1000;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const amzDate = param("X-Amz-Date");
|
|
166
|
+
const amzExpires = param("X-Amz-Expires");
|
|
167
|
+
if (amzDate && amzExpires) {
|
|
168
|
+
// X-Amz-Date is YYYYMMDD'T'HHMMSS'Z'
|
|
169
|
+
const match = /^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})Z$/.exec(amzDate);
|
|
170
|
+
if (!match)
|
|
171
|
+
return null;
|
|
172
|
+
const [, y, mo, d, h, mi, s] = match;
|
|
173
|
+
const startMs = Date.UTC(Number(y), Number(mo) - 1, Number(d), Number(h), Number(mi), Number(s));
|
|
174
|
+
const durationSec = Number(amzExpires);
|
|
175
|
+
if (!Number.isFinite(startMs) || !Number.isFinite(durationSec) || durationSec <= 0) {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
return startMs + durationSec * 1000;
|
|
179
|
+
}
|
|
180
|
+
return null;
|
|
181
|
+
}
|
package/dist/zipServiceWorker.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(()=>{"use strict";var e={180(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]"},451(e,t,n){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 async function(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)}}(t)}},t.isZipUrlAllowed=function(e){return null===i.allowedZipUrls||i.allowedZipUrls.has(e)};const r=n(134),i=n(167),s=n(777)},919(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(s.runtimeConfig.zipAssetCacheName),t=await e.keys();await Promise.all(t.map(t=>e.delete(t))),await caches.delete(s.CONFIG_CACHE_NAME),s.zipManifests.clear(),s.pendingManifestLoads.clear(),(0,s.setAllowedZipUrlsLoaded)(Promise.resolve())},t.clearZipAssetsExceptAllowed=async function(e){try{const t=new Set(e),n=await caches.open(s.runtimeConfig.zipAssetCacheName),r=await n.keys();for(const e of r){const r=e.url;if(r.includes(s.MANIFEST_CACHE_KEY)){const i=(0,o.zipUrlFromManifestCacheKey)(r);i&&!t.has(i)&&await n.delete(e);continue}const a=(0,i.parseZipAssetRequest)(r);a&&!t.has(a.zipUrl)&&await n.delete(e)}for(const e of s.zipManifests.keys())t.has(e)||s.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(s.runtimeConfig.zipAssetCacheName),r=await n.match(e);if(r&&!l(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":"*",[s.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(s.runtimeConfig.zipAssetCacheName),i=await r.match(e);if(i)if(l(i))try{await r.delete(e)}catch(e){(0,a.warn)("asset cache delete expired failed",e)}else t=await i.blob(),n="cache-api"}catch(e){(0,a.warn)("asset cache read failed",e)}return{blob:t,assetSource:n}};const r=n(180),i=n(134),s=n(167),a=n(777),o=n(483);function l(e){const t=e.headers.get(s.ASSET_CACHED_AT_HEADER);if(!t)return!0;const n=parseInt(t,10);return!Number.isFinite(n)||Date.now()-n>s.runtimeConfig.assetCacheTtlMs}},705(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,h=(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,h,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:h,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:E,matchKind:w}=i;"zipBasenameFallback"===w&&((0,l.log)("resolved via zip-basename folder fallback",{requested:h,manifestKey:d}),(0,l.reportClientError)(new Error((0,r.formatZipPeekError)("Exact manifest path not found; resolved via zip-basename folder fallback")),`Exact manifest key "${h}" not found in ${m}; resolved using "${d}"`));const y=(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 p(null,r,i,"manifest",s);const a={"Content-Type":r,...u("manifest")};return null!==i&&(a["Content-Length"]=i.toString()),new Response(null,{status:200,headers:a})}(e.request,d,E);let{blob:A,assetSource:C}=await(0,a.readCachedZipAssetIfFresh)(y);if(!A){const e=await(0,f.fetchUncompressedZipEntryFromNetwork)(m,d,E,y);if(!e.ok)return e.response;A=e.blob,C="network"}return p(A,A.type,A.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(180),i=n(134),s=n(451),a=n(919),o=n(167),l=n(777),c=n(483),f=n(237);function u(e){return{"Access-Control-Allow-Origin":"*","Access-Control-Expose-Headers":o.ASSET_SOURCE_HEADER,[o.ASSET_SOURCE_HEADER]:e}}function p(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}`,...u(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}`,...u(r)}});const f=Math.min(c,n-1),p=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":p.toString(),"Accept-Ranges":"bytes",...u(r)}})}return new Response(e,{status:200,headers:{"Content-Type":t,"Content-Length":n.toString(),...u(r)}})}},167(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},777(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(180),i=n(167);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)})}},483(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 u=t.headers.get("Content-Range");let p=0;if(u){const e=u.match(/\/(\d+)$/);e&&(p=parseInt(e[1],10))}if(p<=0)return(0,s.error)("could not determine ZIP file size from Content-Range header",{zipUrl:e,contentRange:u}),null;const d=p-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),u=a.getUint32(o+42,!0),p=new TextDecoder;if(o+46+s>e.byteLength)break;const d=new Uint8Array(e,o+46,s),m=p.decode(d),g=(0,r.normalizeZipEntryPath)(m);""!==g&&l.push({filename:g,offset:u,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(134),i=n(167),s=n(777);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)}}},814(e,t,n){t.installMessageHandler=function(){self.addEventListener("message",e=>{if(!e.data)return;const{type:t,zipUrl:n,files:p,config:d,allowedZipUrls:m}=e.data,g=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(()=>u(e,{ok:!0})).catch(t=>u(e,f(t)));return void e.waitUntil(t)}if("ZIP_MANIFEST"===t){if(n&&p){const t=(0,i.normalizeZipUrl)(n),r=(0,c.manifestFilesToMap)(p),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,g));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(()=>u(e,{ok:!0})).catch(t=>u(e,f(t)));e.waitUntil(t)}else if("CLEAR_ALL_ZIP_ASSETS"===t){const t=(0,a.clearAllZipAssets)().then(()=>u(e,{ok:!0})).catch(t=>u(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,g).then(()=>u(e,{ok:!0})).catch(t=>u(e,f(t)));e.waitUntil(t)}})};const r=n(180),i=n(134),s=n(451),a=n(919),o=n(167),l=n(777),c=n(483);function f(e){const t=(0,r.toZipPeekError)(e);return{ok:!1,error:t.message,errorStack:t.stack}}function u(e,t){e.ports[0]?.postMessage(t)}},237(e,t,n){t.corsErrorResponse=l,t.getMimeType=c,t.fetchUncompressedZipEntryFromNetwork=async function(e,t,n,i){const f=n.offset,u=n.nextOffset-1;(0,a.log)("fetching zip chunk from",{zipUrl:e,rangeStart:f,rangeEnd:u});const p=await fetch(e,{headers:{Range:`bytes=${f}-${u}`}});if(206!==p.status)return{ok:!1,response:l(`ZIP entry fetch for "${t}" expected HTTP 206 Partial Content from ${e}, got ${p.status}`,p.status>=400?p.status:502)};const d=await p.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 h=new Uint8Array(d,g,n.compressedSize);let E;if(8===n.compression)try{E=(0,r.inflateSync)(h)}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)};E=h}const w=c(t),y=new Blob([E],{type:w});return await(0,o.putCachedFullAssetIfAbsent)(i,y),{ok:!0,blob:y}};const r=n(612),i=n(180),s=n(167),a=n(777),o=n(919);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"}},134(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("?"),u=-1===f?c:c.substring(0,f);return""===u?null:{zipUrl:s+l,internalPath:n(u)}},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,u=c.r;f[28]=258,u[258]=28;for(var p=l(a,0),d=p.b,m=(p.r,new r(32768)),g=0;g<32768;++g){var h=(43690&g)>>1|(21845&g)<<1;h=(61680&(h=(52428&h)>>2|(13107&h)<<2))>>4|(3855&h)<<4,m[g]=((65280&h)>>8|(255&h)<<8)>>1}var E=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],u=t-e[s],p=l[e[s]-1]++<<u,d=p|(1<<u)-1;p<=d;++p)o[m[p]>>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},w=new n(288);for(g=0;g<144;++g)w[g]=8;for(g=144;g<256;++g)w[g]=9;for(g=256;g<280;++g)w[g]=7;for(g=280;g<288;++g)w[g]=8;var y=new n(32);for(g=0;g<32;++g)y[g]=5;var A=E(w,9,1),C=E(y,5,1),z=function(e){for(var t=e[0],n=1;n<e.length;++n)e[n]>t&&(t=e[n]);return t},_=function(e,t,n){var r=t/8|0;return(e[r]|e[r+1]<<8)>>(7&t)&n},U=function(e,t){var n=t/8|0;return(e[n]|e[n+1]<<8|e[n+2]<<16)>>(7&t)},S=function(e){return(e+7)/8|0},Z=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"],R=function(e,t,n){var r=new Error(t||v[e]);if(r.code=e,Error.captureStackTrace&&Error.captureStackTrace(r,R),!n)throw r;return r},P=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 u=!r,p=u||2!=t.i,m=t.i;u&&(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}},h=t.f||0,w=t.p||0,y=t.b||0,v=t.l,P=t.d,M=t.m,b=t.n,I=8*l;do{if(!v){h=_(e,w,1);var k=_(e,w+1,3);if(w+=3,!k){var T=e[(W=S(w)+4)-4]|e[W-3]<<8,x=W+T;if(x>l){m&&R(0);break}p&&g(y+T),r.set(e.subarray(W,x),y),t.b=y+=T,t.p=w=8*x,t.f=h;continue}if(1==k)v=A,P=C,M=9,b=5;else if(2==k){var L=_(e,w,31)+257,F=_(e,w+10,15)+4,N=L+_(e,w+5,31)+1;w+=14;for(var O=new n(N),$=new n(19),H=0;H<F;++H)$[o[H]]=_(e,w+3*H,7);w+=3*F;var D=z($),q=(1<<D)-1,K=E($,D,1);for(H=0;H<N;){var W,j=K[_(e,w,q)];if(w+=15&j,(W=j>>4)<16)O[H++]=W;else{var G=0,Y=0;for(16==W?(Y=3+_(e,w,3),w+=2,G=O[H-1]):17==W?(Y=3+_(e,w,7),w+=3):18==W&&(Y=11+_(e,w,127),w+=7);Y--;)O[H++]=G}}var B=O.subarray(0,L),X=O.subarray(L);M=z(B),b=z(X),v=E(B,M,1),P=E(X,b,1)}else R(1);if(w>I){m&&R(0);break}}p&&g(y+131072);for(var V=(1<<M)-1,J=(1<<b)-1,Q=w;;Q=w){var ee=(G=v[U(e,w)&V])>>4;if((w+=15&G)>I){m&&R(0);break}if(G||R(2),ee<256)r[y++]=ee;else{if(256==ee){Q=w,v=null;break}var te=ee-254;if(ee>264){var ne=s[H=ee-257];te=_(e,w,(1<<ne)-1)+f[H],w+=ne}var re=P[U(e,w)&J],ie=re>>4;if(re||R(3),w+=15&re,X=d[ie],ie>3&&(ne=a[ie],X+=U(e,w)&(1<<ne)-1,w+=ne),w>I){m&&R(0);break}p&&g(y+131072);var se=y+te;if(y<X){var ae=c-X,oe=Math.min(X,se);for(ae+y<0&&R(3);y<oe;++y)r[y]=i[ae+y]}for(;y<se;++y)r[y]=r[y-X]}}t.l=v,t.p=Q,t.b=y,t.f=h,v&&(h=1,t.m=M,t.d=P,t.n=b)}while(!h);return y!=r.length&&u?Z(r,0,y):r.subarray(0,y)},M=new n(0);function b(e,t){return P(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}},t={};function n(r){var i=t[r];if(void 0!==i)return i.exports;var s=t[r]={exports:{}};return e[r](s,s.exports,n),s.exports}(()=>{const e=n(777),t=n(705),r=n(814);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=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)()})()})();
|
|
2
2
|
//# sourceMappingURL=zipServiceWorker.js.map
|