@zip.js/zip.js 2.11.4 → 2.13.0

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.
Files changed (52) hide show
  1. package/deno.json +1 -1
  2. package/dist/zip-core-external.js +549 -139
  3. package/dist/zip-core-external.min.js +1 -1
  4. package/dist/zip-core.js +559 -136
  5. package/dist/zip-core.min.js +1 -1
  6. package/dist/zip-fs-core-external.js +615 -260
  7. package/dist/zip-fs-core-external.min.js +1 -1
  8. package/dist/zip-fs-core.js +628 -257
  9. package/dist/zip-fs-core.min.js +1 -1
  10. package/dist/zip-fs-external.js +615 -260
  11. package/dist/zip-fs-external.min.js +1 -1
  12. package/dist/zip-fs-native.js +630 -259
  13. package/dist/zip-fs-native.min.js +1 -1
  14. package/dist/zip-fs.js +631 -260
  15. package/dist/zip-fs.min.js +1 -1
  16. package/dist/zip-legacy.js +561 -138
  17. package/dist/zip-legacy.min.js +1 -1
  18. package/dist/zip-native.js +561 -138
  19. package/dist/zip-native.min.js +1 -1
  20. package/dist/zip-web-worker-native.js +1 -1
  21. package/dist/zip-web-worker.js +1 -1
  22. package/dist/zip.js +562 -139
  23. package/dist/zip.min.js +1 -1
  24. package/index-native.cjs +630 -259
  25. package/index-native.min.js +1 -1
  26. package/index.cjs +631 -260
  27. package/index.d.cts +474 -59
  28. package/index.d.ts +474 -59
  29. package/index.min.js +1 -1
  30. package/lib/core/codec-worker-web.js +72 -22
  31. package/lib/core/codec-worker.js +18 -5
  32. package/lib/core/configuration.js +20 -5
  33. package/lib/core/constants.js +2 -0
  34. package/lib/core/io.js +13 -5
  35. package/lib/core/options.js +16 -0
  36. package/lib/core/streams/codec-stream.js +6 -0
  37. package/lib/core/util/error.js +35 -0
  38. package/lib/core/util/warnings.js +42 -0
  39. package/lib/core/version.js +1 -1
  40. package/lib/core/web-worker-base.js +46 -9
  41. package/lib/core/web-worker-inline-native.js +1 -1
  42. package/lib/core/web-worker-inline-wasm.js +1 -1
  43. package/lib/core/zip-entry.js +49 -1
  44. package/lib/core/zip-fs.js +45 -133
  45. package/lib/core/zip-reader.js +115 -52
  46. package/lib/core/zip-writer.js +244 -57
  47. package/lib/zip-core-base.js +9 -3
  48. package/lib/zip-core-reader.js +2 -0
  49. package/lib/zip-core-writer.js +6 -1
  50. package/lib/zip-module-wasm-base.js +2 -2
  51. package/package.json +5 -3
  52. package/worker-message-property-names.js +1 -1
@@ -134,6 +134,7 @@
134
134
  const BOOLEAN_TYPE = "boolean";
135
135
 
136
136
  const EMPTY_UINT8_ARRAY = new Uint8Array();
137
+ const SYMBOL_ASYNC_DISPOSE = Symbol.asyncDispose || Symbol();
137
138
 
138
139
  /*
139
140
  Copyright (c) 2022 Gildas Lormeau. All rights reserved.
@@ -178,6 +179,7 @@
178
179
  const OPTION_CHECK_OVERLAPPING_ENTRY = "checkOverlappingEntry";
179
180
  const OPTION_CHECK_AMBIGUITY = "checkAmbiguity";
180
181
  const OPTION_CHECK_LOCAL_DIRECTORY = "checkLocalDirectory";
182
+ const OPTION_CHECK_LOCAL_FILENAME = "checkLocalFilename";
181
183
  const OPTION_CHECK_SIGNATURE = "checkSignature";
182
184
  const OPTION_CHECK_CRC32 = "checkCrc32";
183
185
  const OPTION_CHECK_AUTHENTICATION_CODE = "checkAuthenticationCode";
@@ -208,15 +210,18 @@
208
210
  const OPTION_MAX_APPENDED_DATA_SIZE = "maxAppendedDataSize";
209
211
  const OPTION_DECRYPT_CENTRAL_DIRECTORY = "decryptCentralDirectory";
210
212
  const OPTION_SIGN_CENTRAL_DIRECTORY = "signCentralDirectory";
213
+ const OPTION_ENTRY = "entry";
211
214
  const TEXT_TYPE_FILENAME = "filename";
212
215
  const TEXT_TYPE_COMMENT = "comment";
213
216
  const STRICTNESS_STRICT = "strict";
214
217
  const STRICTNESS_BALANCED = "balanced";
215
218
  const STRICTNESS_TOLERANT = "tolerant";
219
+ const PASS_THROUGH_COMPRESSED = "compressed";
216
220
 
217
221
  const ERR_INVALID_FUNCTION_OPTION = "Invalid option (must be a function)";
218
222
  const ERR_INVALID_SIGNAL = "Invalid signal (must be an AbortSignal instance)";
219
223
  const ERR_INVALID_PASSWORD_TYPE = "Invalid password (password must be a string, rawPassword must be a Uint8Array)";
224
+ const ERR_INVALID_PASS_THROUGH_VALUE = "Invalid passThrough option (must be a boolean or 'compressed')";
220
225
  const ERR_ABORTED = "The operation was aborted";
221
226
  const ABORT_ERROR_NAME = "AbortError";
222
227
 
@@ -246,6 +251,13 @@
246
251
  }
247
252
  }
248
253
 
254
+ function checkPassThroughOption(passThrough) {
255
+ if (passThrough !== UNDEFINED_VALUE && typeof passThrough != BOOLEAN_TYPE && passThrough !== PASS_THROUGH_COMPRESSED) {
256
+ throw new Error(ERR_INVALID_PASS_THROUGH_VALUE);
257
+ }
258
+ return passThrough;
259
+ }
260
+
249
261
  function checkInteger(value, maxValue, errorMessage) {
250
262
  if (!Number.isInteger(value) || value < 0 || value > maxValue) {
251
263
  throw new Error(errorMessage);
@@ -295,6 +307,8 @@
295
307
  const MINIMUM_CHUNK_SIZE = 64;
296
308
  const MINIMUM_PROPERTY_VALUE = 1;
297
309
  const ERR_INVALID_MAX_WORKERS = "Invalid maxWorkers (must be an integer greater than 0)";
310
+ const ERR_INVALID_BASE_URI = "Invalid baseURI (must be a string)";
311
+ const ERR_INVALID_URI = "Invalid URI (must be a string or a function returning a string)";
298
312
  let maxWorkers = 2;
299
313
  try {
300
314
  if (typeof navigator != UNDEFINED_TYPE && navigator.hardwareConcurrency) {
@@ -319,9 +333,9 @@
319
333
  };
320
334
 
321
335
  const PROPERTY_NAME_MAX_WORKERS = "maxWorkers";
336
+ const PROPERTY_NAME_BASE_URI = "baseURI";
322
337
 
323
- const STRING_PROPERTY_NAMES = [
324
- "baseURI",
338
+ const URI_PROPERTY_NAMES = [
325
339
  "wasmURI",
326
340
  "workerURI"
327
341
  ];
@@ -345,7 +359,8 @@
345
359
  "DecompressionStreamFallback"
346
360
  ];
347
361
  const CONFIGURABLE_PROPERTY_NAMES = [
348
- ...STRING_PROPERTY_NAMES,
362
+ PROPERTY_NAME_BASE_URI,
363
+ ...URI_PROPERTY_NAMES,
349
364
  ...BOOLEAN_PROPERTY_NAMES,
350
365
  ...NUMBER_PROPERTY_NAMES,
351
366
  ...FUNCTION_PROPERTY_NAMES
@@ -389,6 +404,14 @@
389
404
  }
390
405
  } else if (FUNCTION_PROPERTY_NAMES.includes(propertyName)) {
391
406
  checkFunctionOption(propertyValue);
407
+ } else if (propertyName == PROPERTY_NAME_BASE_URI) {
408
+ if (propertyValue && typeof propertyValue != STRING_TYPE) {
409
+ throw new Error(ERR_INVALID_BASE_URI);
410
+ }
411
+ } else if (URI_PROPERTY_NAMES.includes(propertyName)) {
412
+ if (propertyValue && typeof propertyValue != STRING_TYPE && typeof propertyValue != FUNCTION_TYPE) {
413
+ throw new Error(ERR_INVALID_URI);
414
+ }
392
415
  }
393
416
  return propertyValue;
394
417
  }
@@ -466,6 +489,39 @@
466
489
  return new DataView(array.buffer, array.byteOffset, array.byteLength);
467
490
  }
468
491
 
492
+ /*
493
+ Copyright (c) 2026 Gildas Lormeau. All rights reserved.
494
+
495
+ Redistribution and use in source and binary forms, with or without
496
+ modification, are permitted provided that the following conditions are met:
497
+
498
+ 1. Redistributions of source code must retain the above copyright notice,
499
+ this list of conditions and the following disclaimer.
500
+
501
+ 2. Redistributions in binary form must reproduce the above copyright
502
+ notice, this list of conditions and the following disclaimer in
503
+ the documentation and/or other materials provided with the distribution.
504
+
505
+ 3. The names of the authors may not be used to endorse or promote products
506
+ derived from this software without specific prior written permission.
507
+
508
+ THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
509
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
510
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
511
+ INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
512
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
513
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
514
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
515
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
516
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
517
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
518
+ */
519
+
520
+
521
+ function isErrorObject(error) {
522
+ return Boolean(error) && typeof error == "object";
523
+ }
524
+
469
525
  /*
470
526
  Copyright (c) 2022 Gildas Lormeau. All rights reserved.
471
527
 
@@ -2605,6 +2661,7 @@
2605
2661
  constructor(chunkSize) {
2606
2662
  const pendingChunks = [];
2607
2663
  let pendingLength = 0;
2664
+ let outputSize = 0;
2608
2665
  if (!Number.isFinite(chunkSize) || chunkSize < 1) {
2609
2666
  chunkSize = DEFAULT_CHUNK_SIZE;
2610
2667
  }
@@ -2613,15 +2670,20 @@
2613
2670
  pendingChunks.push(chunk);
2614
2671
  pendingLength += chunk.length;
2615
2672
  while (pendingLength > chunkSize) {
2673
+ outputSize += chunkSize;
2616
2674
  controller.enqueue(shiftChunk());
2617
2675
  }
2618
2676
  },
2619
2677
  flush(controller) {
2620
2678
  if (pendingLength) {
2679
+ outputSize += pendingLength;
2621
2680
  controller.enqueue(concatChunks(pendingChunks, pendingLength));
2622
2681
  }
2623
2682
  }
2624
2683
  });
2684
+ Object.defineProperty(this, "outputSize", {
2685
+ get: () => outputSize
2686
+ });
2625
2687
 
2626
2688
  function shiftChunk() {
2627
2689
  const result = new Uint8Array(chunkSize);
@@ -2727,7 +2789,9 @@
2727
2789
 
2728
2790
  class CodecWorker {
2729
2791
 
2730
- constructor(workerData, { readable, writable }, { options, config, streamOptions, useWebWorkers, transferStreams, workerURI, createWorker }, onTaskFinished) {
2792
+ constructor(workerData, { readable, writable }, workerOptions, onTaskFinished) {
2793
+ const { options, config, streamOptions, useWebWorkers, transferStreams, workerURI } = workerOptions;
2794
+ let { createWorker } = workerOptions;
2731
2795
  const { signal } = streamOptions;
2732
2796
  if (createWorkerFailed) {
2733
2797
  createWorker = UNDEFINED_VALUE;
@@ -2740,6 +2804,7 @@
2740
2804
  .pipeThrough(new ProgressWatcherStream(streamOptions), { signal }),
2741
2805
  writable,
2742
2806
  options: Object.assign({}, options),
2807
+ workerOptions,
2743
2808
  workerURI,
2744
2809
  createWorker,
2745
2810
  transferStreams,
@@ -2821,8 +2886,8 @@
2821
2886
  };
2822
2887
  }
2823
2888
 
2824
- async function runWorker$1({ options, readable, writable, onTaskFinished }, config) {
2825
- let codecStream;
2889
+ async function runWorker$1({ options, readable, writable, onTaskFinished, workerOptions }, config) {
2890
+ let codecStream, chunkStream;
2826
2891
  try {
2827
2892
  if (options.compressed && !options.format) {
2828
2893
  const deflate = options.codecType.startsWith(CODEC_DEFLATE);
@@ -2845,9 +2910,10 @@
2845
2910
  }
2846
2911
  }
2847
2912
  codecStream = new CodecStream(options, config);
2913
+ chunkStream = new ChunkStream(getChunkSize(config));
2848
2914
  await readable
2849
2915
  .pipeThrough(codecStream)
2850
- .pipeThrough(new ChunkStream(getChunkSize(config)))
2916
+ .pipeThrough(chunkStream)
2851
2917
  .pipeTo(writable, { preventClose: true, preventAbort: true });
2852
2918
  const {
2853
2919
  crc32,
@@ -2861,7 +2927,15 @@
2861
2927
  };
2862
2928
  } catch (error) {
2863
2929
  if (codecStream) {
2864
- error.outputSize = codecStream.outputSize;
2930
+ const outputSize = chunkStream ? chunkStream.outputSize : 0;
2931
+ workerOptions.outputSize = outputSize;
2932
+ if (isErrorObject(error)) {
2933
+ try {
2934
+ error.outputSize = outputSize;
2935
+ } catch {
2936
+ // ignored
2937
+ }
2938
+ }
2865
2939
  }
2866
2940
  throw error;
2867
2941
  } finally {
@@ -2970,11 +3044,23 @@
2970
3044
  let resolveResult, rejectResult;
2971
3045
  const result = new Promise((resolve, reject) => {
2972
3046
  resolveResult = resolve;
2973
- rejectResult = reject;
3047
+ rejectResult = error => {
3048
+ const { outputSize, workerOptions } = workerData;
3049
+ workerOptions.outputSize = outputSize;
3050
+ if (isErrorObject(error) && error.outputSize === UNDEFINED_VALUE) {
3051
+ try {
3052
+ error.outputSize = outputSize;
3053
+ } catch {
3054
+ // ignored
3055
+ }
3056
+ }
3057
+ reject(error);
3058
+ };
2974
3059
  });
2975
3060
  Object.assign(workerData, {
2976
3061
  reader: null,
2977
3062
  writer: null,
3063
+ outputSize: 0,
2978
3064
  resolveResult,
2979
3065
  rejectResult,
2980
3066
  result
@@ -3235,21 +3321,15 @@
3235
3321
  }
3236
3322
 
3237
3323
  async function onMessage({ data }, workerData) {
3238
- const { type, value, messageId, result, error } = data;
3324
+ const { type, value, messageId, result, error, errorValue } = data;
3239
3325
  const { reader, writer, resolveResult, rejectResult, onTaskFinished, generation } = workerData;
3240
3326
  const stale = () => workerData.generation != generation;
3241
3327
  try {
3242
3328
  if (error) {
3243
- const { message, stack, code, name, outputSize, cause, codecImportFailed } = error;
3244
- const responseError = new Error(message);
3245
- Object.assign(responseError, { stack, code, name, outputSize });
3246
- if (cause) {
3247
- responseError.cause = Object.assign(new Error(cause.message), { name: cause.name });
3248
- }
3249
- if (codecImportFailed) {
3250
- responseError.codecImportFailed = true;
3329
+ if (error.outputSize !== UNDEFINED_VALUE) {
3330
+ workerData.outputSize = error.outputSize;
3251
3331
  }
3252
- close(responseError);
3332
+ fail(getResponseError(error, errorValue));
3253
3333
  } else {
3254
3334
  if (type == MESSAGE_PULL) {
3255
3335
  const { value, done } = await reader.read();
@@ -3258,39 +3338,82 @@
3258
3338
  }
3259
3339
  }
3260
3340
  if (type == MESSAGE_DATA) {
3341
+ const chunk = new Uint8Array(value);
3261
3342
  await writer.ready;
3262
- await writer.write(new Uint8Array(value));
3343
+ await writer.write(chunk);
3344
+ workerData.outputSize += chunk.length;
3263
3345
  if (!stale()) {
3264
3346
  sendMessage({ type: MESSAGE_ACK_DATA, messageId }, workerData);
3265
3347
  }
3266
3348
  }
3267
3349
  if (type == MESSAGE_CLOSE) {
3268
- close(null, result);
3350
+ succeed(result);
3269
3351
  }
3270
3352
  }
3271
3353
  } catch (error) {
3272
3354
  if (!stale()) {
3273
3355
  terminateWorker$1(workerData);
3274
- close(error);
3356
+ fail(error);
3275
3357
  }
3276
3358
  }
3277
3359
 
3278
- function close(error, result) {
3279
- if (stale()) {
3280
- return;
3281
- }
3282
- if (error) {
3360
+ function fail(error) {
3361
+ if (!stale()) {
3283
3362
  rejectResult(error);
3284
- } else {
3363
+ releaseWriter();
3364
+ if (!(isErrorObject(error) && error.codecImportFailed)) {
3365
+ onTaskFinished();
3366
+ }
3367
+ }
3368
+ }
3369
+
3370
+ function succeed(result) {
3371
+ if (!stale()) {
3285
3372
  resolveResult(result);
3373
+ releaseWriter();
3374
+ onTaskFinished();
3286
3375
  }
3376
+ }
3377
+
3378
+ function releaseWriter() {
3287
3379
  if (writer) {
3288
3380
  writer.releaseLock();
3289
3381
  }
3290
- if (!(error && error.codecImportFailed)) {
3291
- onTaskFinished();
3382
+ }
3383
+ }
3384
+
3385
+ function getResponseError(errorData, errorValue) {
3386
+ const { message, stack, code, name, outputSize, cause, codecImportFailed } = errorData;
3387
+ let responseError;
3388
+ if (errorValue) {
3389
+ responseError = errorValue.value;
3390
+ } else {
3391
+ responseError = Object.assign(new Error(message), { stack, code, name });
3392
+ if (cause) {
3393
+ responseError.cause = Object.assign(new Error(cause.message), { name: cause.name });
3292
3394
  }
3293
3395
  }
3396
+ if (isErrorObject(responseError)) {
3397
+ try {
3398
+ if (outputSize !== UNDEFINED_VALUE) {
3399
+ responseError.outputSize = outputSize;
3400
+ }
3401
+ if (codecImportFailed) {
3402
+ responseError.codecImportFailed = true;
3403
+ }
3404
+ if (errorValue) {
3405
+ if (responseError.name !== name) {
3406
+ responseError.name = name;
3407
+ }
3408
+ if (responseError.code !== code) {
3409
+ responseError.code = code;
3410
+ }
3411
+ }
3412
+ } catch {
3413
+ // ignored
3414
+ }
3415
+ }
3416
+ return responseError;
3294
3417
  }
3295
3418
 
3296
3419
  /*
@@ -3567,10 +3690,13 @@
3567
3690
 
3568
3691
 
3569
3692
  const ERR_HTTP_STATUS = "HTTP error ";
3693
+ const MIN_SUCCESS_HTTP_STATUS = 200;
3694
+ const MAX_SUCCESS_HTTP_STATUS = 299;
3570
3695
  const ERR_HTTP_RANGE = "HTTP Range not supported";
3571
3696
  const ERR_HTTP_RESOURCE_CHANGED = "HTTP resource changed";
3572
3697
  const ERR_ITERATOR_COMPLETED_TOO_SOON = "Writer iterator completed too soon";
3573
3698
  const ERR_WRITER_NOT_INITIALIZED = "Writer not initialized";
3699
+ const ERR_WRITER_SIZE_NOT_WRITABLE = "Invalid writer (size must be writable)";
3574
3700
 
3575
3701
  const CONTENT_TYPE_TEXT_PLAIN = "text/plain";
3576
3702
  const HTTP_HEADER_CONTENT_LENGTH = "Content-Length";
@@ -3762,6 +3888,7 @@
3762
3888
  const reader = this;
3763
3889
  const { sourceBlob, size } = reader;
3764
3890
  const { offset = 0, size: readSize = size - offset } = options || {};
3891
+ // deno-lint-ignore valid-typeof
3765
3892
  if (typeof sourceBlob.stream == FUNCTION_TYPE) {
3766
3893
  if (!offset && readSize >= size) {
3767
3894
  return toCompatibleReadable(sourceBlob.stream());
@@ -4168,7 +4295,7 @@
4168
4295
 
4169
4296
  async function sendFetchRequest(method, { fetch: fetchFunction = fetch, options, url }, headers) {
4170
4297
  const response = await fetchFunction(url, Object.assign({}, options, { method, headers }));
4171
- if (response.status < 400) {
4298
+ if (response.status >= MIN_SUCCESS_HTTP_STATUS && response.status <= MAX_SUCCESS_HTTP_STATUS) {
4172
4299
  return response;
4173
4300
  } else {
4174
4301
  throw response.status == 416 ? new Error(ERR_HTTP_RANGE) : new Error(ERR_HTTP_STATUS + (response.statusText || response.status));
@@ -4179,7 +4306,7 @@
4179
4306
  return new Promise((resolve, reject) => {
4180
4307
  const request = new XMLHttpRequest();
4181
4308
  request.addEventListener("load", () => {
4182
- if (request.status < 400) {
4309
+ if (request.status >= MIN_SUCCESS_HTTP_STATUS && request.status <= MAX_SUCCESS_HTTP_STATUS) {
4183
4310
  const headers = [];
4184
4311
  request.getAllResponseHeaders().trim().split(/[\r\n]+/).forEach(header => {
4185
4312
  const splitHeader = header.trim().split(/\s*:\s*/);
@@ -4483,8 +4610,10 @@
4483
4610
  writable: toCompatibleWritable(writer)
4484
4611
  };
4485
4612
  }
4486
- if (writer.size === UNDEFINED_VALUE) {
4487
- writer.size = 0;
4613
+ try {
4614
+ writer.size = writer.size === UNDEFINED_VALUE ? 0 : writer.size;
4615
+ } catch {
4616
+ throw new Error(ERR_WRITER_SIZE_NOT_WRITABLE);
4488
4617
  }
4489
4618
  return writer;
4490
4619
  }
@@ -4532,6 +4661,45 @@
4532
4661
  }
4533
4662
  }
4534
4663
 
4664
+ /*
4665
+ Copyright (c) 2026 Gildas Lormeau. All rights reserved.
4666
+
4667
+ Redistribution and use in source and binary forms, with or without
4668
+ modification, are permitted provided that the following conditions are met:
4669
+
4670
+ 1. Redistributions of source code must retain the above copyright notice,
4671
+ this list of conditions and the following disclaimer.
4672
+
4673
+ 2. Redistributions in binary form must reproduce the above copyright
4674
+ notice, this list of conditions and the following disclaimer in
4675
+ the documentation and/or other materials provided with the distribution.
4676
+
4677
+ 3. The names of the authors may not be used to endorse or promote products
4678
+ derived from this software without specific prior written permission.
4679
+
4680
+ THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
4681
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
4682
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
4683
+ INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
4684
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4685
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
4686
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
4687
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
4688
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
4689
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4690
+ */
4691
+
4692
+
4693
+ function addWarning(warnings, reason, filename) {
4694
+ if (!warnings.some(warning => warning.reason == reason)) {
4695
+ const warning = { reason };
4696
+ if (filename !== UNDEFINED_VALUE) {
4697
+ warning.filename = filename;
4698
+ }
4699
+ warnings.push(warning);
4700
+ }
4701
+ }
4702
+
4535
4703
  /*
4536
4704
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
4537
4705
 
@@ -4560,6 +4728,7 @@
4560
4728
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4561
4729
  */
4562
4730
 
4731
+
4563
4732
  const PROPERTY_NAME_FILENAME = "filename";
4564
4733
  const PROPERTY_NAME_RAW_FILENAME = "rawFilename";
4565
4734
  const PROPERTY_NAME_COMMENT = "comment";
@@ -4684,6 +4853,38 @@
4684
4853
 
4685
4854
  }
4686
4855
 
4856
+ const INTERPRETED_EXTRA_FIELD_TYPES = new Set([
4857
+ EXTRAFIELD_TYPE_ZIP64,
4858
+ EXTRAFIELD_TYPE_AES,
4859
+ EXTRAFIELD_TYPE_NTFS,
4860
+ EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP,
4861
+ EXTRAFIELD_TYPE_UNICODE_PATH,
4862
+ EXTRAFIELD_TYPE_UNICODE_COMMENT,
4863
+ EXTRAFIELD_TYPE_USDZ,
4864
+ EXTRAFIELD_TYPE_INFOZIP,
4865
+ EXTRAFIELD_TYPE_UNIX,
4866
+ EXTRAFIELD_TYPE_UNIX_TYPE1,
4867
+ EXTRAFIELD_TYPE_PKWARE_UNIX
4868
+ ]);
4869
+
4870
+ function getUserExtraField(extraField) {
4871
+ if (extraField) {
4872
+ const userExtraField = new Map();
4873
+ extraField.forEach((field, type) => {
4874
+ if (!INTERPRETED_EXTRA_FIELD_TYPES.has(type)) {
4875
+ userExtraField.set(type, field.data);
4876
+ }
4877
+ });
4878
+ if (userExtraField.size) {
4879
+ return userExtraField;
4880
+ }
4881
+ }
4882
+ }
4883
+
4884
+ function getEncryptionOverhead(encrypted, zipCrypto, encryptionStrength) {
4885
+ return encrypted ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
4886
+ }
4887
+
4687
4888
  /*
4688
4889
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
4689
4890
 
@@ -4743,6 +4944,8 @@
4743
4944
  const WARNING_TRAILING_CENTRAL_DIRECTORY_DATA = "trailing central directory data";
4744
4945
  const WARNING_DUPLICATE_FILENAME = "duplicate filename";
4745
4946
  const WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY = "mismatched zip64 end of central directory record";
4947
+ const WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY = "multiple end of central directory records";
4948
+ const WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME = "mismatched local file header (filename)";
4746
4949
  const WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG = "mismatched local file header (general purpose bit flag)";
4747
4950
  const WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD = "mismatched local file header (compression method)";
4748
4951
  const WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES = "mismatched local file header (crc32 or sizes)";
@@ -4813,7 +5016,7 @@
4813
5016
  }
4814
5017
  }
4815
5018
  if (rejectAmbiguousEndOfDirectory && endOfDirectoryReachingEndCount > 1) {
4816
- throwAmbiguousArchive("multiple end of central directory records");
5019
+ throwAmbiguousArchive(WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY);
4817
5020
  }
4818
5021
  const endOfDirectoryView = getDataView(endOfDirectoryInfo);
4819
5022
  let directoryDataLength = getUint32$1(endOfDirectoryView, 12);
@@ -5111,7 +5314,8 @@
5111
5314
  const writer = new TransformStream();
5112
5315
  const arrayBufferPromise = streamToBlob(writer.readable).then(blob => blob.arrayBuffer());
5113
5316
  arrayBufferPromise.catch(() => { });
5114
- await fileEntry.getData(writer, entry, zipReader.readRanges, options);
5317
+ await fileEntry.getData(writer, entry, zipReader.readRanges,
5318
+ Object.assign({}, options, { preventClose: false }));
5115
5319
  return arrayBufferPromise;
5116
5320
  };
5117
5321
  offset = endOffset;
@@ -5192,49 +5396,101 @@
5192
5396
  await reader.readable.cancel();
5193
5397
  }
5194
5398
  }
5399
+
5400
+ [SYMBOL_ASYNC_DISPOSE]() {
5401
+ return this.close();
5402
+ }
5195
5403
  }
5196
5404
 
5197
5405
  class ZipReaderStream {
5198
5406
 
5199
5407
  constructor(options = {}) {
5200
- const { readable, writable } = new TransformStream();
5201
- const gen = new ZipReader(readable, options).getEntriesGenerator();
5408
+ let sourceController;
5409
+ const { readable, writable } = new TransformStream({
5410
+ start(controller) {
5411
+ sourceController = controller;
5412
+ }
5413
+ });
5414
+ const zipReader = new ZipReader(readable, options);
5415
+ const gen = zipReader.getEntriesGenerator();
5416
+ const pendingEntries = new Set();
5202
5417
  this.readable = new ReadableStream({
5203
5418
  async pull(controller) {
5204
5419
  const { done, value } = await gen.next();
5205
5420
  if (done)
5206
5421
  return controller.close();
5207
- const entryReadable = (function () {
5208
- const { readable, writable } = new TransformStream();
5209
- if (value.getData) {
5210
- getData();
5211
- return readable;
5212
- }
5213
-
5214
- async function getData() {
5215
- try {
5216
- await value.getData(writable);
5217
- } catch (error) {
5218
- try {
5219
- await writable.abort(error);
5220
- } catch {
5221
- // ignored
5222
- }
5223
- }
5224
- }
5225
- })();
5422
+ const entryStream = createEntryStream(value, pendingEntries);
5226
5423
  const chunk = {
5227
5424
  ...value,
5228
- readable: entryReadable
5425
+ readable: entryStream.readable
5229
5426
  };
5230
5427
  delete chunk.getData;
5428
+ Object.defineProperties(chunk, {
5429
+ localDirectory: {
5430
+ get: () => value.localDirectory,
5431
+ enumerable: true
5432
+ },
5433
+ warnings: {
5434
+ get: () => value.warnings,
5435
+ enumerable: true
5436
+ }
5437
+ });
5231
5438
  controller.enqueue(chunk);
5439
+ },
5440
+ async cancel(reason) {
5441
+ const entryStreams = Array.from(pendingEntries);
5442
+ pendingEntries.clear();
5443
+ sourceController.error(reason);
5444
+ await Promise.allSettled(entryStreams.map(entryStream => entryStream.cancel(reason)));
5445
+ await Promise.allSettled([gen.return(), zipReader.close()]);
5232
5446
  }
5233
5447
  });
5234
5448
  this.writable = writable;
5235
5449
  }
5236
5450
  }
5237
5451
 
5452
+ function createEntryStream(entry, pendingEntries) {
5453
+ const { readable, writable } = new TransformStream();
5454
+ let dataReader;
5455
+ const entryStream = {
5456
+ cancel: async reason => {
5457
+ pendingEntries.delete(entryStream);
5458
+ await (dataReader ? dataReader.cancel(reason) : readable.cancel(reason));
5459
+ }
5460
+ };
5461
+ entryStream.readable = new ReadableStream({
5462
+ async pull(controller) {
5463
+ if (!dataReader) {
5464
+ dataReader = readable.getReader();
5465
+ pendingEntries.add(entryStream);
5466
+ getData();
5467
+ }
5468
+ const { done, value } = await dataReader.read();
5469
+ if (done) {
5470
+ controller.close();
5471
+ } else {
5472
+ controller.enqueue(value);
5473
+ }
5474
+ },
5475
+ cancel: reason => entryStream.cancel(reason)
5476
+ }, { highWaterMark: 0 });
5477
+ return entryStream;
5478
+
5479
+ async function getData() {
5480
+ try {
5481
+ await entry.getData(writable, { preventClose: false });
5482
+ } catch (error) {
5483
+ try {
5484
+ await writable.abort(error);
5485
+ } catch {
5486
+ // ignored
5487
+ }
5488
+ } finally {
5489
+ pendingEntries.delete(entryStream);
5490
+ }
5491
+ }
5492
+ }
5493
+
5238
5494
  async function isZipFile(reader, options = {}) {
5239
5495
  reader = new GenericReader(reader);
5240
5496
  await initStream(reader);
@@ -5294,7 +5550,9 @@
5294
5550
  const dataView = getDataView(dataArray);
5295
5551
  let password = getOptionValue$1(zipEntry, options, OPTION_PASSWORD);
5296
5552
  let rawPassword = getOptionValue$1(zipEntry, options, OPTION_RAW_PASSWORD);
5297
- const passThrough = getOptionValue$1(zipEntry, options, OPTION_PASS_THROUGH);
5553
+ const passThrough = checkPassThroughOption(getOptionValue$1(zipEntry, options, OPTION_PASS_THROUGH));
5554
+ const passThroughCompression = Boolean(passThrough);
5555
+ const passThroughEncryption = passThrough === true;
5298
5556
  checkPasswordOption(password, rawPassword);
5299
5557
  password = password && password.length && password;
5300
5558
  rawPassword = rawPassword && rawPassword.length && rawPassword;
@@ -5315,7 +5573,9 @@
5315
5573
  const checkLocalDirectoryOption = getOptionValue$1(zipEntry, options, OPTION_CHECK_LOCAL_DIRECTORY);
5316
5574
  const entryStrictness = getStrictness(options, zipEntry.options);
5317
5575
  const checkLocalDirectory = getCheckLocalDirectory(checkLocalDirectoryOption, entryStrictness);
5318
- const checkLocalFilename = getCheckLocalFilename(checkLocalDirectoryOption, entryStrictness);
5576
+ const checkLocalFilenameOption = getOptionValue$1(zipEntry, options, OPTION_CHECK_LOCAL_FILENAME);
5577
+ const checkLocalFilename = getCheckLocalFilename(
5578
+ checkLocalFilenameOption === UNDEFINED_VALUE ? checkLocalDirectoryOption : checkLocalFilenameOption, entryStrictness);
5319
5579
  let rawLocalFilename = EMPTY_UINT8_ARRAY;
5320
5580
  if (checkLocalFilename && (filenameLength || extraFieldLength)) {
5321
5581
  const trailingDataArray = await readUint8Array(reader, localHeaderOffset + HEADER_SIZE, filenameLength + extraFieldLength);
@@ -5346,16 +5606,17 @@
5346
5606
  if (gid !== UNDEFINED_VALUE && fileEntry.gid === UNDEFINED_VALUE) {
5347
5607
  fileEntry.gid = gid;
5348
5608
  }
5349
- const encrypted = zipEntry.encrypted && localDirectory.encrypted && !passThrough;
5609
+ const checkPasswordOnly = getOptionValue$1(zipEntry, options, OPTION_CHECK_PASSWORD_ONLY);
5610
+ const encrypted = zipEntry.encrypted && localDirectory.encrypted && (!passThroughEncryption || checkPasswordOnly);
5350
5611
  const zipCrypto = encrypted && !extraFieldAES;
5351
- if (!passThrough) {
5612
+ if (!passThroughEncryption) {
5352
5613
  fileEntry.zipCrypto = zipCrypto;
5353
5614
  }
5354
5615
  if (encrypted && (localDirectory.rawBitFlag & BITFLAG_STRONG_ENCRYPTION) == BITFLAG_STRONG_ENCRYPTION) {
5355
5616
  throw new Error(ERR_UNSUPPORTED_ENCRYPTION);
5356
5617
  }
5357
- const registeredCodec = passThrough ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
5358
- if (compressionMethod != COMPRESSION_METHOD_STORE && compressionMethod != COMPRESSION_METHOD_DEFLATE && compressionMethod != COMPRESSION_METHOD_DEFLATE_64 && !registeredCodec && !passThrough) {
5618
+ const registeredCodec = passThroughCompression ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
5619
+ if (compressionMethod != COMPRESSION_METHOD_STORE && compressionMethod != COMPRESSION_METHOD_DEFLATE && compressionMethod != COMPRESSION_METHOD_DEFLATE_64 && !registeredCodec && !passThroughCompression) {
5359
5620
  throw new Error(ERR_UNSUPPORTED_COMPRESSION);
5360
5621
  }
5361
5622
  if (encrypted) {
@@ -5372,15 +5633,16 @@
5372
5633
  const readable = toCompatibleReadable(reader.createReadable({ offset: dataOffset, size }));
5373
5634
  const signal = checkSignalOption(getOptionValue$1(zipEntry, options, OPTION_SIGNAL));
5374
5635
  throwIfAborted(signal);
5375
- const checkPasswordOnly = getOptionValue$1(zipEntry, options, OPTION_CHECK_PASSWORD_ONLY);
5376
5636
  let checkOverlappingEntry = getOptionValue$1(zipEntry, options, OPTION_CHECK_OVERLAPPING_ENTRY);
5377
5637
  const checkOverlappingEntryOnly = getOptionValue$1(zipEntry, options, OPTION_CHECK_OVERLAPPING_ENTRY_ONLY);
5378
5638
  if (checkOverlappingEntryOnly) {
5379
5639
  checkOverlappingEntry = true;
5380
5640
  }
5381
5641
  const { onstart, onprogress, onend } = options;
5382
- const compressed = compressionMethod != COMPRESSION_METHOD_STORE && !passThrough;
5383
- const outputSize = passThrough ? compressedSize : uncompressedSize;
5642
+ const compressed = compressionMethod != COMPRESSION_METHOD_STORE && !passThroughCompression;
5643
+ const outputSize = passThroughCompression ?
5644
+ compressedSize - getEncryptionOverhead(encrypted, zipCrypto, extraFieldAES && extraFieldAES.strength) :
5645
+ uncompressedSize;
5384
5646
  const deflate64 = compressionMethod == COMPRESSION_METHOD_DEFLATE_64;
5385
5647
  let useCompressionStream = getOptionValue$1(zipEntry, options, OPTION_USE_COMPRESSION_STREAM);
5386
5648
  if (deflate64) {
@@ -5389,7 +5651,7 @@
5389
5651
  const checkCrc32Option = getOptionValue$1(zipEntry, options, OPTION_CHECK_CRC32);
5390
5652
  const checkCrc32 = (checkCrc32Option === UNDEFINED_VALUE ?
5391
5653
  getOptionValue$1(zipEntry, options, OPTION_CHECK_SIGNATURE) :
5392
- checkCrc32Option) && !passThrough &&
5654
+ checkCrc32Option) && !passThroughCompression &&
5393
5655
  (!encrypted || zipCrypto || (extraFieldAES && extraFieldAES.vendorVersion == VENDOR_VERSION_AE_1$1));
5394
5656
  const workerOptions = {
5395
5657
  options: {
@@ -5433,7 +5695,7 @@
5433
5695
  readRanges
5434
5696
  });
5435
5697
  }
5436
- let writable, abortError;
5698
+ let writable, abortError, aborted;
5437
5699
  try {
5438
5700
  if (!checkOverlappingEntryOnly) {
5439
5701
  if (checkPasswordOnly) {
@@ -5443,24 +5705,28 @@
5443
5705
  await initStream(writer, getDecodableOutputSize(outputSize, compressedSize, compressed));
5444
5706
  ({ writable } = writer);
5445
5707
  const { outputSize: writtenSize } = await runWorker({ readable, writable }, workerOptions);
5446
- writer.size += writtenSize;
5447
5708
  if (writtenSize != outputSize) {
5448
- throw new Error(ERR_INVALID_UNCOMPRESSED_SIZE);
5709
+ throw Object.assign(new Error(ERR_INVALID_UNCOMPRESSED_SIZE), { outputSize: writtenSize });
5449
5710
  }
5711
+ writer.size += writtenSize;
5450
5712
  }
5451
5713
  } catch (error) {
5452
- if (error.outputSize !== UNDEFINED_VALUE) {
5714
+ const { outputSize: failedOutputSize } = workerOptions;
5715
+ if (failedOutputSize !== UNDEFINED_VALUE) {
5716
+ writer.size += failedOutputSize;
5717
+ } else if (isErrorObject(error) && error.outputSize !== UNDEFINED_VALUE) {
5453
5718
  writer.size += error.outputSize;
5454
5719
  }
5455
- if (!checkPasswordOnly || error.message != ERR_ABORT_CHECK_PASSWORD) {
5720
+ if (!checkPasswordOnly || !isErrorObject(error) || error.message != ERR_ABORT_CHECK_PASSWORD) {
5456
5721
  abortError = error;
5722
+ aborted = true;
5457
5723
  throw error;
5458
5724
  }
5459
5725
  } finally {
5460
5726
  const preventClose = !ownsWritable(writer) && getOptionValue$1(zipEntry, options, OPTION_PREVENT_CLOSE);
5461
5727
  if (!preventClose && writable && !writable.locked) {
5462
5728
  const writableWriter = writable.getWriter();
5463
- if (abortError) {
5729
+ if (aborted) {
5464
5730
  try {
5465
5731
  await writableWriter.abort(abortError);
5466
5732
  } catch {
@@ -6112,7 +6378,7 @@
6112
6378
  if (checkLocalFilename && !maskedLocalDirectory &&
6113
6379
  (rawLocalFilename.length != rawFilename.length ||
6114
6380
  rawLocalFilename.some((byteValue, indexByte) => byteValue != rawFilename[indexByte]))) {
6115
- reportAmbiguity(reject, warnings, "mismatched local file header (filename)");
6381
+ reportAmbiguity(reject, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME);
6116
6382
  }
6117
6383
  if ((localDirectory.rawBitFlag & BITFLAG_AMBIGUITY_MASK) != (zipEntry.rawBitFlag & BITFLAG_AMBIGUITY_MASK)) {
6118
6384
  reportAmbiguity(reject, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG);
@@ -6137,16 +6403,6 @@
6137
6403
  }
6138
6404
  }
6139
6405
 
6140
- function addWarning(warnings, reason, filename) {
6141
- if (!warnings.some(warning => warning.reason == reason)) {
6142
- const warning = { reason };
6143
- if (filename !== UNDEFINED_VALUE) {
6144
- warning.filename = filename;
6145
- }
6146
- warnings.push(warning);
6147
- }
6148
- }
6149
-
6150
6406
  function throwAmbiguousArchive(reason) {
6151
6407
  const error = new Error(ERR_AMBIGUOUS_ARCHIVE);
6152
6408
  error.reason = reason;
@@ -6226,7 +6482,9 @@
6226
6482
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG: WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG,
6227
6483
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD: WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD,
6228
6484
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES: WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES,
6485
+ WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME: WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME,
6229
6486
  WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY: WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY,
6487
+ WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY: WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY,
6230
6488
  WARNING_PREPENDED_CENTRAL_DIRECTORY: WARNING_PREPENDED_CENTRAL_DIRECTORY,
6231
6489
  WARNING_PREPENDED_DATA: WARNING_PREPENDED_DATA,
6232
6490
  WARNING_TRAILING_CENTRAL_DIRECTORY_DATA: WARNING_TRAILING_CENTRAL_DIRECTORY_DATA,
@@ -6279,7 +6537,7 @@
6279
6537
  const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3";
6280
6538
  const ERR_UNSUPPORTED_ENCRYPTION_USDZ = "Encryption is not supported in USDZ files";
6281
6539
  const ERR_UNSUPPORTED_SPLIT_USDZ = "Split zip files are not supported in USDZ files";
6282
- const ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = "Encryption is not supported when the 'passThrough' option is set";
6540
+ const ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = "Encryption is not supported when the 'passThrough' option is set to true (use 'compressed' instead)";
6283
6541
  const ERR_INVALID_EXTRAFIELD = "Invalid extra field (must be a Map)";
6284
6542
  const ERR_INVALID_EXTRAFIELD_TYPE = "Invalid extra field type (must be integer 0..65535)";
6285
6543
  const ERR_INVALID_EXTRAFIELD_DATA_TYPE = "Invalid extra field data (must be a Uint8Array)";
@@ -6291,6 +6549,7 @@
6291
6549
  const ERR_UNSUPPORTED_FORMAT = "Zip64 is not supported (set the 'zip64' option to 'true')";
6292
6550
  const ERR_UNDEFINED_UNCOMPRESSED_SIZE = "Undefined uncompressed size";
6293
6551
  const ERR_UNDEFINED_COMPRESSION_METHOD = "Undefined compression method";
6552
+ const ERR_UNDEFINED_CRC32 = "Undefined CRC32";
6294
6553
  const ERR_UNDETERMINED_SIZE = "Undetermined size";
6295
6554
  const ERR_UNDEFINED_READER = "Undefined reader";
6296
6555
  const ERR_INVALID_READER = "Invalid reader (must be a Reader instance, a ReadableStream instance, or an object with a 'readable' property)";
@@ -6304,14 +6563,21 @@
6304
6563
  const ERR_INVALID_MSDOS_DATA = "Invalid msdosAttributes (must be an object with boolean flags)";
6305
6564
  const ERR_INVALID_LEVEL = "Invalid level (must be integer 0..9)";
6306
6565
  const ERR_INVALID_SIGNATURE_DATA = "Signature data exceeds 64KB";
6566
+ const ERR_INVALID_ENTRY = "Invalid entry option (must be an entry returned by ZipReader#getEntries())";
6567
+ const ERR_ZIP_CRYPTO_LAST_MOD_DATE = "The last modification date of an entry encrypted with ZipCrypto cannot be changed when passThrough is set";
6568
+ const WARNING_COMPRESSION_UNAVAILABLE = "compression unavailable";
6569
+ const WARNING_CLAMPED_LAST_MODIFICATION_DATE = "clamped last modification date";
6307
6570
 
6308
6571
  const EXTRAFIELD_DATA_AES = new Uint8Array([0x07, 0x00, 0x02, 0x00, 0x41, 0x45, 0x03, 0x00, 0x00]);
6309
6572
  const EXTRAFIELD_OFFSET_AES_VENDOR_VERSION = 4;
6310
6573
  const EXTRAFIELD_OFFSET_AES_COMPRESSION_METHOD = 9;
6311
6574
  const EXTRAFIELD_USDZ_MAX_LENGTH = 67;
6575
+ const MIN_PRINTABLE_ASCII_CHARACTER_CODE = 0x20;
6576
+ const MAX_PRINTABLE_ASCII_CHARACTER_CODE = 0x7e;
6312
6577
  const VENDOR_VERSION_AE_1 = 1;
6313
- const INFOZIP_EXTRA_FIELD_TYPE$1 = "infozip";
6578
+ const INFOZIP_EXTRA_FIELD_TYPE = "infozip";
6314
6579
  const UNIX_EXTRA_FIELD_TYPE = "unix";
6580
+ const LEVEL_BY_BITFLAG_LEVEL = [8, 9, 5, 3];
6315
6581
  const MAX_LEVEL = 9;
6316
6582
 
6317
6583
  let workers = 0;
@@ -6338,9 +6604,11 @@
6338
6604
  initialOffset: options[OPTION_OFFSET] === UNDEFINED_VALUE ? 0 : options[OPTION_OFFSET] - (writer.size || writer.writable.size || 0),
6339
6605
  pendingAddFileCalls: new Set(),
6340
6606
  pendingErrors: [],
6607
+ warnings: [],
6341
6608
  bufferedWrites: 0,
6342
6609
  directWrites: 0,
6343
- lastFileEntry: UNDEFINED_VALUE
6610
+ lastFileEntry: UNDEFINED_VALUE,
6611
+ archiveClosed: false
6344
6612
  });
6345
6613
  }
6346
6614
 
@@ -6505,6 +6773,9 @@
6505
6773
  const zipWriter = this;
6506
6774
  const { pendingAddFileCalls, writer } = this;
6507
6775
  const { writable } = writer;
6776
+ if (zipWriter.archiveClosed) {
6777
+ return getWriterData(writer);
6778
+ }
6508
6779
  if (!(comment instanceof Uint8Array)) {
6509
6780
  throw new Error(ERR_INVALID_COMMENT_TYPE);
6510
6781
  }
@@ -6515,7 +6786,7 @@
6515
6786
  await Promise.allSettled(Array.from(pendingAddFileCalls));
6516
6787
  }
6517
6788
  await Promise.allSettled(zipWriter.pendingErrors.map(watcher => watcher.recorded));
6518
- const unobservedWatchers = zipWriter.pendingErrors.filter(watcher => watcher.error && !watcher.observed);
6789
+ const unobservedWatchers = zipWriter.pendingErrors.filter(watcher => watcher.failed && !watcher.observed);
6519
6790
  if (unobservedWatchers.length) {
6520
6791
  const unobservedErrors = unobservedWatchers.map(watcher => watcher.error);
6521
6792
  unobservedWatchers.forEach(watcher => watcher.observed = true);
@@ -6528,11 +6799,16 @@
6528
6799
  throw error;
6529
6800
  }
6530
6801
  await closeFile(zipWriter, comment, options);
6802
+ zipWriter.archiveClosed = true;
6531
6803
  const preventClose = !ownsWritable(writer) && getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
6532
6804
  if (!preventClose) {
6533
6805
  await writable.getWriter().close();
6534
6806
  }
6535
- return writer.getData ? writer.getData() : writable;
6807
+ return getWriterData(writer);
6808
+ }
6809
+
6810
+ [SYMBOL_ASYNC_DISPOSE]() {
6811
+ return this.close();
6536
6812
  }
6537
6813
  }
6538
6814
 
@@ -6611,11 +6887,16 @@
6611
6887
  }
6612
6888
  }
6613
6889
 
6890
+ function getWriterData(writer) {
6891
+ return writer.getData ? writer.getData() : writer.writable;
6892
+ }
6893
+
6614
6894
  function watchPromiseError(zipWriter, promise) {
6615
6895
  const watchedPromise = new WatchedPromise((resolve, reject) => Promise.prototype.then.call(promise, resolve, reject));
6616
6896
  const watcher = {};
6617
6897
  watchedPromise.watcher = watcher;
6618
- watcher.recorded = Promise.prototype.then.call(watchedPromise, UNDEFINED_VALUE, error => watcher.error = error);
6898
+ watcher.recorded = Promise.prototype.then.call(watchedPromise, UNDEFINED_VALUE,
6899
+ error => Object.assign(watcher, { failed: true, error }));
6619
6900
  zipWriter.pendingErrors.push(watcher);
6620
6901
  return watchedPromise;
6621
6902
  }
@@ -6629,6 +6910,14 @@
6629
6910
 
6630
6911
  async function addFileEntry(zipWriter, name, reader, options) {
6631
6912
  options = Object.assign({}, options);
6913
+ const entry = options[OPTION_ENTRY];
6914
+ if (entry !== UNDEFINED_VALUE) {
6915
+ const { entryOptions, passThroughOptions } = getSourceEntryOptions(entry,
6916
+ checkPassThroughOption(getOptionValue(zipWriter, options, OPTION_PASS_THROUGH)),
6917
+ getOptionValue(zipWriter, options, PROPERTY_NAME_LAST_MODIFICATION_DATE));
6918
+ delete options[OPTION_ENTRY];
6919
+ options = Object.assign(entryOptions, passThroughOptions, options);
6920
+ }
6632
6921
  if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
6633
6922
  name += DIRECTORY_SIGNATURE;
6634
6923
  }
@@ -6693,21 +6982,33 @@
6693
6982
  try {
6694
6983
  const { resolvedOptions } = metadataInfo;
6695
6984
  if (resolvedOptions.level != 0 && resolvedOptions.compressionMethod === UNDEFINED_VALUE &&
6696
- !resolvedOptions.passThrough && !(await supportsDeflate(getConfiguration()))) {
6985
+ !resolvedOptions.passThroughCompression && !(await supportsDeflate(getConfiguration()))) {
6697
6986
  resolvedOptions.level = 0;
6987
+ addWarning(zipWriter.warnings, WARNING_COMPRESSION_UNAVAILABLE, name);
6698
6988
  }
6699
6989
  const sizesInfo = await resolveSizes(zipWriter, reader, metadataInfo, options);
6700
6990
  ({ reader } = sizesInfo);
6701
6991
  const diskOffset = getDiskOffset(zipWriter.writer);
6702
6992
  const diskNumber = getDiskNumber(zipWriter.writer);
6993
+ let crc32 = options.crc32 === UNDEFINED_VALUE ? options[PROPERTY_NAME_SIGNATURE] : options.crc32;
6994
+ const storesAE2 = sizesInfo.resolvedOptions.encrypted && !resolvedOptions.zipCrypto;
6995
+ if (resolvedOptions.passThroughCompression && !resolvedOptions.passThroughEncryption && storesAE2) {
6996
+ crc32 = UNDEFINED_VALUE;
6997
+ }
6998
+ if (resolvedOptions.passThroughCompression && reader && !storesAE2 && crc32 === UNDEFINED_VALUE) {
6999
+ throw new Error(ERR_UNDEFINED_CRC32);
7000
+ }
6703
7001
  options = Object.assign({}, options, attributesInfo.resolvedOptions, metadataInfo.resolvedOptions, sizesInfo.resolvedOptions, {
6704
7002
  signature: options[PROPERTY_NAME_SIGNATURE],
6705
- crc32: options.crc32 === UNDEFINED_VALUE ? options[PROPERTY_NAME_SIGNATURE] : options.crc32,
7003
+ crc32,
6706
7004
  offset: zipWriter.offset - diskOffset,
6707
7005
  diskNumberStart: diskNumber,
6708
7006
  [OPTION_USDZ]: zipWriter.options[OPTION_USDZ]
6709
7007
  });
6710
7008
  const headerInfo = getHeaderInfo(options);
7009
+ if (headerInfo.lastModDateClamped) {
7010
+ addWarning(zipWriter.warnings, WARNING_CLAMPED_LAST_MODIFICATION_DATE, name);
7011
+ }
6711
7012
  const dataDescriptorInfo = getDataDescriptorInfo(options);
6712
7013
  const metadataSize = getLength(headerInfo.localHeaderArray, dataDescriptorInfo.dataDescriptorArray);
6713
7014
  fileEntry = await getFileEntry(zipWriter, name, reader, {
@@ -6734,6 +7035,95 @@
6734
7035
  return new Entry(fileEntry);
6735
7036
  }
6736
7037
 
7038
+ function getSourceEntryOptions(entry, passThrough, lastModDateOverride) {
7039
+ if (entry === null || typeof entry != OBJECT_TYPE || Array.isArray(entry)) {
7040
+ throw new Error(ERR_INVALID_ENTRY);
7041
+ }
7042
+ const {
7043
+ externalFileAttributes,
7044
+ versionMadeBy,
7045
+ comment,
7046
+ lastModDate,
7047
+ rawLastModDate,
7048
+ creationDate,
7049
+ lastAccessDate,
7050
+ uncompressedSize,
7051
+ encrypted,
7052
+ zipCrypto,
7053
+ crc32,
7054
+ compressionMethod,
7055
+ extraFieldAES,
7056
+ extraFieldUnix,
7057
+ internalFileAttributes,
7058
+ extraField,
7059
+ bitFlag,
7060
+ directory,
7061
+ uid,
7062
+ gid
7063
+ } = entry;
7064
+ const entryOptions = {
7065
+ externalFileAttributes,
7066
+ versionMadeBy,
7067
+ comment,
7068
+ lastModDate,
7069
+ creationDate,
7070
+ lastAccessDate,
7071
+ internalFileAttributes,
7072
+ directory
7073
+ };
7074
+ if (bitFlag && bitFlag.languageEncodingFlag) {
7075
+ entryOptions[OPTION_USE_UNICODE_FILE_NAMES] = true;
7076
+ }
7077
+ const userExtraField = getUserExtraField(extraField);
7078
+ if (userExtraField) {
7079
+ entryOptions[PROPERTY_NAME_EXTRA_FIELD] = userExtraField;
7080
+ }
7081
+ if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
7082
+ Object.assign(entryOptions, {
7083
+ uid,
7084
+ gid,
7085
+ unixExtraFieldType: extraFieldUnix ? UNIX_EXTRA_FIELD_TYPE : INFOZIP_EXTRA_FIELD_TYPE
7086
+ });
7087
+ }
7088
+ const passThroughOptions = {};
7089
+ if (passThrough && !directory) {
7090
+ Object.assign(passThroughOptions, {
7091
+ uncompressedSize,
7092
+ crc32,
7093
+ compressionMethod
7094
+ });
7095
+ if (passThrough !== PASS_THROUGH_COMPRESSED) {
7096
+ Object.assign(passThroughOptions, {
7097
+ encrypted,
7098
+ zipCrypto,
7099
+ encryptionStrength: extraFieldAES ? extraFieldAES.strength : UNDEFINED_VALUE
7100
+ });
7101
+ }
7102
+ if (bitFlag) {
7103
+ passThroughOptions.dataDescriptor = bitFlag.dataDescriptor;
7104
+ passThroughOptions[OPTION_LEVEL] = LEVEL_BY_BITFLAG_LEVEL[bitFlag.level];
7105
+ }
7106
+ if (lastModDateOverride === UNDEFINED_VALUE) {
7107
+ passThroughOptions.rawLastModDate = rawLastModDate;
7108
+ } else if (passThrough !== PASS_THROUGH_COMPRESSED && zipCrypto && (!bitFlag || bitFlag.dataDescriptor) &&
7109
+ lastModDateOverride instanceof Date &&
7110
+ getDosTimeHighByte(lastModDateOverride) != ((rawLastModDate >>> 8) & MAX_8_BITS)) {
7111
+ throw new Error(ERR_ZIP_CRYPTO_LAST_MOD_DATE);
7112
+ }
7113
+ }
7114
+ return { entryOptions, passThroughOptions };
7115
+ }
7116
+
7117
+ function getDosTimeHighByte(lastModDate) {
7118
+ let dosLastModDate = new Date(Math.ceil(Math.floor(lastModDate.getTime() / 1000) / 2) * 2000);
7119
+ if (dosLastModDate < MIN_DATE) {
7120
+ dosLastModDate = MIN_DATE;
7121
+ } else if (dosLastModDate > MAX_DATE) {
7122
+ dosLastModDate = MAX_DATE;
7123
+ }
7124
+ return ((dosLastModDate.getHours() << 3) | (dosLastModDate.getMinutes() >> 3)) & MAX_8_BITS;
7125
+ }
7126
+
6737
7127
  function resolveAttributes(zipWriter, name, options) {
6738
7128
  let msDosCompatible = getOptionValue(zipWriter, options, PROPERTY_NAME_MS_DOS_COMPATIBLE);
6739
7129
  let versionMadeBy = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION_MADE_BY, msDosCompatible ? VERSION_MADE_BY_MSDOS : VERSION_MADE_BY_UNIX);
@@ -6748,7 +7138,7 @@
6748
7138
  checkIntegerOption(uid, MAX_32_BITS, ERR_INVALID_UID);
6749
7139
  checkIntegerOption(gid, MAX_32_BITS, ERR_INVALID_GID);
6750
7140
  checkIntegerOption(unixMode, MAX_16_BITS, ERR_INVALID_UNIX_MODE);
6751
- if (unixExtraFieldType !== UNDEFINED_VALUE && unixExtraFieldType !== INFOZIP_EXTRA_FIELD_TYPE$1 && unixExtraFieldType !== UNIX_EXTRA_FIELD_TYPE) {
7141
+ if (unixExtraFieldType !== UNDEFINED_VALUE && unixExtraFieldType !== INFOZIP_EXTRA_FIELD_TYPE && unixExtraFieldType !== UNIX_EXTRA_FIELD_TYPE) {
6752
7142
  throw new Error(ERR_INVALID_UNIX_EXTRA_FIELD_TYPE);
6753
7143
  }
6754
7144
  if (unixExtraFieldType === UNIX_EXTRA_FIELD_TYPE &&
@@ -6756,7 +7146,7 @@
6756
7146
  throw new Error(ERR_INVALID_UNIX_ID_SIZE);
6757
7147
  }
6758
7148
  if (unixExtraFieldType === UNDEFINED_VALUE && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE)) {
6759
- unixExtraFieldType = INFOZIP_EXTRA_FIELD_TYPE$1;
7149
+ unixExtraFieldType = INFOZIP_EXTRA_FIELD_TYPE;
6760
7150
  }
6761
7151
  let msdosAttributesRaw = getNumberOptionValue(zipWriter, options, PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW);
6762
7152
  let msdosAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_MSDOS_ATTRIBUTES);
@@ -6887,7 +7277,9 @@
6887
7277
  const lastAccessDate = getDateOptionValue(zipWriter, options, PROPERTY_NAME_LAST_ACCESS_DATE);
6888
7278
  const creationDate = getDateOptionValue(zipWriter, options, PROPERTY_NAME_CREATION_DATE);
6889
7279
  const internalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, 0);
6890
- const passThrough = getOptionValue(zipWriter, options, OPTION_PASS_THROUGH);
7280
+ const passThrough = checkPassThroughOption(getOptionValue(zipWriter, options, OPTION_PASS_THROUGH));
7281
+ const passThroughCompression = Boolean(passThrough);
7282
+ const passThroughEncryption = passThrough === true;
6891
7283
  const password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
6892
7284
  const rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
6893
7285
  checkPasswordOption(password, rawPassword);
@@ -6903,10 +7295,11 @@
6903
7295
  const dataDescriptorSignature = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR_SIGNATURE, true);
6904
7296
  const signal = checkSignalOption(getOptionValue(zipWriter, options, OPTION_SIGNAL));
6905
7297
  throwIfAborted(signal);
6906
- const useUnicodeFileNames = getOptionValue(zipWriter, options, OPTION_USE_UNICODE_FILE_NAMES, true);
7298
+ const useUnicodeFileNames = getOptionValue(zipWriter, options, OPTION_USE_UNICODE_FILE_NAMES,
7299
+ !isPrintableASCIIText(rawFilename) || !isPrintableASCIIText(rawComment));
6907
7300
  const compressionMethod = getOptionValue(zipWriter, options, PROPERTY_NAME_COMPRESSION_METHOD);
6908
- const registeredCodec = passThrough || compressionMethod === UNDEFINED_VALUE ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
6909
- if (!passThrough && compressionMethod !== UNDEFINED_VALUE &&
7301
+ const registeredCodec = passThroughCompression || compressionMethod === UNDEFINED_VALUE ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
7302
+ if (!passThroughCompression && compressionMethod !== UNDEFINED_VALUE &&
6910
7303
  compressionMethod !== COMPRESSION_METHOD_STORE && compressionMethod !== COMPRESSION_METHOD_DEFLATE && !registeredCodec) {
6911
7304
  throw new Error(ERR_UNSUPPORTED_COMPRESSION);
6912
7305
  }
@@ -6920,15 +7313,15 @@
6920
7313
  level = 0;
6921
7314
  }
6922
7315
  }
6923
- if (passThrough) {
6924
- level = UNDEFINED_VALUE;
7316
+ if (passThroughCompression) {
7317
+ level = toNumber(options[OPTION_LEVEL]);
6925
7318
  }
6926
7319
  let useCompressionStream = getOptionValue(zipWriter, options, OPTION_USE_COMPRESSION_STREAM);
6927
7320
  let dataDescriptor = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR);
6928
7321
  if (bufferedWrite && dataDescriptor === UNDEFINED_VALUE) {
6929
7322
  dataDescriptor = false;
6930
7323
  }
6931
- if (dataDescriptor === UNDEFINED_VALUE || (zipCrypto && !passThrough)) {
7324
+ if (dataDescriptor === UNDEFINED_VALUE || (zipCrypto && !passThroughEncryption)) {
6932
7325
  dataDescriptor = true;
6933
7326
  }
6934
7327
  if (level !== UNDEFINED_VALUE && level != 6) {
@@ -6952,7 +7345,8 @@
6952
7345
  lastAccessDate,
6953
7346
  creationDate,
6954
7347
  internalFileAttributes,
6955
- passThrough,
7348
+ passThroughCompression,
7349
+ passThroughEncryption,
6956
7350
  password,
6957
7351
  rawPassword,
6958
7352
  encryptionStrength,
@@ -7013,7 +7407,7 @@
7013
7407
  }
7014
7408
 
7015
7409
  async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, options) {
7016
- if (metadata.passThrough && !reader && !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY)) {
7410
+ if (metadata.passThroughCompression && !reader && !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY)) {
7017
7411
  throw new Error(ERR_UNDEFINED_READER);
7018
7412
  }
7019
7413
  let contentSize;
@@ -7029,12 +7423,12 @@
7029
7423
  }
7030
7424
 
7031
7425
  function resolveEntrySizes(zipWriter, hasContent, contentSize, metadata, options) {
7032
- const { passThrough, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
7426
+ const { passThroughCompression, passThroughEncryption, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
7033
7427
  let { dataDescriptor, zip64, level, compressionMethod } = metadata;
7034
7428
  let maximumCompressedSize = 0;
7035
7429
  let uncompressedSize = 0;
7036
7430
  let unknownSize = false;
7037
- if (passThrough && hasContent) {
7431
+ if (passThroughCompression && hasContent) {
7038
7432
  uncompressedSize = options[PROPERTY_NAME_UNCOMPRESSED_SIZE];
7039
7433
  if (uncompressedSize === UNDEFINED_VALUE) {
7040
7434
  throw new Error(ERR_UNDEFINED_UNCOMPRESSED_SIZE);
@@ -7045,17 +7439,17 @@
7045
7439
  }
7046
7440
  const zip64Enabled = zip64 === true;
7047
7441
  const encrypted = getOptionValue(zipWriter, options, PROPERTY_NAME_ENCRYPTED);
7048
- if (hasContent && passThrough && !encrypted && getLength(password, rawPassword)) {
7442
+ if (hasContent && passThroughEncryption && !encrypted && getLength(password, rawPassword)) {
7049
7443
  throw new Error(ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH);
7050
7444
  }
7051
- const encryptedEntry = hasContent && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
7445
+ const encryptedEntry = hasContent && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThroughEncryption && encrypted));
7052
7446
  if (!hasContent) {
7053
7447
  level = 0;
7054
7448
  compressionMethod = COMPRESSION_METHOD_STORE;
7055
7449
  }
7056
- const encryptionOverhead = encryptedEntry ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
7450
+ const encryptionOverhead = getEncryptionOverhead(encryptedEntry, zipCrypto, encryptionStrength);
7057
7451
  if (hasContent) {
7058
- if (!passThrough) {
7452
+ if (!passThroughCompression) {
7059
7453
  if (contentSize === UNDEFINED_VALUE) {
7060
7454
  dataDescriptor = true;
7061
7455
  if (zip64 || zip64 === UNDEFINED_VALUE) {
@@ -7068,10 +7462,12 @@
7068
7462
  }
7069
7463
  } else {
7070
7464
  options.uncompressedSize = uncompressedSize;
7071
- maximumCompressedSize = contentSize === UNDEFINED_VALUE ? getMaximumCompressedSize(uncompressedSize) + encryptionOverhead : contentSize;
7465
+ maximumCompressedSize = contentSize === UNDEFINED_VALUE ?
7466
+ getMaximumCompressedSize(uncompressedSize) + encryptionOverhead :
7467
+ contentSize + (passThroughEncryption ? 0 : encryptionOverhead);
7072
7468
  }
7073
7469
  }
7074
- const emptyEntry = !encryptedEntry && (!hasContent || (contentSize === 0 && !passThrough)) && !isCompressed(compressionMethod, level);
7470
+ const emptyEntry = !encryptedEntry && (!hasContent || (contentSize === 0 && !passThroughCompression)) && !isCompressed(compressionMethod, level);
7075
7471
  if (emptyEntry && !zipCrypto && getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR) === UNDEFINED_VALUE) {
7076
7472
  dataDescriptor = false;
7077
7473
  }
@@ -7120,6 +7516,8 @@
7120
7516
  const initialOffset = writerOptions[OPTION_OFFSET] === UNDEFINED_VALUE ? 0 : writerOptions[OPTION_OFFSET];
7121
7517
  let offset = initialOffset;
7122
7518
  let minimumEntrySize = INFINITY_VALUE;
7519
+ const entrySizes = [];
7520
+ const entriesAlreadyZip64 = new Set();
7123
7521
  for (const entry of entries) {
7124
7522
  let { name } = entry;
7125
7523
  const { size } = entry;
@@ -7131,7 +7529,7 @@
7131
7529
  ({ name } = attributesInfo);
7132
7530
  const { resolvedOptions: metadata } = resolveMetadata(zipWriter, name, options);
7133
7531
  if (metadata.level != 0 && metadata.compressionMethod === UNDEFINED_VALUE &&
7134
- !metadata.passThrough && !(await supportsDeflate(getConfiguration()))) {
7532
+ !metadata.passThroughCompression && !(await supportsDeflate(getConfiguration()))) {
7135
7533
  metadata.level = 0;
7136
7534
  }
7137
7535
  const hasContent = !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY);
@@ -7139,7 +7537,7 @@
7139
7537
  throw new Error(ERR_UNDETERMINED_SIZE);
7140
7538
  }
7141
7539
  const { maximumCompressedSize, resolvedOptions: sizes } = resolveEntrySizes(zipWriter, hasContent, size, metadata, options);
7142
- if (hasContent && !metadata.passThrough && isCompressed(sizes.compressionMethod, sizes.level)) {
7540
+ if (hasContent && !metadata.passThroughCompression && isCompressed(sizes.compressionMethod, sizes.level)) {
7143
7541
  throw new Error(ERR_UNDETERMINED_SIZE);
7144
7542
  }
7145
7543
  const entryOptions = Object.assign({}, options, attributesInfo.resolvedOptions, metadata, sizes, { [OPTION_USDZ]: usdz });
@@ -7159,10 +7557,15 @@
7159
7557
  compressedSize
7160
7558
  }));
7161
7559
  const entrySize = entryInfo.metadataSize + compressedSize;
7560
+ entrySizes.push(entrySize);
7561
+ entriesAlreadyZip64.add(Boolean(entryOptions.zip64Enabled ||
7562
+ entryOptions.uncompressedSize >= MAX_32_BITS || compressedSize >= MAX_32_BITS));
7162
7563
  minimumEntrySize = Math.min(minimumEntrySize, entrySize);
7163
7564
  offset += entrySize;
7164
7565
  }
7165
- const layoutDependsOnWriteOrder = files.size > 1 && (usdz || offset - minimumEntrySize >= MAX_32_BITS);
7566
+ const layoutDependsOnWriteOrder = files.size > 1 && (usdz ||
7567
+ (offset - minimumEntrySize >= MAX_32_BITS &&
7568
+ (entriesAlreadyZip64.size > 1 || countEntriesBefore4GB(entrySizes, initialOffset, true) != countEntriesBefore4GB(entrySizes, initialOffset, false))));
7166
7569
  if (layoutDependsOnWriteOrder && !writeOrderGuaranteed) {
7167
7570
  throw new Error(ERR_UNDETERMINED_SIZE);
7168
7571
  }
@@ -7180,6 +7583,20 @@
7180
7583
  return offset - initialOffset + directoryDataLength + commentLength + (zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
7181
7584
  }
7182
7585
 
7586
+ function countEntriesBefore4GB(entrySizes, initialOffset, largestFirst) {
7587
+ const ordered = entrySizes.slice().sort((first, second) => largestFirst ? second - first : first - second);
7588
+ let position = initialOffset;
7589
+ let count = 0;
7590
+ for (const entrySize of ordered) {
7591
+ if (position >= MAX_32_BITS) {
7592
+ break;
7593
+ }
7594
+ position += entrySize;
7595
+ count++;
7596
+ }
7597
+ return count;
7598
+ }
7599
+
7183
7600
  async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
7184
7601
  const {
7185
7602
  fileEntries,
@@ -7355,6 +7772,7 @@
7355
7772
  localExtraFieldZip64Length,
7356
7773
  rawExtraFieldExtendedTimestamp,
7357
7774
  extraFieldExtendedTimestampFlag,
7775
+ extraFieldExtendedTimestampTime,
7358
7776
  rawExtraFieldNTFS,
7359
7777
  rawExtraFieldUnix,
7360
7778
  rawExtraFieldAES,
@@ -7367,6 +7785,7 @@
7367
7785
  password,
7368
7786
  rawPassword,
7369
7787
  level,
7788
+ useUnicodeFileNames,
7370
7789
  zip64,
7371
7790
  zip64Enabled,
7372
7791
  zip64UncompressedSize,
@@ -7401,7 +7820,8 @@
7401
7820
  msdosAttributesRaw,
7402
7821
  msdosAttributes,
7403
7822
  useCompressionStream,
7404
- passThrough,
7823
+ passThroughCompression,
7824
+ passThroughEncryption,
7405
7825
  format,
7406
7826
  codecURI
7407
7827
  } = options;
@@ -7412,9 +7832,9 @@
7412
7832
  zip64Enabled,
7413
7833
  directory: Boolean(directory),
7414
7834
  executable: Boolean(executable),
7415
- filenameUTF8: true,
7835
+ filenameUTF8: Boolean(useUnicodeFileNames),
7416
7836
  rawFilename,
7417
- commentUTF8: true,
7837
+ commentUTF8: Boolean(useUnicodeFileNames),
7418
7838
  rawComment,
7419
7839
  rawExtraFieldZip64,
7420
7840
  localExtraFieldZip64Length,
@@ -7445,7 +7865,7 @@
7445
7865
  uncompressedSize
7446
7866
  } = options;
7447
7867
  let compressedSize = 0;
7448
- if (!passThrough) {
7868
+ if (!passThroughCompression) {
7449
7869
  uncompressedSize = 0;
7450
7870
  }
7451
7871
  const { writable } = writer;
@@ -7462,9 +7882,9 @@
7462
7882
  encryptionStrength,
7463
7883
  zipCrypto: encrypted && zipCrypto,
7464
7884
  passwordVerification: encrypted && zipCrypto && (rawLastModDate >> 8) & MAX_8_BITS,
7465
- computeCrc32: !passThrough,
7466
- compressed: compressed && !passThrough,
7467
- encrypted: encrypted && !passThrough,
7885
+ computeCrc32: !passThroughCompression,
7886
+ compressed: compressed && !passThroughCompression,
7887
+ encrypted: encrypted && !passThroughEncryption,
7468
7888
  useWebWorkers,
7469
7889
  useCompressionStream,
7470
7890
  transferStreams,
@@ -7479,7 +7899,7 @@
7479
7899
  const result = await runWorker({ readable, writable }, workerOptions);
7480
7900
  compressedSize = result.outputSize;
7481
7901
  writer.size += compressedSize;
7482
- if (!passThrough) {
7902
+ if (!passThroughCompression) {
7483
7903
  uncompressedSize = result.inputSize;
7484
7904
  if (!encrypted || zipCrypto) {
7485
7905
  crc32 = result.crc32;
@@ -7490,7 +7910,10 @@
7490
7910
  throw new Error(ERR_UNSUPPORTED_FORMAT);
7491
7911
  }
7492
7912
  } catch (error) {
7493
- if (error.outputSize !== UNDEFINED_VALUE) {
7913
+ const { outputSize: failedOutputSize } = workerOptions;
7914
+ if (failedOutputSize !== UNDEFINED_VALUE) {
7915
+ writer.size += failedOutputSize;
7916
+ } else if (isErrorObject(error) && error.outputSize !== UNDEFINED_VALUE) {
7494
7917
  writer.size += error.outputSize;
7495
7918
  }
7496
7919
  throw error;
@@ -7522,8 +7945,9 @@
7522
7945
  headerArray,
7523
7946
  headerView,
7524
7947
  signature: crc32,
7525
- crc32: encrypted && !zipCrypto && !passThrough ? UNDEFINED_VALUE : crc32,
7948
+ crc32: encrypted && !zipCrypto && !passThroughCompression ? UNDEFINED_VALUE : crc32,
7526
7949
  extraFieldExtendedTimestampFlag,
7950
+ extraFieldExtendedTimestampTime,
7527
7951
  zip64UncompressedSize,
7528
7952
  zip64CompressedSize
7529
7953
  });
@@ -7548,7 +7972,7 @@
7548
7972
  encryptionStrength,
7549
7973
  extendedTimestamp,
7550
7974
  ntfsTimestamp,
7551
- passThrough,
7975
+ passThroughCompression,
7552
7976
  encrypted,
7553
7977
  zip64UncompressedSize,
7554
7978
  zip64CompressedSize,
@@ -7559,7 +7983,7 @@
7559
7983
  let { version, compressionMethod } = options;
7560
7984
  const compressed = !directory && isCompressed(compressionMethod, level);
7561
7985
  let rawLocalExtraFieldZip64;
7562
- const uncompressedFile = passThrough || !compressed;
7986
+ const uncompressedFile = passThroughCompression || !compressed;
7563
7987
  const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || !dataDescriptor || ((!zip64UncompressedSize && !zip64CompressedSize) || (uncompressedFile && !unknownSize)));
7564
7988
  const writeLocalExtraFieldZip64 = zip64ExtraFieldComplete || (zip64 && dataDescriptor && (zip64UncompressedSize || zip64CompressedSize));
7565
7989
  if (zip64 && (zip64UncompressedSize || zip64CompressedSize)) {
@@ -7571,8 +7995,8 @@
7571
7995
  if (zip64ExtraFieldComplete) {
7572
7996
  extraFieldZip64.writeUint64(uncompressedSize);
7573
7997
  if (uncompressedFile) {
7574
- const encryptionOverhead = encrypted ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
7575
- extraFieldZip64.writeUint64(passThrough ? 0 : uncompressedSize + encryptionOverhead);
7998
+ const encryptionOverhead = getEncryptionOverhead(encrypted, zipCrypto, encryptionStrength);
7999
+ extraFieldZip64.writeUint64(passThroughCompression ? 0 : uncompressedSize + encryptionOverhead);
7576
8000
  }
7577
8001
  }
7578
8002
  } else {
@@ -7591,6 +8015,7 @@
7591
8015
  let rawExtraFieldNTFS;
7592
8016
  let rawExtraFieldExtendedTimestamp;
7593
8017
  let extraFieldExtendedTimestampFlag;
8018
+ let extraFieldExtendedTimestampTime;
7594
8019
  if (extendedTimestamp) {
7595
8020
  const lastModTimeUnix = getTimeUnix(lastModDate);
7596
8021
  const lastModTimeUnixInRange = inUnixTimeRange(lastModTimeUnix);
@@ -7598,6 +8023,7 @@
7598
8023
  const extraFieldTimestampLength = 9 + (lastAccessDate ? 4 : 0) + (creationDate ? 4 : 0);
7599
8024
  const extraFieldTimestamp = createRecordWriter(extraFieldTimestampLength);
7600
8025
  extraFieldExtendedTimestampFlag = 0x1 + (lastAccessDate ? 0x2 : 0) + (creationDate ? 0x4 : 0);
8026
+ extraFieldExtendedTimestampTime = lastModTimeUnix;
7601
8027
  extraFieldTimestamp.writeUint16(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
7602
8028
  extraFieldTimestamp.writeUint16(extraFieldTimestampLength - 4);
7603
8029
  extraFieldTimestamp.writeUint8(extraFieldExtendedTimestampFlag);
@@ -7640,7 +8066,7 @@
7640
8066
  let rawExtraFieldUnix;
7641
8067
  try {
7642
8068
  const { uid, gid, unixExtraFieldType } = options;
7643
- if (unixExtraFieldType == INFOZIP_EXTRA_FIELD_TYPE$1 && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE)) {
8069
+ if (unixExtraFieldType == INFOZIP_EXTRA_FIELD_TYPE && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE)) {
7644
8070
  const uidBytes = packUnixId(uid === UNDEFINED_VALUE ? 0 : uid);
7645
8071
  const gidBytes = packUnixId(gid === UNDEFINED_VALUE ? 0 : gid);
7646
8072
  const payloadLength = 3 + uidBytes.length + gidBytes.length;
@@ -7681,7 +8107,7 @@
7681
8107
  }
7682
8108
  if (encrypted && !zipCrypto) {
7683
8109
  version = version > VERSION_AES ? version : VERSION_AES;
7684
- if (passThrough && crc32 !== UNDEFINED_VALUE) {
8110
+ if (passThroughCompression && crc32 !== UNDEFINED_VALUE) {
7685
8111
  rawExtraFieldAES[EXTRAFIELD_OFFSET_AES_VENDOR_VERSION] = VENDOR_VERSION_AE_1;
7686
8112
  }
7687
8113
  setUint16(getDataView(rawExtraFieldAES), EXTRAFIELD_OFFSET_AES_COMPRESSION_METHOD, compressionMethod);
@@ -7743,12 +8169,14 @@
7743
8169
  headerArray,
7744
8170
  headerView,
7745
8171
  lastModDate: storedLastModDate,
8172
+ lastModDateClamped: storedLastModDate === clampedLastModDate && dosLastModDate.getTime() != clampedLastModDate.getTime(),
7746
8173
  rawLastModDate,
7747
8174
  encrypted,
7748
8175
  compressed,
7749
8176
  version,
7750
8177
  compressionMethod,
7751
8178
  extraFieldExtendedTimestampFlag,
8179
+ extraFieldExtendedTimestampTime,
7752
8180
  rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
7753
8181
  localExtraFieldZip64Length,
7754
8182
  rawExtraFieldExtendedTimestamp,
@@ -7851,7 +8279,7 @@
7851
8279
  }, {
7852
8280
  zip64,
7853
8281
  zipCrypto,
7854
- passThrough,
8282
+ passThroughCompression,
7855
8283
  dataDescriptor
7856
8284
  }) {
7857
8285
  const {
@@ -7862,7 +8290,7 @@
7862
8290
  dataDescriptorView,
7863
8291
  dataDescriptorOffset
7864
8292
  } = dataDescriptorInfo;
7865
- if ((!encrypted || zipCrypto || passThrough) && crc32 !== UNDEFINED_VALUE) {
8293
+ if ((!encrypted || zipCrypto || passThroughCompression) && crc32 !== UNDEFINED_VALUE) {
7866
8294
  setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
7867
8295
  if (dataDescriptor) {
7868
8296
  setUint32(dataDescriptorView, dataDescriptorOffset, crc32);
@@ -7893,9 +8321,9 @@
7893
8321
  uncompressedSize,
7894
8322
  zip64UncompressedSize,
7895
8323
  zip64CompressedSize
7896
- }, localHeaderView, { dataDescriptor, passThrough }) {
8324
+ }, localHeaderView, { dataDescriptor, passThroughCompression }) {
7897
8325
  if (!dataDescriptor) {
7898
- if (!encrypted || (passThrough && crc32 !== UNDEFINED_VALUE)) {
8326
+ if (!encrypted || (passThroughCompression && crc32 !== UNDEFINED_VALUE)) {
7899
8327
  setUint32(localHeaderView, HEADER_OFFSET_SIGNATURE + LOCAL_HEADER_COMMON_OFFSET, crc32);
7900
8328
  }
7901
8329
  if (!zip64CompressedSize) {
@@ -7932,9 +8360,8 @@
7932
8360
  rawExtraFieldUnix,
7933
8361
  rawExtraField,
7934
8362
  rawCentralExtraField,
7935
- extendedTimestamp,
7936
8363
  extraFieldExtendedTimestampFlag,
7937
- lastModDate,
8364
+ extraFieldExtendedTimestampTime,
7938
8365
  zip64Enabled,
7939
8366
  uncompressedSize,
7940
8367
  compressedSize
@@ -7977,16 +8404,15 @@
7977
8404
  fileEntry.zip64Offset = zip64Offset;
7978
8405
  fileEntry.zip64DiskNumberStart = zip64DiskNumberStart;
7979
8406
  let rawExtraFieldTimestamp;
7980
- const lastModTimeUnix = getTimeUnix(lastModDate);
7981
- if (extendedTimestamp && inUnixTimeRange(lastModTimeUnix)) {
8407
+ if (extraFieldExtendedTimestampTime === UNDEFINED_VALUE) {
8408
+ rawExtraFieldTimestamp = EMPTY_UINT8_ARRAY;
8409
+ } else {
7982
8410
  const extraFieldTimestamp = createRecordWriter(9);
7983
8411
  extraFieldTimestamp.writeUint16(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
7984
8412
  extraFieldTimestamp.writeUint16(5);
7985
8413
  extraFieldTimestamp.writeUint8(extraFieldExtendedTimestampFlag);
7986
- extraFieldTimestamp.writeUint32(lastModTimeUnix);
8414
+ extraFieldTimestamp.writeUint32(extraFieldExtendedTimestampTime);
7987
8415
  rawExtraFieldTimestamp = extraFieldTimestamp.array;
7988
- } else {
7989
- rawExtraFieldTimestamp = EMPTY_UINT8_ARRAY;
7990
8416
  }
7991
8417
  fileEntry.rawExtraFieldExtendedTimestamp = rawExtraFieldTimestamp;
7992
8418
  const extraFieldLength = getLength(
@@ -8486,6 +8912,11 @@
8486
8912
  };
8487
8913
  }
8488
8914
 
8915
+ function isPrintableASCIIText(rawText) {
8916
+ return rawText.every(characterCode =>
8917
+ characterCode >= MIN_PRINTABLE_ASCII_CHARACTER_CODE && characterCode <= MAX_PRINTABLE_ASCII_CHARACTER_CODE);
8918
+ }
8919
+
8489
8920
  function getBitFlag(level, useUnicodeFileNames, dataDescriptor, encrypted, compressionMethod) {
8490
8921
  let bitFlag = 0;
8491
8922
  if (useUnicodeFileNames) {
@@ -8647,7 +9078,7 @@
8647
9078
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8648
9079
  */
8649
9080
 
8650
- const VERSION = "2.11.4";
9081
+ const VERSION = "2.13.0";
8651
9082
 
8652
9083
  /*
8653
9084
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
@@ -9128,7 +9559,10 @@
9128
9559
  const ERR_ENTRY_EXISTS = "Entry filename already exists";
9129
9560
  const ERR_DUPLICATE_IMPORTED_ENTRY = "Duplicate entry filename in the imported zip file";
9130
9561
  const ERR_INVALID_DUPLICATES = "Invalid duplicates option (must be \"throw\", \"keep-first\" or \"keep-last\")";
9131
- const ERR_ANCESTOR_ENTRY = "Entry is a ancestor of target entry";
9562
+ const ERR_ANCESTOR_ENTRY = "Entry is an ancestor of target entry";
9563
+ const ERR_ROOT_DIRECTORY_NOT_MOVABLE = "Root directory cannot be moved";
9564
+ const ERR_TARGET_NOT_DIRECTORY = "Target entry is not a directory";
9565
+ const ERR_PARENT_NOT_DIRECTORY = "Parent entry is not a directory";
9132
9566
  const ERR_READABLE_CONSUMED = "Readable stream already consumed";
9133
9567
  const DUPLICATES_THROW = "throw";
9134
9568
  const DUPLICATES_KEEP_FIRST = "keep-first";
@@ -9136,22 +9570,8 @@
9136
9570
  const DUPLICATES_VALUES = new Set([DUPLICATES_THROW, DUPLICATES_KEEP_FIRST, DUPLICATES_KEEP_LAST]);
9137
9571
  const ERR_INVALID_PASS_THROUGH = "Invalid passThrough option (use readerOptions.passThrough or set uncompressedSize for each entry)";
9138
9572
  const ERR_INVALID_READER_OPTIONS = "Invalid readerOptions (must be an object)";
9139
- const ERR_ZIP_CRYPTO_LAST_MOD_DATE = "The last modification date of an entry encrypted with ZipCrypto cannot be changed when passThrough is set";
9573
+ const ERR_UNSUPPORTED_PASS_THROUGH_VALUE = "The 'compressed' passThrough option is only supported by Entry#getData() and ZipWriter#add()";
9140
9574
  const ERR_ABORT_EXPORT = "zipjs-abort-export";
9141
- const INFOZIP_EXTRA_FIELD_TYPE = "infozip";
9142
- const INTERPRETED_EXTRA_FIELD_TYPES = new Set([
9143
- EXTRAFIELD_TYPE_ZIP64,
9144
- EXTRAFIELD_TYPE_AES,
9145
- EXTRAFIELD_TYPE_NTFS,
9146
- EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP,
9147
- EXTRAFIELD_TYPE_UNICODE_PATH,
9148
- EXTRAFIELD_TYPE_UNICODE_COMMENT,
9149
- EXTRAFIELD_TYPE_USDZ,
9150
- EXTRAFIELD_TYPE_INFOZIP,
9151
- EXTRAFIELD_TYPE_UNIX,
9152
- EXTRAFIELD_TYPE_UNIX_TYPE1,
9153
- EXTRAFIELD_TYPE_PKWARE_UNIX
9154
- ]);
9155
9575
 
9156
9576
  class ZipEntry {
9157
9577
 
@@ -9283,7 +9703,7 @@
9283
9703
  }));
9284
9704
  return true;
9285
9705
  } catch (error) {
9286
- if (error.message == ERR_INVALID_PASSWORD) {
9706
+ if (isErrorObject(error) && error.message == ERR_INVALID_PASSWORD) {
9287
9707
  return false;
9288
9708
  } else {
9289
9709
  throw error;
@@ -9523,6 +9943,7 @@
9523
9943
  await initStream(reader);
9524
9944
  zipReader = new ZipReader(reader, options);
9525
9945
  }
9946
+ checkPassThroughValue(options.passThrough);
9526
9947
  const duplicates = checkDuplicatesOption(options.duplicates);
9527
9948
  const importedEntries = [];
9528
9949
  const entries = await zipReader.getEntries(options);
@@ -9613,18 +10034,25 @@
9613
10034
 
9614
10035
  async exportZip(writer, options = {}) {
9615
10036
  const zipEntry = this;
10037
+ const zipWriterProvided = Boolean(writer) && typeof writer.add == FUNCTION_TYPE;
9616
10038
  options = Object.assign({}, options);
9617
- if (options.bufferedWrite === UNDEFINED_VALUE) {
10039
+ if (!zipWriterProvided && options.bufferedWrite === UNDEFINED_VALUE) {
9618
10040
  options.bufferedWrite = true;
9619
10041
  }
9620
- const [readers] = await Promise.all([initReaders(zipEntry, checkReaderOptions(options.readerOptions)), initStream(writer)]);
9621
- const zipWriter = new ZipWriter(writer, options);
10042
+ const [readers] = await Promise.all([
10043
+ initReaders(zipEntry, checkReaderOptions(options.readerOptions)),
10044
+ zipWriterProvided ? UNDEFINED_VALUE : initStream(writer)
10045
+ ]);
10046
+ const zipWriter = zipWriterProvided ? writer : new ZipWriter(writer, options);
9622
10047
  await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], getUncompressedSize), options, readers);
10048
+ if (zipWriterProvided) {
10049
+ return zipWriter;
10050
+ }
9623
10051
  await zipWriter.close(options.globalComment);
9624
10052
  return writer.getData ? writer.getData() : writer.writable;
9625
10053
  }
9626
10054
 
9627
- getExportedSize(options = {}) {
10055
+ async getExportedSize(options = {}) {
9628
10056
  const zipEntry = this;
9629
10057
  options = Object.assign({}, options);
9630
10058
  checkReaderOptions(options.readerOptions);
@@ -9639,7 +10067,7 @@
9639
10067
  const writeOrderGuaranteed = !options.bufferedWrite ||
9640
10068
  (entries.every(entry => entry.options.keepOrder !== false) &&
9641
10069
  children.every(child => isImplicitDirectory(child) || !child.children.length));
9642
- return getEntriesSize(options, entries, writeOrderGuaranteed, options.globalComment);
10070
+ return await getEntriesSize(options, entries, writeOrderGuaranteed, options.globalComment);
9643
10071
  }
9644
10072
 
9645
10073
  getChildByName(name) {
@@ -9700,7 +10128,7 @@
9700
10128
 
9701
10129
  move(entry, destination) {
9702
10130
  if (entry == this.root) {
9703
- throw new Error("Root directory cannot be moved");
10131
+ throw new Error(ERR_ROOT_DIRECTORY_NOT_MOVABLE);
9704
10132
  } else {
9705
10133
  if (destination.directory) {
9706
10134
  if (!destination.isDescendantOf(entry)) {
@@ -9721,7 +10149,7 @@
9721
10149
  throw new Error(ERR_ANCESTOR_ENTRY);
9722
10150
  }
9723
10151
  } else {
9724
- throw new Error("Target entry is not a directory");
10152
+ throw new Error(ERR_TARGET_NOT_DIRECTORY);
9725
10153
  }
9726
10154
  }
9727
10155
  }
@@ -10034,70 +10462,11 @@
10034
10462
  let zipEntryMetadata = {};
10035
10463
  let passThroughOptions = {};
10036
10464
  if (child.data instanceof Entry) {
10037
- const {
10038
- externalFileAttributes,
10039
- versionMadeBy,
10040
- comment,
10041
- lastModDate,
10042
- rawLastModDate,
10043
- creationDate,
10044
- lastAccessDate,
10045
- uncompressedSize,
10046
- encrypted,
10047
- zipCrypto,
10048
- crc32,
10049
- compressionMethod,
10050
- extraFieldAES,
10051
- internalFileAttributes,
10052
- extraField,
10053
- bitFlag,
10054
- uid,
10055
- gid
10056
- } = child.data;
10057
- zipEntryMetadata = {
10058
- externalFileAttributes,
10059
- versionMadeBy,
10060
- comment,
10061
- lastModDate,
10062
- creationDate,
10063
- lastAccessDate,
10064
- internalFileAttributes
10065
- };
10066
- const userExtraField = getUserExtraField(extraField);
10067
- if (userExtraField) {
10068
- zipEntryMetadata.extraField = userExtraField;
10069
- }
10070
- if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
10071
- Object.assign(zipEntryMetadata, {
10072
- uid,
10073
- gid,
10074
- unixExtraFieldType: INFOZIP_EXTRA_FIELD_TYPE
10075
- });
10076
- }
10077
- if (isPassThrough(child, options)) {
10078
- let encryptionStrength;
10079
- if (extraFieldAES) {
10080
- encryptionStrength = extraFieldAES.strength;
10081
- }
10082
- passThroughOptions = {
10083
- passThrough: true,
10084
- encrypted,
10085
- zipCrypto,
10086
- crc32,
10087
- uncompressedSize,
10088
- encryptionStrength,
10089
- compressionMethod
10090
- };
10091
- if (bitFlag) {
10092
- passThroughOptions.dataDescriptor = bitFlag.dataDescriptor;
10093
- }
10094
- const lastModDateOverride = childOptions.lastModDate === UNDEFINED_VALUE ? options.lastModDate : childOptions.lastModDate;
10095
- if (lastModDateOverride === UNDEFINED_VALUE) {
10096
- passThroughOptions.rawLastModDate = rawLastModDate;
10097
- } else if (zipCrypto && (!bitFlag || bitFlag.dataDescriptor) && lastModDateOverride instanceof Date &&
10098
- getDosTimeHighByte(lastModDateOverride) != ((rawLastModDate >>> 8) & MAX_8_BITS)) {
10099
- throw new Error(ERR_ZIP_CRYPTO_LAST_MOD_DATE);
10100
- }
10465
+ const passThrough = isPassThrough(child, options);
10466
+ const lastModDateOverride = childOptions.lastModDate === UNDEFINED_VALUE ? options.lastModDate : childOptions.lastModDate;
10467
+ ({ entryOptions: zipEntryMetadata, passThroughOptions } = getSourceEntryOptions(child.data, passThrough, lastModDateOverride));
10468
+ if (passThrough) {
10469
+ passThroughOptions.passThrough = true;
10101
10470
  }
10102
10471
  }
10103
10472
  const entryOptions = Object.assign({ lastModDate: child.defaultLastModDate }, zipEntryMetadata, options, childOptions, passThroughOptions, { directory: child.directory });
@@ -10107,16 +10476,6 @@
10107
10476
  return { name, entryOptions };
10108
10477
  }
10109
10478
 
10110
- function getDosTimeHighByte(lastModDate) {
10111
- let dosLastModDate = new Date(Math.ceil(Math.floor(lastModDate.getTime() / 1000) / 2) * 2000);
10112
- if (dosLastModDate < MIN_DATE) {
10113
- dosLastModDate = MIN_DATE;
10114
- } else if (dosLastModDate > MAX_DATE) {
10115
- dosLastModDate = MAX_DATE;
10116
- }
10117
- return ((dosLastModDate.getHours() << 3) | (dosLastModDate.getMinutes() >> 3)) & MAX_8_BITS;
10118
- }
10119
-
10120
10479
  function getDeterminedSize(child, passThrough) {
10121
10480
  const { reader } = child;
10122
10481
  if (reader && reader.size !== UNDEFINED_VALUE) {
@@ -10129,9 +10488,18 @@
10129
10488
  if (readerOptions && (typeof readerOptions != OBJECT_TYPE || Array.isArray(readerOptions))) {
10130
10489
  throw new Error(ERR_INVALID_READER_OPTIONS);
10131
10490
  }
10491
+ if (readerOptions) {
10492
+ checkPassThroughValue(readerOptions.passThrough);
10493
+ }
10132
10494
  return readerOptions;
10133
10495
  }
10134
10496
 
10497
+ function checkPassThroughValue(passThrough) {
10498
+ if (checkPassThroughOption(passThrough) === PASS_THROUGH_COMPRESSED) {
10499
+ throw new Error(ERR_UNSUPPORTED_PASS_THROUGH_VALUE);
10500
+ }
10501
+ }
10502
+
10135
10503
  function replaceContent(zipEntry, params) {
10136
10504
  const { uncompressedSize } = params;
10137
10505
  Object.assign(zipEntry, params, {
@@ -10160,20 +10528,6 @@
10160
10528
  return child.directory && child.data === null;
10161
10529
  }
10162
10530
 
10163
- function getUserExtraField(extraField) {
10164
- if (extraField) {
10165
- const userExtraField = new Map();
10166
- extraField.forEach((field, type) => {
10167
- if (!INTERPRETED_EXTRA_FIELD_TYPES.has(type)) {
10168
- userExtraField.set(type, field.data);
10169
- }
10170
- });
10171
- if (userExtraField.size) {
10172
- return userExtraField;
10173
- }
10174
- }
10175
- }
10176
-
10177
10531
  async function exportZip(zipWriter, entry, totalSize, options, readers) {
10178
10532
  const { onstart, onprogress, onend, onentryprogress } = options;
10179
10533
  const selectedEntry = entry;
@@ -10276,6 +10630,7 @@
10276
10630
 
10277
10631
  async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
10278
10632
  const { onstart, onprogress, onend } = options;
10633
+ checkPassThroughValue(options.passThrough);
10279
10634
  const readerOptions = checkReaderOptions(options.readerOptions);
10280
10635
  const abortController = new AbortController();
10281
10636
  const { signal } = abortController;
@@ -10351,7 +10706,7 @@
10351
10706
  if (exportAborted || isExportAborted(signal.reason)) {
10352
10707
  return;
10353
10708
  }
10354
- throw signal.reason === UNDEFINED_VALUE ? new DOMException(ERR_ABORTED, ABORT_ERROR_NAME) : signal.reason;
10709
+ throwIfAborted(signal);
10355
10710
  }
10356
10711
  try {
10357
10712
  if (child.directory) {
@@ -10484,7 +10839,7 @@
10484
10839
  }
10485
10840
  return directory ? new ZipDirectoryEntry(parent.fs, name, params, parent) : new ZipFileEntry(parent.fs, name, params, parent);
10486
10841
  } else {
10487
- throw new Error("Parent entry is not a directory");
10842
+ throw new Error(ERR_PARENT_NOT_DIRECTORY);
10488
10843
  }
10489
10844
  }
10490
10845
 
@@ -10531,6 +10886,7 @@
10531
10886
  exports.Data64URIWriter = Data64URIWriter;
10532
10887
  exports.ERR_ABORTED = ERR_ABORTED;
10533
10888
  exports.ERR_AMBIGUOUS_ARCHIVE = ERR_AMBIGUOUS_ARCHIVE;
10889
+ exports.ERR_ANCESTOR_ENTRY = ERR_ANCESTOR_ENTRY;
10534
10890
  exports.ERR_BAD_FORMAT = ERR_BAD_FORMAT;
10535
10891
  exports.ERR_CENTRAL_DIRECTORY_NOT_FOUND = ERR_CENTRAL_DIRECTORY_NOT_FOUND;
10536
10892
  exports.ERR_DUPLICATED_NAME = ERR_DUPLICATED_NAME;
@@ -10544,7 +10900,9 @@
10544
10900
  exports.ERR_EXTRAFIELD_ZIP64_NOT_FOUND = ERR_EXTRAFIELD_ZIP64_NOT_FOUND;
10545
10901
  exports.ERR_HTTP_RANGE = ERR_HTTP_RANGE;
10546
10902
  exports.ERR_HTTP_RESOURCE_CHANGED = ERR_HTTP_RESOURCE_CHANGED;
10903
+ exports.ERR_HTTP_STATUS = ERR_HTTP_STATUS;
10547
10904
  exports.ERR_INVALID_AUTHENTICATION_CODE = ERR_INVALID_AUTHENTICATION_CODE;
10905
+ exports.ERR_INVALID_BASE_URI = ERR_INVALID_BASE_URI;
10548
10906
  exports.ERR_INVALID_CODEC_DEFINITION = ERR_INVALID_CODEC_DEFINITION;
10549
10907
  exports.ERR_INVALID_CODEC_MODULE = ERR_INVALID_CODEC_MODULE;
10550
10908
  exports.ERR_INVALID_COMMENT = ERR_INVALID_COMMENT;
@@ -10554,6 +10912,7 @@
10554
10912
  exports.ERR_INVALID_DATE = ERR_INVALID_DATE;
10555
10913
  exports.ERR_INVALID_DUPLICATES = ERR_INVALID_DUPLICATES;
10556
10914
  exports.ERR_INVALID_ENCRYPTION_STRENGTH = ERR_INVALID_ENCRYPTION_STRENGTH;
10915
+ exports.ERR_INVALID_ENTRY = ERR_INVALID_ENTRY;
10557
10916
  exports.ERR_INVALID_ENTRY_COMMENT = ERR_INVALID_ENTRY_COMMENT;
10558
10917
  exports.ERR_INVALID_ENTRY_COMMENT_TYPE = ERR_INVALID_ENTRY_COMMENT_TYPE;
10559
10918
  exports.ERR_INVALID_ENTRY_NAME = ERR_INVALID_ENTRY_NAME;
@@ -10572,6 +10931,7 @@
10572
10931
  exports.ERR_INVALID_PASSWORD = ERR_INVALID_PASSWORD;
10573
10932
  exports.ERR_INVALID_PASSWORD_TYPE = ERR_INVALID_PASSWORD_TYPE;
10574
10933
  exports.ERR_INVALID_PASS_THROUGH = ERR_INVALID_PASS_THROUGH;
10934
+ exports.ERR_INVALID_PASS_THROUGH_VALUE = ERR_INVALID_PASS_THROUGH_VALUE;
10575
10935
  exports.ERR_INVALID_READER = ERR_INVALID_READER;
10576
10936
  exports.ERR_INVALID_READER_OPTIONS = ERR_INVALID_READER_OPTIONS;
10577
10937
  exports.ERR_INVALID_SIGNAL = ERR_INVALID_SIGNAL;
@@ -10582,14 +10942,19 @@
10582
10942
  exports.ERR_INVALID_UNIX_EXTRA_FIELD_TYPE = ERR_INVALID_UNIX_EXTRA_FIELD_TYPE;
10583
10943
  exports.ERR_INVALID_UNIX_ID_SIZE = ERR_INVALID_UNIX_ID_SIZE;
10584
10944
  exports.ERR_INVALID_UNIX_MODE = ERR_INVALID_UNIX_MODE;
10945
+ exports.ERR_INVALID_URI = ERR_INVALID_URI;
10585
10946
  exports.ERR_INVALID_VERSION = ERR_INVALID_VERSION;
10586
10947
  exports.ERR_ITERATOR_COMPLETED_TOO_SOON = ERR_ITERATOR_COMPLETED_TOO_SOON;
10587
10948
  exports.ERR_LOCAL_FILE_HEADER_NOT_FOUND = ERR_LOCAL_FILE_HEADER_NOT_FOUND;
10588
10949
  exports.ERR_OVERLAPPING_ENTRY = ERR_OVERLAPPING_ENTRY;
10950
+ exports.ERR_PARENT_NOT_DIRECTORY = ERR_PARENT_NOT_DIRECTORY;
10589
10951
  exports.ERR_READABLE_CONSUMED = ERR_READABLE_CONSUMED;
10590
10952
  exports.ERR_RESERVED_COMPRESSION_METHOD = ERR_RESERVED_COMPRESSION_METHOD;
10953
+ exports.ERR_ROOT_DIRECTORY_NOT_MOVABLE = ERR_ROOT_DIRECTORY_NOT_MOVABLE;
10591
10954
  exports.ERR_SPLIT_ZIP_FILE = ERR_SPLIT_ZIP_FILE;
10955
+ exports.ERR_TARGET_NOT_DIRECTORY = ERR_TARGET_NOT_DIRECTORY;
10592
10956
  exports.ERR_UNDEFINED_COMPRESSION_METHOD = ERR_UNDEFINED_COMPRESSION_METHOD;
10957
+ exports.ERR_UNDEFINED_CRC32 = ERR_UNDEFINED_CRC32;
10593
10958
  exports.ERR_UNDEFINED_READER = ERR_UNDEFINED_READER;
10594
10959
  exports.ERR_UNDEFINED_UNCOMPRESSED_SIZE = ERR_UNDEFINED_UNCOMPRESSED_SIZE;
10595
10960
  exports.ERR_UNDETERMINED_SIZE = ERR_UNDETERMINED_SIZE;
@@ -10601,10 +10966,12 @@
10601
10966
  exports.ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH;
10602
10967
  exports.ERR_UNSUPPORTED_ENCRYPTION_USDZ = ERR_UNSUPPORTED_ENCRYPTION_USDZ;
10603
10968
  exports.ERR_UNSUPPORTED_FORMAT = ERR_UNSUPPORTED_FORMAT;
10969
+ exports.ERR_UNSUPPORTED_PASS_THROUGH_VALUE = ERR_UNSUPPORTED_PASS_THROUGH_VALUE;
10604
10970
  exports.ERR_UNSUPPORTED_SPLIT_USDZ = ERR_UNSUPPORTED_SPLIT_USDZ;
10605
10971
  exports.ERR_UNSUPPORTED_UINT64 = ERR_UNSUPPORTED_UINT64;
10606
10972
  exports.ERR_WORKER_STARTUP_TIMEOUT = ERR_WORKER_STARTUP_TIMEOUT;
10607
10973
  exports.ERR_WRITER_NOT_INITIALIZED = ERR_WRITER_NOT_INITIALIZED;
10974
+ exports.ERR_WRITER_SIZE_NOT_WRITABLE = ERR_WRITER_SIZE_NOT_WRITABLE;
10608
10975
  exports.ERR_ZIP_CRYPTO_LAST_MOD_DATE = ERR_ZIP_CRYPTO_LAST_MOD_DATE;
10609
10976
  exports.ERR_ZIP_NOT_EMPTY = ERR_ZIP_NOT_EMPTY;
10610
10977
  exports.HttpRangeReader = HttpRangeReader;
@@ -10618,13 +10985,17 @@
10618
10985
  exports.Uint8ArrayWriter = Uint8ArrayWriter;
10619
10986
  exports.VERSION = VERSION;
10620
10987
  exports.WARNING_APPENDED_DATA = WARNING_APPENDED_DATA;
10988
+ exports.WARNING_CLAMPED_LAST_MODIFICATION_DATE = WARNING_CLAMPED_LAST_MODIFICATION_DATE;
10621
10989
  exports.WARNING_COMPRESSED_PATCHED_DATA = WARNING_COMPRESSED_PATCHED_DATA;
10990
+ exports.WARNING_COMPRESSION_UNAVAILABLE = WARNING_COMPRESSION_UNAVAILABLE;
10622
10991
  exports.WARNING_DUPLICATE_FILENAME = WARNING_DUPLICATE_FILENAME;
10623
10992
  exports.WARNING_MALFORMED_EXTRA_FIELD = WARNING_MALFORMED_EXTRA_FIELD;
10624
10993
  exports.WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG = WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG;
10625
10994
  exports.WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD = WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD;
10626
10995
  exports.WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES = WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES;
10996
+ exports.WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME = WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME;
10627
10997
  exports.WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY = WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY;
10998
+ exports.WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY = WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY;
10628
10999
  exports.WARNING_PREPENDED_CENTRAL_DIRECTORY = WARNING_PREPENDED_CENTRAL_DIRECTORY;
10629
11000
  exports.WARNING_PREPENDED_DATA = WARNING_PREPENDED_DATA;
10630
11001
  exports.WARNING_TRAILING_CENTRAL_DIRECTORY_DATA = WARNING_TRAILING_CENTRAL_DIRECTORY_DATA;