single-file-core 1.5.126 → 1.5.128

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/vendor/zip/zip.js CHANGED
@@ -127,6 +127,7 @@ const NUMBER_TYPE = "number";
127
127
  const BOOLEAN_TYPE = "boolean";
128
128
 
129
129
  const EMPTY_UINT8_ARRAY = new Uint8Array();
130
+ const SYMBOL_ASYNC_DISPOSE = Symbol.asyncDispose || Symbol();
130
131
 
131
132
  /*
132
133
  Copyright (c) 2022 Gildas Lormeau. All rights reserved.
@@ -171,6 +172,7 @@ const OPTION_CHECK_OVERLAPPING_ENTRY_ONLY = "checkOverlappingEntryOnly";
171
172
  const OPTION_CHECK_OVERLAPPING_ENTRY = "checkOverlappingEntry";
172
173
  const OPTION_CHECK_AMBIGUITY = "checkAmbiguity";
173
174
  const OPTION_CHECK_LOCAL_DIRECTORY = "checkLocalDirectory";
175
+ const OPTION_CHECK_LOCAL_FILENAME = "checkLocalFilename";
174
176
  const OPTION_CHECK_SIGNATURE = "checkSignature";
175
177
  const OPTION_CHECK_CRC32 = "checkCrc32";
176
178
  const OPTION_CHECK_AUTHENTICATION_CODE = "checkAuthenticationCode";
@@ -201,15 +203,20 @@ const OPTION_NORMALIZE_FILENAME = "normalizeFilename";
201
203
  const OPTION_MAX_APPENDED_DATA_SIZE = "maxAppendedDataSize";
202
204
  const OPTION_DECRYPT_CENTRAL_DIRECTORY = "decryptCentralDirectory";
203
205
  const OPTION_SIGN_CENTRAL_DIRECTORY = "signCentralDirectory";
206
+ const OPTION_ENTRY = "entry";
204
207
  const TEXT_TYPE_FILENAME = "filename";
205
208
  const TEXT_TYPE_COMMENT = "comment";
206
209
  const STRICTNESS_STRICT = "strict";
207
210
  const STRICTNESS_BALANCED = "balanced";
208
211
  const STRICTNESS_TOLERANT = "tolerant";
212
+ const PASS_THROUGH_COMPRESSED = "compressed";
209
213
 
210
214
  const ERR_INVALID_FUNCTION_OPTION = "Invalid option (must be a function)";
211
215
  const ERR_INVALID_SIGNAL = "Invalid signal (must be an AbortSignal instance)";
212
216
  const ERR_INVALID_PASSWORD_TYPE = "Invalid password (password must be a string, rawPassword must be a Uint8Array)";
217
+ const ERR_INVALID_PASS_THROUGH_VALUE = "Invalid passThrough option (must be a boolean or 'compressed')";
218
+ const ERR_ABORTED = "The operation was aborted";
219
+ const ABORT_ERROR_NAME = "AbortError";
213
220
 
214
221
  function checkFunctionOption(value) {
215
222
  if (value && typeof value != FUNCTION_TYPE) {
@@ -225,12 +232,25 @@ function checkSignalOption(signal) {
225
232
  return signal || UNDEFINED_VALUE;
226
233
  }
227
234
 
235
+ function throwIfAborted(signal) {
236
+ if (signal && signal.aborted) {
237
+ throw signal.reason === UNDEFINED_VALUE ? new DOMException(ERR_ABORTED, ABORT_ERROR_NAME) : signal.reason;
238
+ }
239
+ }
240
+
228
241
  function checkPasswordOption(password, rawPassword) {
229
242
  if ((password && typeof password != STRING_TYPE) || (rawPassword && !(rawPassword instanceof Uint8Array))) {
230
243
  throw new Error(ERR_INVALID_PASSWORD_TYPE);
231
244
  }
232
245
  }
233
246
 
247
+ function checkPassThroughOption(passThrough) {
248
+ if (passThrough !== UNDEFINED_VALUE && typeof passThrough != BOOLEAN_TYPE && passThrough !== PASS_THROUGH_COMPRESSED) {
249
+ throw new Error(ERR_INVALID_PASS_THROUGH_VALUE);
250
+ }
251
+ return passThrough;
252
+ }
253
+
234
254
  function checkInteger(value, maxValue, errorMessage) {
235
255
  if (!Number.isInteger(value) || value < 0 || value > maxValue) {
236
256
  throw new Error(errorMessage);
@@ -280,6 +300,8 @@ const DEFAULT_CHUNK_SIZE$1 = 64 * 1024;
280
300
  const MINIMUM_CHUNK_SIZE = 64;
281
301
  const MINIMUM_PROPERTY_VALUE = 1;
282
302
  const ERR_INVALID_MAX_WORKERS = "Invalid maxWorkers (must be an integer greater than 0)";
303
+ const ERR_INVALID_BASE_URI = "Invalid baseURI (must be a string)";
304
+ const ERR_INVALID_URI = "Invalid URI (must be a string or a function returning a string)";
283
305
  let maxWorkers = 2;
284
306
  try {
285
307
  if (typeof navigator != UNDEFINED_TYPE && navigator.hardwareConcurrency) {
@@ -304,9 +326,9 @@ const DEFAULT_CONFIGURATION = {
304
326
  };
305
327
 
306
328
  const PROPERTY_NAME_MAX_WORKERS = "maxWorkers";
329
+ const PROPERTY_NAME_BASE_URI = "baseURI";
307
330
 
308
- const STRING_PROPERTY_NAMES = [
309
- "baseURI",
331
+ const URI_PROPERTY_NAMES = [
310
332
  "wasmURI",
311
333
  "workerURI"
312
334
  ];
@@ -330,7 +352,8 @@ const FUNCTION_PROPERTY_NAMES = [
330
352
  "DecompressionStreamFallback"
331
353
  ];
332
354
  const CONFIGURABLE_PROPERTY_NAMES = [
333
- ...STRING_PROPERTY_NAMES,
355
+ PROPERTY_NAME_BASE_URI,
356
+ ...URI_PROPERTY_NAMES,
334
357
  ...BOOLEAN_PROPERTY_NAMES,
335
358
  ...NUMBER_PROPERTY_NAMES,
336
359
  ...FUNCTION_PROPERTY_NAMES
@@ -374,6 +397,14 @@ function checkPropertyValue(propertyName, propertyValue) {
374
397
  }
375
398
  } else if (FUNCTION_PROPERTY_NAMES.includes(propertyName)) {
376
399
  checkFunctionOption(propertyValue);
400
+ } else if (propertyName == PROPERTY_NAME_BASE_URI) {
401
+ if (propertyValue && typeof propertyValue != STRING_TYPE) {
402
+ throw new Error(ERR_INVALID_BASE_URI);
403
+ }
404
+ } else if (URI_PROPERTY_NAMES.includes(propertyName)) {
405
+ if (propertyValue && typeof propertyValue != STRING_TYPE && typeof propertyValue != FUNCTION_TYPE) {
406
+ throw new Error(ERR_INVALID_URI);
407
+ }
377
408
  }
378
409
  return propertyValue;
379
410
  }
@@ -451,6 +482,39 @@ function getDataView(array) {
451
482
  return new DataView(array.buffer, array.byteOffset, array.byteLength);
452
483
  }
453
484
 
485
+ /*
486
+ Copyright (c) 2026 Gildas Lormeau. All rights reserved.
487
+
488
+ Redistribution and use in source and binary forms, with or without
489
+ modification, are permitted provided that the following conditions are met:
490
+
491
+ 1. Redistributions of source code must retain the above copyright notice,
492
+ this list of conditions and the following disclaimer.
493
+
494
+ 2. Redistributions in binary form must reproduce the above copyright
495
+ notice, this list of conditions and the following disclaimer in
496
+ the documentation and/or other materials provided with the distribution.
497
+
498
+ 3. The names of the authors may not be used to endorse or promote products
499
+ derived from this software without specific prior written permission.
500
+
501
+ THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
502
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
503
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
504
+ INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
505
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
506
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
507
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
508
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
509
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
510
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
511
+ */
512
+
513
+
514
+ function isErrorObject(error) {
515
+ return Boolean(error) && typeof error == "object";
516
+ }
517
+
454
518
  /*
455
519
  Copyright (c) 2022 Gildas Lormeau. All rights reserved.
456
520
 
@@ -2590,6 +2654,7 @@ class ChunkStream extends TransformStream {
2590
2654
  constructor(chunkSize) {
2591
2655
  const pendingChunks = [];
2592
2656
  let pendingLength = 0;
2657
+ let outputSize = 0;
2593
2658
  if (!Number.isFinite(chunkSize) || chunkSize < 1) {
2594
2659
  chunkSize = DEFAULT_CHUNK_SIZE;
2595
2660
  }
@@ -2598,15 +2663,20 @@ class ChunkStream extends TransformStream {
2598
2663
  pendingChunks.push(chunk);
2599
2664
  pendingLength += chunk.length;
2600
2665
  while (pendingLength > chunkSize) {
2666
+ outputSize += chunkSize;
2601
2667
  controller.enqueue(shiftChunk());
2602
2668
  }
2603
2669
  },
2604
2670
  flush(controller) {
2605
2671
  if (pendingLength) {
2672
+ outputSize += pendingLength;
2606
2673
  controller.enqueue(concatChunks(pendingChunks, pendingLength));
2607
2674
  }
2608
2675
  }
2609
2676
  });
2677
+ Object.defineProperty(this, "outputSize", {
2678
+ get: () => outputSize
2679
+ });
2610
2680
 
2611
2681
  function shiftChunk() {
2612
2682
  const result = new Uint8Array(chunkSize);
@@ -2712,7 +2782,9 @@ function disableWebWorker(workerData) {
2712
2782
 
2713
2783
  class CodecWorker {
2714
2784
 
2715
- constructor(workerData, { readable, writable }, { options, config, streamOptions, useWebWorkers, transferStreams, workerURI, createWorker }, onTaskFinished) {
2785
+ constructor(workerData, { readable, writable }, workerOptions, onTaskFinished) {
2786
+ const { options, config, streamOptions, useWebWorkers, transferStreams, workerURI } = workerOptions;
2787
+ let { createWorker } = workerOptions;
2716
2788
  const { signal } = streamOptions;
2717
2789
  if (createWorkerFailed) {
2718
2790
  createWorker = UNDEFINED_VALUE;
@@ -2725,6 +2797,7 @@ class CodecWorker {
2725
2797
  .pipeThrough(new ProgressWatcherStream(streamOptions), { signal }),
2726
2798
  writable,
2727
2799
  options: Object.assign({}, options),
2800
+ workerOptions,
2728
2801
  workerURI,
2729
2802
  createWorker,
2730
2803
  transferStreams,
@@ -2806,8 +2879,8 @@ function createWorkerInterface(workerData, config) {
2806
2879
  };
2807
2880
  }
2808
2881
 
2809
- async function runWorker$1({ options, readable, writable, onTaskFinished }, config) {
2810
- let codecStream;
2882
+ async function runWorker$1({ options, readable, writable, onTaskFinished, workerOptions }, config) {
2883
+ let codecStream, chunkStream;
2811
2884
  try {
2812
2885
  if (options.compressed && !options.format) {
2813
2886
  const deflate = options.codecType.startsWith(CODEC_DEFLATE);
@@ -2830,9 +2903,10 @@ async function runWorker$1({ options, readable, writable, onTaskFinished }, conf
2830
2903
  }
2831
2904
  }
2832
2905
  codecStream = new CodecStream(options, config);
2906
+ chunkStream = new ChunkStream(getChunkSize(config));
2833
2907
  await readable
2834
2908
  .pipeThrough(codecStream)
2835
- .pipeThrough(new ChunkStream(getChunkSize(config)))
2909
+ .pipeThrough(chunkStream)
2836
2910
  .pipeTo(writable, { preventClose: true, preventAbort: true });
2837
2911
  const {
2838
2912
  crc32,
@@ -2846,7 +2920,15 @@ async function runWorker$1({ options, readable, writable, onTaskFinished }, conf
2846
2920
  };
2847
2921
  } catch (error) {
2848
2922
  if (codecStream) {
2849
- error.outputSize = codecStream.outputSize;
2923
+ const outputSize = chunkStream ? chunkStream.outputSize : 0;
2924
+ workerOptions.outputSize = outputSize;
2925
+ if (isErrorObject(error)) {
2926
+ try {
2927
+ error.outputSize = outputSize;
2928
+ } catch {
2929
+ // ignored
2930
+ }
2931
+ }
2850
2932
  }
2851
2933
  throw error;
2852
2934
  } finally {
@@ -2955,17 +3037,31 @@ async function runWebWorker(workerData, config) {
2955
3037
  let resolveResult, rejectResult;
2956
3038
  const result = new Promise((resolve, reject) => {
2957
3039
  resolveResult = resolve;
2958
- rejectResult = reject;
3040
+ rejectResult = error => {
3041
+ const { outputSize, workerOptions } = workerData;
3042
+ workerOptions.outputSize = outputSize;
3043
+ if (isErrorObject(error)) {
3044
+ try {
3045
+ error.outputSize = outputSize;
3046
+ } catch {
3047
+ // ignored
3048
+ }
3049
+ }
3050
+ reject(error);
3051
+ };
2959
3052
  });
2960
3053
  Object.assign(workerData, {
2961
3054
  reader: null,
2962
3055
  writer: null,
3056
+ outputSize: 0,
3057
+ destinationFailed: false,
3058
+ destinationError: null,
2963
3059
  resolveResult,
2964
3060
  rejectResult,
2965
3061
  result
2966
3062
  });
2967
3063
  const { readable, options } = workerData;
2968
- const { writable, closed, abortPipe } = watchClosedStream(workerData.writable);
3064
+ const { writable, closed, abortPipe } = watchClosedStream(workerData.writable, workerData);
2969
3065
  let streamsTransferred;
2970
3066
  try {
2971
3067
  streamsTransferred = sendMessage({
@@ -3008,7 +3104,18 @@ async function runWebWorker(workerData, config) {
3008
3104
  } catch {
3009
3105
  // ignored
3010
3106
  }
3011
- throw error;
3107
+ const { outputSize, workerOptions, destinationFailed, destinationError } = workerData;
3108
+ workerOptions.outputSize = outputSize;
3109
+ const workerFailed = isErrorObject(error) && (error.codecImportFailed || error.workerStartupFailed);
3110
+ const reportedError = destinationFailed && !workerFailed ? destinationError : error;
3111
+ if (isErrorObject(reportedError)) {
3112
+ try {
3113
+ reportedError.outputSize = outputSize;
3114
+ } catch {
3115
+ // ignored
3116
+ }
3117
+ }
3118
+ throw reportedError;
3012
3119
  }
3013
3120
 
3014
3121
  async function closeWritable() {
@@ -3022,12 +3129,27 @@ async function runWebWorker(workerData, config) {
3022
3129
  }
3023
3130
  }
3024
3131
 
3025
- function watchClosedStream(writableSource) {
3132
+ function watchClosedStream(writableSource, workerData) {
3026
3133
  const abortController = new AbortController();
3027
- const { writable, readable } = new TransformStream();
3134
+ let aborting;
3135
+ const { writable, readable } = new TransformStream({
3136
+ transform(chunk, controller) {
3137
+ workerData.outputSize += chunk.length;
3138
+ controller.enqueue(chunk);
3139
+ }
3140
+ });
3028
3141
  const closed = readable.pipeTo(writableSource, { preventClose: true, preventAbort: true, signal: abortController.signal });
3029
- closed.catch(() => { });
3030
- return { writable, closed, abortPipe: () => abortController.abort() };
3142
+ closed.catch(error => {
3143
+ if (!aborting) {
3144
+ Object.assign(workerData, { destinationFailed: true, destinationError: error });
3145
+ }
3146
+ });
3147
+ return {
3148
+ writable, closed, abortPipe: () => {
3149
+ aborting = true;
3150
+ abortController.abort();
3151
+ }
3152
+ };
3031
3153
  }
3032
3154
 
3033
3155
  function releaseWorkerStreams(workerData) {
@@ -3220,21 +3342,12 @@ function sendMessage(message, { worker, writer, transferStreams, workerAlive })
3220
3342
  }
3221
3343
 
3222
3344
  async function onMessage({ data }, workerData) {
3223
- const { type, value, messageId, result, error } = data;
3345
+ const { type, value, messageId, result, error, errorValue } = data;
3224
3346
  const { reader, writer, resolveResult, rejectResult, onTaskFinished, generation } = workerData;
3225
3347
  const stale = () => workerData.generation != generation;
3226
3348
  try {
3227
3349
  if (error) {
3228
- const { message, stack, code, name, outputSize, cause, codecImportFailed } = error;
3229
- const responseError = new Error(message);
3230
- Object.assign(responseError, { stack, code, name, outputSize });
3231
- if (cause) {
3232
- responseError.cause = Object.assign(new Error(cause.message), { name: cause.name });
3233
- }
3234
- if (codecImportFailed) {
3235
- responseError.codecImportFailed = true;
3236
- }
3237
- close(responseError);
3350
+ fail(getResponseError(error, errorValue));
3238
3351
  } else {
3239
3352
  if (type == MESSAGE_PULL) {
3240
3353
  const { value, done } = await reader.read();
@@ -3243,39 +3356,81 @@ async function onMessage({ data }, workerData) {
3243
3356
  }
3244
3357
  }
3245
3358
  if (type == MESSAGE_DATA) {
3359
+ const chunk = new Uint8Array(value);
3246
3360
  await writer.ready;
3247
- await writer.write(new Uint8Array(value));
3361
+ await writer.write(chunk);
3248
3362
  if (!stale()) {
3249
3363
  sendMessage({ type: MESSAGE_ACK_DATA, messageId }, workerData);
3250
3364
  }
3251
3365
  }
3252
3366
  if (type == MESSAGE_CLOSE) {
3253
- close(null, result);
3367
+ succeed(result);
3254
3368
  }
3255
3369
  }
3256
3370
  } catch (error) {
3257
3371
  if (!stale()) {
3258
3372
  terminateWorker$1(workerData);
3259
- close(error);
3373
+ fail(error);
3260
3374
  }
3261
3375
  }
3262
3376
 
3263
- function close(error, result) {
3264
- if (stale()) {
3265
- return;
3266
- }
3267
- if (error) {
3377
+ function fail(error) {
3378
+ if (!stale()) {
3268
3379
  rejectResult(error);
3269
- } else {
3380
+ releaseWriter();
3381
+ if (!(isErrorObject(error) && error.codecImportFailed)) {
3382
+ onTaskFinished();
3383
+ }
3384
+ }
3385
+ }
3386
+
3387
+ function succeed(result) {
3388
+ if (!stale()) {
3270
3389
  resolveResult(result);
3390
+ releaseWriter();
3391
+ onTaskFinished();
3271
3392
  }
3393
+ }
3394
+
3395
+ function releaseWriter() {
3272
3396
  if (writer) {
3273
3397
  writer.releaseLock();
3274
3398
  }
3275
- if (!(error && error.codecImportFailed)) {
3276
- onTaskFinished();
3399
+ }
3400
+ }
3401
+
3402
+ function getResponseError(errorData, errorValue) {
3403
+ const { message, stack, code, name, outputSize, cause, codecImportFailed } = errorData;
3404
+ let responseError;
3405
+ if (errorValue) {
3406
+ responseError = errorValue.value;
3407
+ } else {
3408
+ responseError = Object.assign(new Error(message), { stack, code, name });
3409
+ if (cause) {
3410
+ responseError.cause = Object.assign(new Error(cause.message), { name: cause.name });
3411
+ }
3412
+ }
3413
+ if (isErrorObject(responseError)) {
3414
+ try {
3415
+ if (outputSize !== UNDEFINED_VALUE) {
3416
+ responseError.outputSize = outputSize;
3417
+ }
3418
+ if (codecImportFailed) {
3419
+ responseError.codecImportFailed = true;
3420
+ }
3421
+ if (errorValue) {
3422
+ if (responseError.name !== name) {
3423
+ responseError.name = name;
3424
+ }
3425
+ if (responseError.code !== code) {
3426
+ responseError.code = code;
3427
+ }
3428
+ }
3429
+ } catch {
3430
+ // ignored
3277
3431
  }
3278
3432
  }
3433
+ return responseError;
3279
3434
  }
3280
3435
 
3281
3436
  /*
@@ -3552,10 +3707,13 @@ function decode(value, encoding, ignoreBOM) {
3552
3707
 
3553
3708
 
3554
3709
  const ERR_HTTP_STATUS = "HTTP error ";
3710
+ const MIN_SUCCESS_HTTP_STATUS = 200;
3711
+ const MAX_SUCCESS_HTTP_STATUS = 299;
3555
3712
  const ERR_HTTP_RANGE = "HTTP Range not supported";
3556
3713
  const ERR_HTTP_RESOURCE_CHANGED = "HTTP resource changed";
3557
3714
  const ERR_ITERATOR_COMPLETED_TOO_SOON = "Writer iterator completed too soon";
3558
3715
  const ERR_WRITER_NOT_INITIALIZED = "Writer not initialized";
3716
+ const ERR_WRITER_SIZE_NOT_WRITABLE = "Invalid writer (size must be writable)";
3559
3717
 
3560
3718
  const CONTENT_TYPE_TEXT_PLAIN = "text/plain";
3561
3719
  const HTTP_HEADER_CONTENT_LENGTH = "Content-Length";
@@ -3601,11 +3759,10 @@ class Reader extends Stream {
3601
3759
  const data = await readUint8Array(reader, offset + chunkOffset, dataSize);
3602
3760
  if (data.length) {
3603
3761
  controller.enqueue(data);
3762
+ chunkOffset += data.length;
3604
3763
  }
3605
- if ((chunkOffset + chunkSize >= size) || (!data.length && dataSize)) {
3764
+ if ((size !== UNDEFINED_VALUE && chunkOffset >= size) || (!data.length && dataSize)) {
3606
3765
  controller.close();
3607
- } else {
3608
- chunkOffset += chunkSize;
3609
3766
  }
3610
3767
  }
3611
3768
  });
@@ -3748,11 +3905,14 @@ class BlobReader extends Reader {
3748
3905
  const reader = this;
3749
3906
  const { sourceBlob, size } = reader;
3750
3907
  const { offset = 0, size: readSize = size - offset } = options || {};
3751
- if (!offset && readSize >= size) {
3752
- return toCompatibleReadable(sourceBlob.stream());
3753
- }
3754
- if (blobSliceReliable) {
3755
- return toCompatibleReadable(sourceBlob.slice(offset, offset + readSize).stream());
3908
+ // deno-lint-ignore valid-typeof
3909
+ if (typeof sourceBlob.stream == FUNCTION_TYPE) {
3910
+ if (!offset && readSize >= size) {
3911
+ return toCompatibleReadable(sourceBlob.stream());
3912
+ }
3913
+ if (blobSliceReliable) {
3914
+ return toCompatibleReadable(sourceBlob.slice(offset, offset + readSize).stream());
3915
+ }
3756
3916
  }
3757
3917
  return super.createReadable(options);
3758
3918
  }
@@ -4132,7 +4292,7 @@ async function getContentLength(httpReader, sendRequest, getRequestData) {
4132
4292
 
4133
4293
  async function sendFetchRequest(method, { fetch: fetchFunction = fetch, options, url }, headers) {
4134
4294
  const response = await fetchFunction(url, Object.assign({}, options, { method, headers }));
4135
- if (response.status < 400) {
4295
+ if (response.status >= MIN_SUCCESS_HTTP_STATUS && response.status <= MAX_SUCCESS_HTTP_STATUS) {
4136
4296
  return response;
4137
4297
  } else {
4138
4298
  throw response.status == 416 ? new Error(ERR_HTTP_RANGE) : new Error(ERR_HTTP_STATUS + (response.statusText || response.status));
@@ -4143,7 +4303,7 @@ function sendXMLHttpRequest(method, { url }, headers) {
4143
4303
  return new Promise((resolve, reject) => {
4144
4304
  const request = new XMLHttpRequest();
4145
4305
  request.addEventListener("load", () => {
4146
- if (request.status < 400) {
4306
+ if (request.status >= MIN_SUCCESS_HTTP_STATUS && request.status <= MAX_SUCCESS_HTTP_STATUS) {
4147
4307
  const headers = [];
4148
4308
  request.getAllResponseHeaders().trim().split(/[\r\n]+/).forEach(header => {
4149
4309
  const splitHeader = header.trim().split(/\s*:\s*/);
@@ -4447,8 +4607,10 @@ class GenericWriter {
4447
4607
  writable: toCompatibleWritable(writer)
4448
4608
  };
4449
4609
  }
4450
- if (writer.size === UNDEFINED_VALUE) {
4451
- writer.size = 0;
4610
+ try {
4611
+ writer.size = writer.size === UNDEFINED_VALUE ? 0 : writer.size;
4612
+ } catch {
4613
+ throw new Error(ERR_WRITER_SIZE_NOT_WRITABLE);
4452
4614
  }
4453
4615
  return writer;
4454
4616
  }
@@ -4496,6 +4658,45 @@ function createReadable(reader, options) {
4496
4658
  }
4497
4659
  }
4498
4660
 
4661
+ /*
4662
+ Copyright (c) 2026 Gildas Lormeau. All rights reserved.
4663
+
4664
+ Redistribution and use in source and binary forms, with or without
4665
+ modification, are permitted provided that the following conditions are met:
4666
+
4667
+ 1. Redistributions of source code must retain the above copyright notice,
4668
+ this list of conditions and the following disclaimer.
4669
+
4670
+ 2. Redistributions in binary form must reproduce the above copyright
4671
+ notice, this list of conditions and the following disclaimer in
4672
+ the documentation and/or other materials provided with the distribution.
4673
+
4674
+ 3. The names of the authors may not be used to endorse or promote products
4675
+ derived from this software without specific prior written permission.
4676
+
4677
+ THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
4678
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
4679
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
4680
+ INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
4681
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4682
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
4683
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
4684
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
4685
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
4686
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4687
+ */
4688
+
4689
+
4690
+ function addWarning(warnings, reason, filename) {
4691
+ if (!warnings.some(warning => warning.reason == reason)) {
4692
+ const warning = { reason };
4693
+ if (filename !== UNDEFINED_VALUE) {
4694
+ warning.filename = filename;
4695
+ }
4696
+ warnings.push(warning);
4697
+ }
4698
+ }
4699
+
4499
4700
  /*
4500
4701
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
4501
4702
 
@@ -4524,6 +4725,7 @@ function createReadable(reader, options) {
4524
4725
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4525
4726
  */
4526
4727
 
4728
+
4527
4729
  const PROPERTY_NAME_FILENAME = "filename";
4528
4730
  const PROPERTY_NAME_RAW_FILENAME = "rawFilename";
4529
4731
  const PROPERTY_NAME_COMMENT = "comment";
@@ -4648,6 +4850,38 @@ class Entry {
4648
4850
 
4649
4851
  }
4650
4852
 
4853
+ const INTERPRETED_EXTRA_FIELD_TYPES = new Set([
4854
+ EXTRAFIELD_TYPE_ZIP64,
4855
+ EXTRAFIELD_TYPE_AES,
4856
+ EXTRAFIELD_TYPE_NTFS,
4857
+ EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP,
4858
+ EXTRAFIELD_TYPE_UNICODE_PATH,
4859
+ EXTRAFIELD_TYPE_UNICODE_COMMENT,
4860
+ EXTRAFIELD_TYPE_USDZ,
4861
+ EXTRAFIELD_TYPE_INFOZIP,
4862
+ EXTRAFIELD_TYPE_UNIX,
4863
+ EXTRAFIELD_TYPE_UNIX_TYPE1,
4864
+ EXTRAFIELD_TYPE_PKWARE_UNIX
4865
+ ]);
4866
+
4867
+ function getUserExtraField(extraField) {
4868
+ if (extraField) {
4869
+ const userExtraField = new Map();
4870
+ extraField.forEach((field, type) => {
4871
+ if (!INTERPRETED_EXTRA_FIELD_TYPES.has(type)) {
4872
+ userExtraField.set(type, field.data);
4873
+ }
4874
+ });
4875
+ if (userExtraField.size) {
4876
+ return userExtraField;
4877
+ }
4878
+ }
4879
+ }
4880
+
4881
+ function getEncryptionOverhead(encrypted, zipCrypto, encryptionStrength) {
4882
+ return encrypted ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
4883
+ }
4884
+
4651
4885
  /*
4652
4886
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
4653
4887
 
@@ -4707,6 +4941,8 @@ const WARNING_PREPENDED_CENTRAL_DIRECTORY = "prepended central directory";
4707
4941
  const WARNING_TRAILING_CENTRAL_DIRECTORY_DATA = "trailing central directory data";
4708
4942
  const WARNING_DUPLICATE_FILENAME = "duplicate filename";
4709
4943
  const WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY = "mismatched zip64 end of central directory record";
4944
+ const WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY = "multiple end of central directory records";
4945
+ const WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME = "mismatched local file header (filename)";
4710
4946
  const WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG = "mismatched local file header (general purpose bit flag)";
4711
4947
  const WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD = "mismatched local file header (compression method)";
4712
4948
  const WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES = "mismatched local file header (crc32 or sizes)";
@@ -4777,7 +5013,7 @@ class ZipReader {
4777
5013
  }
4778
5014
  }
4779
5015
  if (rejectAmbiguousEndOfDirectory && endOfDirectoryReachingEndCount > 1) {
4780
- throwAmbiguousArchive("multiple end of central directory records");
5016
+ throwAmbiguousArchive(WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY);
4781
5017
  }
4782
5018
  const endOfDirectoryView = getDataView(endOfDirectoryInfo);
4783
5019
  let directoryDataLength = getUint32$1(endOfDirectoryView, 12);
@@ -5075,7 +5311,8 @@ class ZipReader {
5075
5311
  const writer = new TransformStream();
5076
5312
  const arrayBufferPromise = streamToBlob(writer.readable).then(blob => blob.arrayBuffer());
5077
5313
  arrayBufferPromise.catch(() => { });
5078
- await fileEntry.getData(writer, entry, zipReader.readRanges, options);
5314
+ await fileEntry.getData(writer, entry, zipReader.readRanges,
5315
+ Object.assign({}, options, { preventClose: false }));
5079
5316
  return arrayBufferPromise;
5080
5317
  };
5081
5318
  offset = endOffset;
@@ -5156,48 +5393,101 @@ class ZipReader {
5156
5393
  await reader.readable.cancel();
5157
5394
  }
5158
5395
  }
5396
+
5397
+ [SYMBOL_ASYNC_DISPOSE]() {
5398
+ return this.close();
5399
+ }
5159
5400
  }
5160
5401
 
5161
5402
  class ZipReaderStream {
5162
5403
 
5163
5404
  constructor(options = {}) {
5164
- const { readable, writable } = new TransformStream();
5165
- const gen = new ZipReader(readable, options).getEntriesGenerator();
5405
+ let sourceController;
5406
+ const { readable, writable } = new TransformStream({
5407
+ start(controller) {
5408
+ sourceController = controller;
5409
+ }
5410
+ });
5411
+ const zipReader = new ZipReader(readable, options);
5412
+ const gen = zipReader.getEntriesGenerator();
5413
+ const pendingEntries = new Set();
5166
5414
  this.readable = new ReadableStream({
5167
5415
  async pull(controller) {
5168
5416
  const { done, value } = await gen.next();
5169
5417
  if (done)
5170
5418
  return controller.close();
5419
+ const entryStream = createEntryStream(value, pendingEntries);
5171
5420
  const chunk = {
5172
5421
  ...value,
5173
- readable: (function () {
5174
- const { readable, writable } = new TransformStream();
5175
- if (value.getData) {
5176
- getData();
5177
- return readable;
5178
- }
5179
-
5180
- async function getData() {
5181
- try {
5182
- await value.getData(writable);
5183
- } catch (error) {
5184
- try {
5185
- await writable.abort(error);
5186
- } catch {
5187
- // ignored
5188
- }
5189
- }
5190
- }
5191
- })()
5422
+ readable: entryStream.readable
5192
5423
  };
5193
5424
  delete chunk.getData;
5425
+ Object.defineProperties(chunk, {
5426
+ localDirectory: {
5427
+ get: () => value.localDirectory,
5428
+ enumerable: true
5429
+ },
5430
+ warnings: {
5431
+ get: () => value.warnings,
5432
+ enumerable: true
5433
+ }
5434
+ });
5194
5435
  controller.enqueue(chunk);
5436
+ },
5437
+ async cancel(reason) {
5438
+ const entryStreams = Array.from(pendingEntries);
5439
+ pendingEntries.clear();
5440
+ sourceController.error(reason);
5441
+ await Promise.allSettled(entryStreams.map(entryStream => entryStream.cancel(reason)));
5442
+ await Promise.allSettled([gen.return(), zipReader.close()]);
5195
5443
  }
5196
5444
  });
5197
5445
  this.writable = writable;
5198
5446
  }
5199
5447
  }
5200
5448
 
5449
+ function createEntryStream(entry, pendingEntries) {
5450
+ const { readable, writable } = new TransformStream();
5451
+ let dataReader;
5452
+ const entryStream = {
5453
+ cancel: async reason => {
5454
+ pendingEntries.delete(entryStream);
5455
+ await (dataReader ? dataReader.cancel(reason) : readable.cancel(reason));
5456
+ }
5457
+ };
5458
+ entryStream.readable = new ReadableStream({
5459
+ async pull(controller) {
5460
+ if (!dataReader) {
5461
+ dataReader = readable.getReader();
5462
+ pendingEntries.add(entryStream);
5463
+ getData();
5464
+ }
5465
+ const { done, value } = await dataReader.read();
5466
+ if (done) {
5467
+ controller.close();
5468
+ } else {
5469
+ controller.enqueue(value);
5470
+ }
5471
+ },
5472
+ cancel: reason => entryStream.cancel(reason)
5473
+ }, { highWaterMark: 0 });
5474
+ return entryStream;
5475
+
5476
+ async function getData() {
5477
+ try {
5478
+ await entry.getData(writable, { preventClose: false });
5479
+ } catch (error) {
5480
+ try {
5481
+ await writable.abort(error);
5482
+ } catch {
5483
+ // ignored
5484
+ }
5485
+ } finally {
5486
+ pendingEntries.delete(entryStream);
5487
+ }
5488
+ }
5489
+ }
5490
+
5201
5491
  async function isZipFile(reader, options = {}) {
5202
5492
  reader = new GenericReader(reader);
5203
5493
  await initStream(reader);
@@ -5257,7 +5547,9 @@ class ZipEntry {
5257
5547
  const dataView = getDataView(dataArray);
5258
5548
  let password = getOptionValue$1(zipEntry, options, OPTION_PASSWORD);
5259
5549
  let rawPassword = getOptionValue$1(zipEntry, options, OPTION_RAW_PASSWORD);
5260
- const passThrough = getOptionValue$1(zipEntry, options, OPTION_PASS_THROUGH);
5550
+ const passThrough = checkPassThroughOption(getOptionValue$1(zipEntry, options, OPTION_PASS_THROUGH));
5551
+ const passThroughCompression = Boolean(passThrough);
5552
+ const passThroughEncryption = passThrough === true;
5261
5553
  checkPasswordOption(password, rawPassword);
5262
5554
  password = password && password.length && password;
5263
5555
  rawPassword = rawPassword && rawPassword.length && rawPassword;
@@ -5278,7 +5570,9 @@ class ZipEntry {
5278
5570
  const checkLocalDirectoryOption = getOptionValue$1(zipEntry, options, OPTION_CHECK_LOCAL_DIRECTORY);
5279
5571
  const entryStrictness = getStrictness(options, zipEntry.options);
5280
5572
  const checkLocalDirectory = getCheckLocalDirectory(checkLocalDirectoryOption, entryStrictness);
5281
- const checkLocalFilename = getCheckLocalFilename(checkLocalDirectoryOption, entryStrictness);
5573
+ const checkLocalFilenameOption = getOptionValue$1(zipEntry, options, OPTION_CHECK_LOCAL_FILENAME);
5574
+ const checkLocalFilename = getCheckLocalFilename(
5575
+ checkLocalFilenameOption === UNDEFINED_VALUE ? checkLocalDirectoryOption : checkLocalFilenameOption, entryStrictness);
5282
5576
  let rawLocalFilename = EMPTY_UINT8_ARRAY;
5283
5577
  if (checkLocalFilename && (filenameLength || extraFieldLength)) {
5284
5578
  const trailingDataArray = await readUint8Array(reader, localHeaderOffset + HEADER_SIZE, filenameLength + extraFieldLength);
@@ -5309,16 +5603,17 @@ class ZipEntry {
5309
5603
  if (gid !== UNDEFINED_VALUE && fileEntry.gid === UNDEFINED_VALUE) {
5310
5604
  fileEntry.gid = gid;
5311
5605
  }
5312
- const encrypted = zipEntry.encrypted && localDirectory.encrypted && !passThrough;
5606
+ const checkPasswordOnly = getOptionValue$1(zipEntry, options, OPTION_CHECK_PASSWORD_ONLY);
5607
+ const encrypted = zipEntry.encrypted && localDirectory.encrypted && (!passThroughEncryption || checkPasswordOnly);
5313
5608
  const zipCrypto = encrypted && !extraFieldAES;
5314
- if (!passThrough) {
5609
+ if (!passThroughEncryption) {
5315
5610
  fileEntry.zipCrypto = zipCrypto;
5316
5611
  }
5317
5612
  if (encrypted && (localDirectory.rawBitFlag & BITFLAG_STRONG_ENCRYPTION) == BITFLAG_STRONG_ENCRYPTION) {
5318
5613
  throw new Error(ERR_UNSUPPORTED_ENCRYPTION);
5319
5614
  }
5320
- const registeredCodec = passThrough ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
5321
- if (compressionMethod != COMPRESSION_METHOD_STORE && compressionMethod != COMPRESSION_METHOD_DEFLATE && compressionMethod != COMPRESSION_METHOD_DEFLATE_64 && !registeredCodec && !passThrough) {
5615
+ const registeredCodec = passThroughCompression ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
5616
+ if (compressionMethod != COMPRESSION_METHOD_STORE && compressionMethod != COMPRESSION_METHOD_DEFLATE && compressionMethod != COMPRESSION_METHOD_DEFLATE_64 && !registeredCodec && !passThroughCompression) {
5322
5617
  throw new Error(ERR_UNSUPPORTED_COMPRESSION);
5323
5618
  }
5324
5619
  if (encrypted) {
@@ -5334,15 +5629,17 @@ class ZipEntry {
5334
5629
  const size = compressedSize;
5335
5630
  const readable = toCompatibleReadable(reader.createReadable({ offset: dataOffset, size }));
5336
5631
  const signal = checkSignalOption(getOptionValue$1(zipEntry, options, OPTION_SIGNAL));
5337
- const checkPasswordOnly = getOptionValue$1(zipEntry, options, OPTION_CHECK_PASSWORD_ONLY);
5632
+ throwIfAborted(signal);
5338
5633
  let checkOverlappingEntry = getOptionValue$1(zipEntry, options, OPTION_CHECK_OVERLAPPING_ENTRY);
5339
5634
  const checkOverlappingEntryOnly = getOptionValue$1(zipEntry, options, OPTION_CHECK_OVERLAPPING_ENTRY_ONLY);
5340
5635
  if (checkOverlappingEntryOnly) {
5341
5636
  checkOverlappingEntry = true;
5342
5637
  }
5343
5638
  const { onstart, onprogress, onend } = options;
5344
- const compressed = compressionMethod != COMPRESSION_METHOD_STORE && !passThrough;
5345
- const outputSize = passThrough ? compressedSize : uncompressedSize;
5639
+ const compressed = compressionMethod != COMPRESSION_METHOD_STORE && !passThroughCompression;
5640
+ const outputSize = passThroughCompression ?
5641
+ compressedSize - getEncryptionOverhead(encrypted, zipCrypto, extraFieldAES && extraFieldAES.strength) :
5642
+ uncompressedSize;
5346
5643
  const deflate64 = compressionMethod == COMPRESSION_METHOD_DEFLATE_64;
5347
5644
  let useCompressionStream = getOptionValue$1(zipEntry, options, OPTION_USE_COMPRESSION_STREAM);
5348
5645
  if (deflate64) {
@@ -5351,7 +5648,7 @@ class ZipEntry {
5351
5648
  const checkCrc32Option = getOptionValue$1(zipEntry, options, OPTION_CHECK_CRC32);
5352
5649
  const checkCrc32 = (checkCrc32Option === UNDEFINED_VALUE ?
5353
5650
  getOptionValue$1(zipEntry, options, OPTION_CHECK_SIGNATURE) :
5354
- checkCrc32Option) && !passThrough &&
5651
+ checkCrc32Option) && !passThroughCompression &&
5355
5652
  (!encrypted || zipCrypto || (extraFieldAES && extraFieldAES.vendorVersion == VENDOR_VERSION_AE_1$1));
5356
5653
  const workerOptions = {
5357
5654
  options: {
@@ -5395,7 +5692,7 @@ class ZipEntry {
5395
5692
  readRanges
5396
5693
  });
5397
5694
  }
5398
- let writable, abortError;
5695
+ let writable, abortError, aborted;
5399
5696
  try {
5400
5697
  if (!checkOverlappingEntryOnly) {
5401
5698
  if (checkPasswordOnly) {
@@ -5405,24 +5702,28 @@ class ZipEntry {
5405
5702
  await initStream(writer, getDecodableOutputSize(outputSize, compressedSize, compressed));
5406
5703
  ({ writable } = writer);
5407
5704
  const { outputSize: writtenSize } = await runWorker({ readable, writable }, workerOptions);
5408
- writer.size += writtenSize;
5409
5705
  if (writtenSize != outputSize) {
5410
- throw new Error(ERR_INVALID_UNCOMPRESSED_SIZE);
5706
+ throw Object.assign(new Error(ERR_INVALID_UNCOMPRESSED_SIZE), { outputSize: writtenSize });
5411
5707
  }
5708
+ writer.size += writtenSize;
5412
5709
  }
5413
5710
  } catch (error) {
5414
- if (error.outputSize !== UNDEFINED_VALUE) {
5711
+ const { outputSize: failedOutputSize } = workerOptions;
5712
+ if (failedOutputSize !== UNDEFINED_VALUE) {
5713
+ writer.size += failedOutputSize;
5714
+ } else if (isErrorObject(error) && error.outputSize !== UNDEFINED_VALUE) {
5415
5715
  writer.size += error.outputSize;
5416
5716
  }
5417
- if (!checkPasswordOnly || error.message != ERR_ABORT_CHECK_PASSWORD) {
5717
+ if (!checkPasswordOnly || !isErrorObject(error) || error.message != ERR_ABORT_CHECK_PASSWORD) {
5418
5718
  abortError = error;
5719
+ aborted = true;
5419
5720
  throw error;
5420
5721
  }
5421
5722
  } finally {
5422
5723
  const preventClose = !ownsWritable(writer) && getOptionValue$1(zipEntry, options, OPTION_PREVENT_CLOSE);
5423
5724
  if (!preventClose && writable && !writable.locked) {
5424
5725
  const writableWriter = writable.getWriter();
5425
- if (abortError) {
5726
+ if (aborted) {
5426
5727
  try {
5427
5728
  await writableWriter.abort(abortError);
5428
5729
  } catch {
@@ -6074,7 +6375,7 @@ function validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, chec
6074
6375
  if (checkLocalFilename && !maskedLocalDirectory &&
6075
6376
  (rawLocalFilename.length != rawFilename.length ||
6076
6377
  rawLocalFilename.some((byteValue, indexByte) => byteValue != rawFilename[indexByte]))) {
6077
- reportAmbiguity(reject, warnings, "mismatched local file header (filename)");
6378
+ reportAmbiguity(reject, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME);
6078
6379
  }
6079
6380
  if ((localDirectory.rawBitFlag & BITFLAG_AMBIGUITY_MASK) != (zipEntry.rawBitFlag & BITFLAG_AMBIGUITY_MASK)) {
6080
6381
  reportAmbiguity(reject, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG);
@@ -6099,16 +6400,6 @@ function reportAmbiguity(reject, warnings, reason) {
6099
6400
  }
6100
6401
  }
6101
6402
 
6102
- function addWarning(warnings, reason, filename) {
6103
- if (!warnings.some(warning => warning.reason == reason)) {
6104
- const warning = { reason };
6105
- if (filename !== UNDEFINED_VALUE) {
6106
- warning.filename = filename;
6107
- }
6108
- warnings.push(warning);
6109
- }
6110
- }
6111
-
6112
6403
  function throwAmbiguousArchive(reason) {
6113
6404
  const error = new Error(ERR_AMBIGUOUS_ARCHIVE);
6114
6405
  error.reason = reason;
@@ -6188,7 +6479,9 @@ var zipReader = /*#__PURE__*/Object.freeze({
6188
6479
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG: WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG,
6189
6480
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD: WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD,
6190
6481
  WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES: WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES,
6482
+ WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME: WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME,
6191
6483
  WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY: WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY,
6484
+ WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY: WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY,
6192
6485
  WARNING_PREPENDED_CENTRAL_DIRECTORY: WARNING_PREPENDED_CENTRAL_DIRECTORY,
6193
6486
  WARNING_PREPENDED_DATA: WARNING_PREPENDED_DATA,
6194
6487
  WARNING_TRAILING_CENTRAL_DIRECTORY_DATA: WARNING_TRAILING_CENTRAL_DIRECTORY_DATA,
@@ -6240,7 +6533,8 @@ const ERR_INVALID_ENTRY_NAME = "File entry name exceeds 64KB";
6240
6533
  const ERR_INVALID_VERSION = "Version exceeds 65535";
6241
6534
  const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3";
6242
6535
  const ERR_UNSUPPORTED_ENCRYPTION_USDZ = "Encryption is not supported in USDZ files";
6243
- const ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = "Encryption is not supported when the 'passThrough' option is set";
6536
+ const ERR_UNSUPPORTED_SPLIT_USDZ = "Split zip files are not supported in USDZ files";
6537
+ const ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH = "Encryption is not supported when the 'passThrough' option is set to true (use 'compressed' instead)";
6244
6538
  const ERR_INVALID_EXTRAFIELD = "Invalid extra field (must be a Map)";
6245
6539
  const ERR_INVALID_EXTRAFIELD_TYPE = "Invalid extra field type (must be integer 0..65535)";
6246
6540
  const ERR_INVALID_EXTRAFIELD_DATA_TYPE = "Invalid extra field data (must be a Uint8Array)";
@@ -6252,8 +6546,10 @@ const MAX_NTFS_TIME = BigInt("0x7fffffffffffffff");
6252
6546
  const ERR_UNSUPPORTED_FORMAT = "Zip64 is not supported (set the 'zip64' option to 'true')";
6253
6547
  const ERR_UNDEFINED_UNCOMPRESSED_SIZE = "Undefined uncompressed size";
6254
6548
  const ERR_UNDEFINED_COMPRESSION_METHOD = "Undefined compression method";
6549
+ const ERR_UNDEFINED_CRC32 = "Undefined CRC32";
6255
6550
  const ERR_UNDETERMINED_SIZE = "Undetermined size";
6256
6551
  const ERR_UNDEFINED_READER = "Undefined reader";
6552
+ const ERR_INVALID_READER = "Invalid reader (must be a Reader instance, a ReadableStream instance, or an object with a 'readable' property)";
6257
6553
  const ERR_ZIP_NOT_EMPTY = "Zip file not empty";
6258
6554
  const ERR_INVALID_UID = "Invalid uid (must be integer 0..2^32-1)";
6259
6555
  const ERR_INVALID_GID = "Invalid gid (must be integer 0..2^32-1)";
@@ -6264,14 +6560,21 @@ const ERR_INVALID_MSDOS_ATTRIBUTES = "Invalid msdosAttributesRaw (must be intege
6264
6560
  const ERR_INVALID_MSDOS_DATA = "Invalid msdosAttributes (must be an object with boolean flags)";
6265
6561
  const ERR_INVALID_LEVEL = "Invalid level (must be integer 0..9)";
6266
6562
  const ERR_INVALID_SIGNATURE_DATA = "Signature data exceeds 64KB";
6563
+ const ERR_INVALID_ENTRY = "Invalid entry option (must be an entry returned by ZipReader#getEntries())";
6564
+ const ERR_ZIP_CRYPTO_LAST_MOD_DATE = "The last modification date of an entry encrypted with ZipCrypto cannot be changed when passThrough is set";
6565
+ const WARNING_COMPRESSION_UNAVAILABLE = "compression unavailable";
6566
+ const WARNING_CLAMPED_LAST_MODIFICATION_DATE = "clamped last modification date";
6267
6567
 
6268
6568
  const EXTRAFIELD_DATA_AES = new Uint8Array([0x07, 0x00, 0x02, 0x00, 0x41, 0x45, 0x03, 0x00, 0x00]);
6269
6569
  const EXTRAFIELD_OFFSET_AES_VENDOR_VERSION = 4;
6270
6570
  const EXTRAFIELD_OFFSET_AES_COMPRESSION_METHOD = 9;
6271
6571
  const EXTRAFIELD_USDZ_MAX_LENGTH = 67;
6572
+ const MIN_PRINTABLE_ASCII_CHARACTER_CODE = 0x20;
6573
+ const MAX_PRINTABLE_ASCII_CHARACTER_CODE = 0x7e;
6272
6574
  const VENDOR_VERSION_AE_1 = 1;
6273
6575
  const INFOZIP_EXTRA_FIELD_TYPE = "infozip";
6274
6576
  const UNIX_EXTRA_FIELD_TYPE = "unix";
6577
+ const LEVEL_BY_BITFLAG_LEVEL = [8, 9, 5, 3];
6275
6578
  const MAX_LEVEL = 9;
6276
6579
 
6277
6580
  let workers = 0;
@@ -6285,6 +6588,9 @@ class ZipWriter {
6285
6588
  const addSplitZipSignature =
6286
6589
  availableSize > 0 && availableSize !== INFINITY_VALUE &&
6287
6590
  maxSize > 0 && maxSize !== INFINITY_VALUE;
6591
+ if (addSplitZipSignature && options[OPTION_USDZ]) {
6592
+ throw new Error(ERR_UNSUPPORTED_SPLIT_USDZ);
6593
+ }
6288
6594
  Object.assign(this, {
6289
6595
  writer,
6290
6596
  addSplitZipSignature,
@@ -6295,8 +6601,11 @@ class ZipWriter {
6295
6601
  initialOffset: options[OPTION_OFFSET] === UNDEFINED_VALUE ? 0 : options[OPTION_OFFSET] - (writer.size || writer.writable.size || 0),
6296
6602
  pendingAddFileCalls: new Set(),
6297
6603
  pendingErrors: [],
6604
+ warnings: [],
6298
6605
  bufferedWrites: 0,
6299
- lastFileEntry: UNDEFINED_VALUE
6606
+ directWrites: 0,
6607
+ lastFileEntry: UNDEFINED_VALUE,
6608
+ archiveClosed: false
6300
6609
  });
6301
6610
  }
6302
6611
 
@@ -6399,6 +6708,7 @@ class ZipWriter {
6399
6708
  }
6400
6709
  const { offset, diskNumberStart } = entryPositions.get(entry);
6401
6710
  Object.assign(entry, {
6711
+ zip64Enabled: true,
6402
6712
  zip64UncompressedSize,
6403
6713
  zip64CompressedSize,
6404
6714
  offset,
@@ -6460,6 +6770,9 @@ class ZipWriter {
6460
6770
  const zipWriter = this;
6461
6771
  const { pendingAddFileCalls, writer } = this;
6462
6772
  const { writable } = writer;
6773
+ if (zipWriter.archiveClosed) {
6774
+ return getWriterData(writer);
6775
+ }
6463
6776
  if (!(comment instanceof Uint8Array)) {
6464
6777
  throw new Error(ERR_INVALID_COMMENT_TYPE);
6465
6778
  }
@@ -6470,7 +6783,7 @@ class ZipWriter {
6470
6783
  await Promise.allSettled(Array.from(pendingAddFileCalls));
6471
6784
  }
6472
6785
  await Promise.allSettled(zipWriter.pendingErrors.map(watcher => watcher.recorded));
6473
- const unobservedWatchers = zipWriter.pendingErrors.filter(watcher => watcher.error && !watcher.observed);
6786
+ const unobservedWatchers = zipWriter.pendingErrors.filter(watcher => watcher.failed && !watcher.observed);
6474
6787
  if (unobservedWatchers.length) {
6475
6788
  const unobservedErrors = unobservedWatchers.map(watcher => watcher.error);
6476
6789
  unobservedWatchers.forEach(watcher => watcher.observed = true);
@@ -6483,11 +6796,16 @@ class ZipWriter {
6483
6796
  throw error;
6484
6797
  }
6485
6798
  await closeFile(zipWriter, comment, options);
6799
+ zipWriter.archiveClosed = true;
6486
6800
  const preventClose = !ownsWritable(writer) && getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
6487
6801
  if (!preventClose) {
6488
6802
  await writable.getWriter().close();
6489
6803
  }
6490
- return writer.getData ? writer.getData() : writable;
6804
+ return getWriterData(writer);
6805
+ }
6806
+
6807
+ [SYMBOL_ASYNC_DISPOSE]() {
6808
+ return this.close();
6491
6809
  }
6492
6810
  }
6493
6811
 
@@ -6566,11 +6884,16 @@ class WatchedPromise extends Promise {
6566
6884
  }
6567
6885
  }
6568
6886
 
6887
+ function getWriterData(writer) {
6888
+ return writer.getData ? writer.getData() : writer.writable;
6889
+ }
6890
+
6569
6891
  function watchPromiseError(zipWriter, promise) {
6570
6892
  const watchedPromise = new WatchedPromise((resolve, reject) => Promise.prototype.then.call(promise, resolve, reject));
6571
6893
  const watcher = {};
6572
6894
  watchedPromise.watcher = watcher;
6573
- watcher.recorded = Promise.prototype.then.call(watchedPromise, UNDEFINED_VALUE, error => watcher.error = error);
6895
+ watcher.recorded = Promise.prototype.then.call(watchedPromise, UNDEFINED_VALUE,
6896
+ error => Object.assign(watcher, { failed: true, error }));
6574
6897
  zipWriter.pendingErrors.push(watcher);
6575
6898
  return watchedPromise;
6576
6899
  }
@@ -6584,6 +6907,14 @@ async function prependZipEntries(zipWriter, reader) {
6584
6907
 
6585
6908
  async function addFileEntry(zipWriter, name, reader, options) {
6586
6909
  options = Object.assign({}, options);
6910
+ const entry = options[OPTION_ENTRY];
6911
+ if (entry !== UNDEFINED_VALUE) {
6912
+ const { entryOptions, passThroughOptions } = getSourceEntryOptions(entry,
6913
+ checkPassThroughOption(getOptionValue(zipWriter, options, OPTION_PASS_THROUGH)),
6914
+ getOptionValue(zipWriter, options, PROPERTY_NAME_LAST_MODIFICATION_DATE));
6915
+ delete options[OPTION_ENTRY];
6916
+ options = Object.assign(entryOptions, passThroughOptions, options);
6917
+ }
6587
6918
  if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
6588
6919
  name += DIRECTORY_SIGNATURE;
6589
6920
  }
@@ -6648,21 +6979,33 @@ async function addFile(zipWriter, name, reader, options) {
6648
6979
  try {
6649
6980
  const { resolvedOptions } = metadataInfo;
6650
6981
  if (resolvedOptions.level != 0 && resolvedOptions.compressionMethod === UNDEFINED_VALUE &&
6651
- !resolvedOptions.passThrough && !(await supportsDeflate(getConfiguration()))) {
6982
+ !resolvedOptions.passThroughCompression && !(await supportsDeflate(getConfiguration()))) {
6652
6983
  resolvedOptions.level = 0;
6984
+ addWarning(zipWriter.warnings, WARNING_COMPRESSION_UNAVAILABLE, name);
6653
6985
  }
6654
6986
  const sizesInfo = await resolveSizes(zipWriter, reader, metadataInfo, options);
6655
6987
  ({ reader } = sizesInfo);
6656
6988
  const diskOffset = getDiskOffset(zipWriter.writer);
6657
6989
  const diskNumber = getDiskNumber(zipWriter.writer);
6990
+ let crc32 = options.crc32 === UNDEFINED_VALUE ? options[PROPERTY_NAME_SIGNATURE] : options.crc32;
6991
+ const storesAE2 = sizesInfo.resolvedOptions.encrypted && !resolvedOptions.zipCrypto;
6992
+ if (resolvedOptions.passThroughCompression && !resolvedOptions.passThroughEncryption && storesAE2) {
6993
+ crc32 = UNDEFINED_VALUE;
6994
+ }
6995
+ if (resolvedOptions.passThroughCompression && reader && !storesAE2 && crc32 === UNDEFINED_VALUE) {
6996
+ throw new Error(ERR_UNDEFINED_CRC32);
6997
+ }
6658
6998
  options = Object.assign({}, options, attributesInfo.resolvedOptions, metadataInfo.resolvedOptions, sizesInfo.resolvedOptions, {
6659
6999
  signature: options[PROPERTY_NAME_SIGNATURE],
6660
- crc32: options.crc32 === UNDEFINED_VALUE ? options[PROPERTY_NAME_SIGNATURE] : options.crc32,
7000
+ crc32,
6661
7001
  offset: zipWriter.offset - diskOffset,
6662
7002
  diskNumberStart: diskNumber,
6663
7003
  [OPTION_USDZ]: zipWriter.options[OPTION_USDZ]
6664
7004
  });
6665
7005
  const headerInfo = getHeaderInfo(options);
7006
+ if (headerInfo.lastModDateClamped) {
7007
+ addWarning(zipWriter.warnings, WARNING_CLAMPED_LAST_MODIFICATION_DATE, name);
7008
+ }
6666
7009
  const dataDescriptorInfo = getDataDescriptorInfo(options);
6667
7010
  const metadataSize = getLength(headerInfo.localHeaderArray, dataDescriptorInfo.dataDescriptorArray);
6668
7011
  fileEntry = await getFileEntry(zipWriter, name, reader, {
@@ -6689,6 +7032,95 @@ async function addFile(zipWriter, name, reader, options) {
6689
7032
  return new Entry(fileEntry);
6690
7033
  }
6691
7034
 
7035
+ function getSourceEntryOptions(entry, passThrough, lastModDateOverride) {
7036
+ if (entry === null || typeof entry != OBJECT_TYPE || Array.isArray(entry)) {
7037
+ throw new Error(ERR_INVALID_ENTRY);
7038
+ }
7039
+ const {
7040
+ externalFileAttributes,
7041
+ versionMadeBy,
7042
+ comment,
7043
+ lastModDate,
7044
+ rawLastModDate,
7045
+ creationDate,
7046
+ lastAccessDate,
7047
+ uncompressedSize,
7048
+ encrypted,
7049
+ zipCrypto,
7050
+ crc32,
7051
+ compressionMethod,
7052
+ extraFieldAES,
7053
+ extraFieldUnix,
7054
+ internalFileAttributes,
7055
+ extraField,
7056
+ bitFlag,
7057
+ directory,
7058
+ uid,
7059
+ gid
7060
+ } = entry;
7061
+ const entryOptions = {
7062
+ externalFileAttributes,
7063
+ versionMadeBy,
7064
+ comment,
7065
+ lastModDate,
7066
+ creationDate,
7067
+ lastAccessDate,
7068
+ internalFileAttributes,
7069
+ directory
7070
+ };
7071
+ if (bitFlag && bitFlag.languageEncodingFlag) {
7072
+ entryOptions[OPTION_USE_UNICODE_FILE_NAMES] = true;
7073
+ }
7074
+ const userExtraField = getUserExtraField(extraField);
7075
+ if (userExtraField) {
7076
+ entryOptions[PROPERTY_NAME_EXTRA_FIELD] = userExtraField;
7077
+ }
7078
+ if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
7079
+ Object.assign(entryOptions, {
7080
+ uid,
7081
+ gid,
7082
+ unixExtraFieldType: extraFieldUnix ? UNIX_EXTRA_FIELD_TYPE : INFOZIP_EXTRA_FIELD_TYPE
7083
+ });
7084
+ }
7085
+ const passThroughOptions = {};
7086
+ if (passThrough && !directory) {
7087
+ Object.assign(passThroughOptions, {
7088
+ uncompressedSize,
7089
+ crc32,
7090
+ compressionMethod
7091
+ });
7092
+ if (passThrough !== PASS_THROUGH_COMPRESSED) {
7093
+ Object.assign(passThroughOptions, {
7094
+ encrypted,
7095
+ zipCrypto,
7096
+ encryptionStrength: extraFieldAES ? extraFieldAES.strength : UNDEFINED_VALUE
7097
+ });
7098
+ }
7099
+ if (bitFlag) {
7100
+ passThroughOptions.dataDescriptor = bitFlag.dataDescriptor;
7101
+ passThroughOptions[OPTION_LEVEL] = LEVEL_BY_BITFLAG_LEVEL[bitFlag.level];
7102
+ }
7103
+ if (lastModDateOverride === UNDEFINED_VALUE) {
7104
+ passThroughOptions.rawLastModDate = rawLastModDate;
7105
+ } else if (passThrough !== PASS_THROUGH_COMPRESSED && zipCrypto && (!bitFlag || bitFlag.dataDescriptor) &&
7106
+ lastModDateOverride instanceof Date &&
7107
+ getDosTimeHighByte(lastModDateOverride) != ((rawLastModDate >>> 8) & MAX_8_BITS)) {
7108
+ throw new Error(ERR_ZIP_CRYPTO_LAST_MOD_DATE);
7109
+ }
7110
+ }
7111
+ return { entryOptions, passThroughOptions };
7112
+ }
7113
+
7114
+ function getDosTimeHighByte(lastModDate) {
7115
+ let dosLastModDate = new Date(Math.ceil(Math.floor(lastModDate.getTime() / 1000) / 2) * 2000);
7116
+ if (dosLastModDate < MIN_DATE) {
7117
+ dosLastModDate = MIN_DATE;
7118
+ } else if (dosLastModDate > MAX_DATE) {
7119
+ dosLastModDate = MAX_DATE;
7120
+ }
7121
+ return ((dosLastModDate.getHours() << 3) | (dosLastModDate.getMinutes() >> 3)) & MAX_8_BITS;
7122
+ }
7123
+
6692
7124
  function resolveAttributes(zipWriter, name, options) {
6693
7125
  let msDosCompatible = getOptionValue(zipWriter, options, PROPERTY_NAME_MS_DOS_COMPATIBLE);
6694
7126
  let versionMadeBy = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION_MADE_BY, msDosCompatible ? VERSION_MADE_BY_MSDOS : VERSION_MADE_BY_UNIX);
@@ -6842,7 +7274,9 @@ function resolveMetadata(zipWriter, name, options) {
6842
7274
  const lastAccessDate = getDateOptionValue(zipWriter, options, PROPERTY_NAME_LAST_ACCESS_DATE);
6843
7275
  const creationDate = getDateOptionValue(zipWriter, options, PROPERTY_NAME_CREATION_DATE);
6844
7276
  const internalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, 0);
6845
- const passThrough = getOptionValue(zipWriter, options, OPTION_PASS_THROUGH);
7277
+ const passThrough = checkPassThroughOption(getOptionValue(zipWriter, options, OPTION_PASS_THROUGH));
7278
+ const passThroughCompression = Boolean(passThrough);
7279
+ const passThroughEncryption = passThrough === true;
6846
7280
  const password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
6847
7281
  const rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
6848
7282
  checkPasswordOption(password, rawPassword);
@@ -6857,10 +7291,12 @@ function resolveMetadata(zipWriter, name, options) {
6857
7291
  const createTempStream = getFunctionOptionValue(zipWriter, options, OPTION_CREATE_TEMP_STREAM);
6858
7292
  const dataDescriptorSignature = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR_SIGNATURE, true);
6859
7293
  const signal = checkSignalOption(getOptionValue(zipWriter, options, OPTION_SIGNAL));
6860
- const useUnicodeFileNames = getOptionValue(zipWriter, options, OPTION_USE_UNICODE_FILE_NAMES, true);
7294
+ throwIfAborted(signal);
7295
+ const useUnicodeFileNames = getOptionValue(zipWriter, options, OPTION_USE_UNICODE_FILE_NAMES,
7296
+ !isPrintableASCIIText(rawFilename) || !isPrintableASCIIText(rawComment));
6861
7297
  const compressionMethod = getOptionValue(zipWriter, options, PROPERTY_NAME_COMPRESSION_METHOD);
6862
- const registeredCodec = passThrough || compressionMethod === UNDEFINED_VALUE ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
6863
- if (!passThrough && compressionMethod !== UNDEFINED_VALUE &&
7298
+ const registeredCodec = passThroughCompression || compressionMethod === UNDEFINED_VALUE ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
7299
+ if (!passThroughCompression && compressionMethod !== UNDEFINED_VALUE &&
6864
7300
  compressionMethod !== COMPRESSION_METHOD_STORE && compressionMethod !== COMPRESSION_METHOD_DEFLATE && !registeredCodec) {
6865
7301
  throw new Error(ERR_UNSUPPORTED_COMPRESSION);
6866
7302
  }
@@ -6874,15 +7310,15 @@ function resolveMetadata(zipWriter, name, options) {
6874
7310
  level = 0;
6875
7311
  }
6876
7312
  }
6877
- if (passThrough) {
6878
- level = UNDEFINED_VALUE;
7313
+ if (passThroughCompression) {
7314
+ level = toNumber(options[OPTION_LEVEL]);
6879
7315
  }
6880
7316
  let useCompressionStream = getOptionValue(zipWriter, options, OPTION_USE_COMPRESSION_STREAM);
6881
7317
  let dataDescriptor = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR);
6882
7318
  if (bufferedWrite && dataDescriptor === UNDEFINED_VALUE) {
6883
7319
  dataDescriptor = false;
6884
7320
  }
6885
- if (dataDescriptor === UNDEFINED_VALUE || (zipCrypto && !passThrough)) {
7321
+ if (dataDescriptor === UNDEFINED_VALUE || (zipCrypto && !passThroughEncryption)) {
6886
7322
  dataDescriptor = true;
6887
7323
  }
6888
7324
  if (level !== UNDEFINED_VALUE && level != 6) {
@@ -6906,7 +7342,8 @@ function resolveMetadata(zipWriter, name, options) {
6906
7342
  lastAccessDate,
6907
7343
  creationDate,
6908
7344
  internalFileAttributes,
6909
- passThrough,
7345
+ passThroughCompression,
7346
+ passThroughEncryption,
6910
7347
  password,
6911
7348
  rawPassword,
6912
7349
  encryptionStrength,
@@ -6967,24 +7404,28 @@ function serializeExtraField(extraField) {
6967
7404
  }
6968
7405
 
6969
7406
  async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, options) {
6970
- if (metadata.passThrough && !reader && !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY)) {
7407
+ if (metadata.passThroughCompression && !reader && !getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY)) {
6971
7408
  throw new Error(ERR_UNDEFINED_READER);
6972
7409
  }
6973
7410
  let contentSize;
6974
7411
  if (reader) {
6975
7412
  reader = new GenericReader(reader);
6976
7413
  await initStream(reader);
7414
+ if (!reader.readable && !reader.readUint8Array) {
7415
+ throw new Error(ERR_INVALID_READER);
7416
+ }
6977
7417
  ({ size: contentSize } = reader);
6978
7418
  }
6979
7419
  return Object.assign({ reader }, resolveEntrySizes(zipWriter, Boolean(reader), contentSize, metadata, options));
6980
7420
  }
6981
7421
 
6982
7422
  function resolveEntrySizes(zipWriter, hasContent, contentSize, metadata, options) {
6983
- const { passThrough, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
7423
+ const { passThroughCompression, passThroughEncryption, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
6984
7424
  let { dataDescriptor, zip64, level, compressionMethod } = metadata;
6985
7425
  let maximumCompressedSize = 0;
6986
7426
  let uncompressedSize = 0;
6987
- if (passThrough && hasContent) {
7427
+ let unknownSize = false;
7428
+ if (passThroughCompression && hasContent) {
6988
7429
  uncompressedSize = options[PROPERTY_NAME_UNCOMPRESSED_SIZE];
6989
7430
  if (uncompressedSize === UNDEFINED_VALUE) {
6990
7431
  throw new Error(ERR_UNDEFINED_UNCOMPRESSED_SIZE);
@@ -6995,22 +7436,22 @@ function resolveEntrySizes(zipWriter, hasContent, contentSize, metadata, options
6995
7436
  }
6996
7437
  const zip64Enabled = zip64 === true;
6997
7438
  const encrypted = getOptionValue(zipWriter, options, PROPERTY_NAME_ENCRYPTED);
6998
- if (hasContent && passThrough && !encrypted && getLength(password, rawPassword)) {
7439
+ if (hasContent && passThroughEncryption && !encrypted && getLength(password, rawPassword)) {
6999
7440
  throw new Error(ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH);
7000
7441
  }
7001
- const encryptedEntry = hasContent && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
7442
+ const encryptedEntry = hasContent && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThroughEncryption && encrypted));
7002
7443
  if (!hasContent) {
7003
7444
  level = 0;
7004
7445
  compressionMethod = COMPRESSION_METHOD_STORE;
7005
7446
  }
7006
- const encryptionOverhead = encryptedEntry ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
7447
+ const encryptionOverhead = getEncryptionOverhead(encryptedEntry, zipCrypto, encryptionStrength);
7007
7448
  if (hasContent) {
7008
- if (!passThrough) {
7449
+ if (!passThroughCompression) {
7009
7450
  if (contentSize === UNDEFINED_VALUE) {
7010
7451
  dataDescriptor = true;
7011
7452
  if (zip64 || zip64 === UNDEFINED_VALUE) {
7012
- zip64 = true;
7013
- uncompressedSize = maximumCompressedSize = MAX_32_BITS + 1;
7453
+ zip64 = unknownSize = true;
7454
+ maximumCompressedSize = MAX_32_BITS + 1;
7014
7455
  }
7015
7456
  } else {
7016
7457
  options.uncompressedSize = uncompressedSize = contentSize;
@@ -7018,14 +7459,16 @@ function resolveEntrySizes(zipWriter, hasContent, contentSize, metadata, options
7018
7459
  }
7019
7460
  } else {
7020
7461
  options.uncompressedSize = uncompressedSize;
7021
- maximumCompressedSize = contentSize === UNDEFINED_VALUE ? getMaximumCompressedSize(uncompressedSize) + encryptionOverhead : contentSize;
7462
+ maximumCompressedSize = contentSize === UNDEFINED_VALUE ?
7463
+ getMaximumCompressedSize(uncompressedSize) + encryptionOverhead :
7464
+ contentSize + (passThroughEncryption ? 0 : encryptionOverhead);
7022
7465
  }
7023
7466
  }
7024
- const emptyEntry = !encryptedEntry && (!hasContent || (contentSize === 0 && !passThrough)) && !isCompressed(compressionMethod, level);
7467
+ const emptyEntry = !encryptedEntry && (!hasContent || (contentSize === 0 && !passThroughCompression)) && !isCompressed(compressionMethod, level);
7025
7468
  if (emptyEntry && !zipCrypto && getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR) === UNDEFINED_VALUE) {
7026
7469
  dataDescriptor = false;
7027
7470
  }
7028
- const zip64UncompressedSize = zip64Enabled || uncompressedSize >= MAX_32_BITS;
7471
+ const zip64UncompressedSize = zip64Enabled || unknownSize || uncompressedSize >= MAX_32_BITS;
7029
7472
  const zip64CompressedSize = zip64Enabled || maximumCompressedSize >= MAX_32_BITS;
7030
7473
  if (zip64UncompressedSize || zip64CompressedSize) {
7031
7474
  if (zip64 === false) {
@@ -7041,6 +7484,8 @@ function resolveEntrySizes(zipWriter, hasContent, contentSize, metadata, options
7041
7484
  dataDescriptor,
7042
7485
  emptyEntry,
7043
7486
  zip64,
7487
+ zip64Enabled,
7488
+ unknownSize,
7044
7489
  zip64UncompressedSize,
7045
7490
  zip64CompressedSize,
7046
7491
  uncompressedSize,
@@ -7071,6 +7516,7 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
7071
7516
  const usdz = zipWriter.options[OPTION_USDZ];
7072
7517
  let fileEntry = pendingFileEntry;
7073
7518
  let bufferedWrite;
7519
+ let directWrite;
7074
7520
  let releaseLockWriter;
7075
7521
  let writingBufferedEntryData;
7076
7522
  let writingEntryData;
@@ -7080,7 +7526,7 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
7080
7526
  const lockPreviousFileEntry = keepOrder && previousFileEntry ? previousFileEntry.lockFileEntry : UNDEFINED_VALUE;
7081
7527
  fileEntries.set(name, fileEntry);
7082
7528
  try {
7083
- if (options.bufferedWrite || !keepOrder || zipWriter.writerLocked || zipWriter.bufferedWrites || (!dataDescriptor && !emptyEntry)) {
7529
+ if (options.bufferedWrite || !keepOrder || zipWriter.writerLocked || zipWriter.bufferedWrites || zipWriter.directWrites || (!dataDescriptor && !emptyEntry)) {
7084
7530
  bufferedWrite = true;
7085
7531
  zipWriter.bufferedWrites++;
7086
7532
  if (options.createTempStream) {
@@ -7091,6 +7537,8 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
7091
7537
  fileWriter.size = 0;
7092
7538
  await initStream(writer);
7093
7539
  } else {
7540
+ directWrite = true;
7541
+ zipWriter.directWrites++;
7094
7542
  fileWriter = writer;
7095
7543
  await lockPreviousFileEntry;
7096
7544
  await requestLockWriter();
@@ -7169,6 +7617,9 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
7169
7617
  if (bufferedWrite) {
7170
7618
  zipWriter.bufferedWrites--;
7171
7619
  }
7620
+ if (directWrite) {
7621
+ zipWriter.directWrites--;
7622
+ }
7172
7623
  if (releaseLockFileEntry) {
7173
7624
  releaseLockFileEntry(lockPreviousFileEntry);
7174
7625
  }
@@ -7220,6 +7671,7 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7220
7671
  localExtraFieldZip64Length,
7221
7672
  rawExtraFieldExtendedTimestamp,
7222
7673
  extraFieldExtendedTimestampFlag,
7674
+ extraFieldExtendedTimestampTime,
7223
7675
  rawExtraFieldNTFS,
7224
7676
  rawExtraFieldUnix,
7225
7677
  rawExtraFieldAES,
@@ -7232,7 +7684,9 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7232
7684
  password,
7233
7685
  rawPassword,
7234
7686
  level,
7687
+ useUnicodeFileNames,
7235
7688
  zip64,
7689
+ zip64Enabled,
7236
7690
  zip64UncompressedSize,
7237
7691
  zip64CompressedSize,
7238
7692
  zipCrypto,
@@ -7265,7 +7719,8 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7265
7719
  msdosAttributesRaw,
7266
7720
  msdosAttributes,
7267
7721
  useCompressionStream,
7268
- passThrough,
7722
+ passThroughCompression,
7723
+ passThroughEncryption,
7269
7724
  format,
7270
7725
  codecURI
7271
7726
  } = options;
@@ -7273,11 +7728,12 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7273
7728
  lockFileEntry,
7274
7729
  versionMadeBy,
7275
7730
  zip64,
7731
+ zip64Enabled,
7276
7732
  directory: Boolean(directory),
7277
7733
  executable: Boolean(executable),
7278
- filenameUTF8: true,
7734
+ filenameUTF8: Boolean(useUnicodeFileNames),
7279
7735
  rawFilename,
7280
- commentUTF8: true,
7736
+ commentUTF8: Boolean(useUnicodeFileNames),
7281
7737
  rawComment,
7282
7738
  rawExtraFieldZip64,
7283
7739
  localExtraFieldZip64Length,
@@ -7308,13 +7764,13 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7308
7764
  uncompressedSize
7309
7765
  } = options;
7310
7766
  let compressedSize = 0;
7311
- if (!passThrough) {
7767
+ if (!passThroughCompression) {
7312
7768
  uncompressedSize = 0;
7313
7769
  }
7314
7770
  const { writable } = writer;
7315
7771
  if (reader) {
7316
- const readable = toCompatibleReadable(createReadable(reader));
7317
7772
  const size = reader.size;
7773
+ const readable = toCompatibleReadable(createReadable(reader, { size }));
7318
7774
  const workerOptions = {
7319
7775
  options: {
7320
7776
  codecType: CODEC_DEFLATE,
@@ -7325,9 +7781,9 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7325
7781
  encryptionStrength,
7326
7782
  zipCrypto: encrypted && zipCrypto,
7327
7783
  passwordVerification: encrypted && zipCrypto && (rawLastModDate >> 8) & MAX_8_BITS,
7328
- computeCrc32: !passThrough,
7329
- compressed: compressed && !passThrough,
7330
- encrypted: encrypted && !passThrough,
7784
+ computeCrc32: !passThroughCompression,
7785
+ compressed: compressed && !passThroughCompression,
7786
+ encrypted: encrypted && !passThroughEncryption,
7331
7787
  useWebWorkers,
7332
7788
  useCompressionStream,
7333
7789
  transferStreams,
@@ -7342,7 +7798,7 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7342
7798
  const result = await runWorker({ readable, writable }, workerOptions);
7343
7799
  compressedSize = result.outputSize;
7344
7800
  writer.size += compressedSize;
7345
- if (!passThrough) {
7801
+ if (!passThroughCompression) {
7346
7802
  uncompressedSize = result.inputSize;
7347
7803
  if (!encrypted || zipCrypto) {
7348
7804
  crc32 = result.crc32;
@@ -7353,7 +7809,10 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7353
7809
  throw new Error(ERR_UNSUPPORTED_FORMAT);
7354
7810
  }
7355
7811
  } catch (error) {
7356
- if (error.outputSize !== UNDEFINED_VALUE) {
7812
+ const { outputSize: failedOutputSize } = workerOptions;
7813
+ if (failedOutputSize !== UNDEFINED_VALUE) {
7814
+ writer.size += failedOutputSize;
7815
+ } else if (isErrorObject(error) && error.outputSize !== UNDEFINED_VALUE) {
7357
7816
  writer.size += error.outputSize;
7358
7817
  }
7359
7818
  throw error;
@@ -7385,8 +7844,9 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7385
7844
  headerArray,
7386
7845
  headerView,
7387
7846
  signature: crc32,
7388
- crc32: encrypted && !zipCrypto && !passThrough ? UNDEFINED_VALUE : crc32,
7847
+ crc32: encrypted && !zipCrypto && !passThroughCompression ? UNDEFINED_VALUE : crc32,
7389
7848
  extraFieldExtendedTimestampFlag,
7849
+ extraFieldExtendedTimestampTime,
7390
7850
  zip64UncompressedSize,
7391
7851
  zip64CompressedSize
7392
7852
  });
@@ -7411,18 +7871,19 @@ function getHeaderInfo(options) {
7411
7871
  encryptionStrength,
7412
7872
  extendedTimestamp,
7413
7873
  ntfsTimestamp,
7414
- passThrough,
7874
+ passThroughCompression,
7415
7875
  encrypted,
7416
7876
  zip64UncompressedSize,
7417
7877
  zip64CompressedSize,
7418
7878
  uncompressedSize,
7879
+ unknownSize,
7419
7880
  crc32
7420
7881
  } = options;
7421
7882
  let { version, compressionMethod } = options;
7422
7883
  const compressed = !directory && isCompressed(compressionMethod, level);
7423
7884
  let rawLocalExtraFieldZip64;
7424
- const uncompressedFile = passThrough || !compressed;
7425
- const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || !dataDescriptor || ((!zip64UncompressedSize && !zip64CompressedSize) || uncompressedFile));
7885
+ const uncompressedFile = passThroughCompression || !compressed;
7886
+ const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || !dataDescriptor || ((!zip64UncompressedSize && !zip64CompressedSize) || (uncompressedFile && !unknownSize)));
7426
7887
  const writeLocalExtraFieldZip64 = zip64ExtraFieldComplete || (zip64 && dataDescriptor && (zip64UncompressedSize || zip64CompressedSize));
7427
7888
  if (zip64 && (zip64UncompressedSize || zip64CompressedSize)) {
7428
7889
  const length = 4 + 16;
@@ -7433,8 +7894,8 @@ function getHeaderInfo(options) {
7433
7894
  if (zip64ExtraFieldComplete) {
7434
7895
  extraFieldZip64.writeUint64(uncompressedSize);
7435
7896
  if (uncompressedFile) {
7436
- const encryptionOverhead = encrypted ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
7437
- extraFieldZip64.writeUint64(passThrough ? 0 : uncompressedSize + encryptionOverhead);
7897
+ const encryptionOverhead = getEncryptionOverhead(encrypted, zipCrypto, encryptionStrength);
7898
+ extraFieldZip64.writeUint64(passThroughCompression ? 0 : uncompressedSize + encryptionOverhead);
7438
7899
  }
7439
7900
  }
7440
7901
  } else {
@@ -7453,6 +7914,7 @@ function getHeaderInfo(options) {
7453
7914
  let rawExtraFieldNTFS;
7454
7915
  let rawExtraFieldExtendedTimestamp;
7455
7916
  let extraFieldExtendedTimestampFlag;
7917
+ let extraFieldExtendedTimestampTime;
7456
7918
  if (extendedTimestamp) {
7457
7919
  const lastModTimeUnix = getTimeUnix(lastModDate);
7458
7920
  const lastModTimeUnixInRange = inUnixTimeRange(lastModTimeUnix);
@@ -7460,6 +7922,7 @@ function getHeaderInfo(options) {
7460
7922
  const extraFieldTimestampLength = 9 + (lastAccessDate ? 4 : 0) + (creationDate ? 4 : 0);
7461
7923
  const extraFieldTimestamp = createRecordWriter(extraFieldTimestampLength);
7462
7924
  extraFieldExtendedTimestampFlag = 0x1 + (lastAccessDate ? 0x2 : 0) + (creationDate ? 0x4 : 0);
7925
+ extraFieldExtendedTimestampTime = lastModTimeUnix;
7463
7926
  extraFieldTimestamp.writeUint16(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
7464
7927
  extraFieldTimestamp.writeUint16(extraFieldTimestampLength - 4);
7465
7928
  extraFieldTimestamp.writeUint8(extraFieldExtendedTimestampFlag);
@@ -7543,7 +8006,7 @@ function getHeaderInfo(options) {
7543
8006
  }
7544
8007
  if (encrypted && !zipCrypto) {
7545
8008
  version = version > VERSION_AES ? version : VERSION_AES;
7546
- if (passThrough && crc32 !== UNDEFINED_VALUE) {
8009
+ if (passThroughCompression && crc32 !== UNDEFINED_VALUE) {
7547
8010
  rawExtraFieldAES[EXTRAFIELD_OFFSET_AES_VENDOR_VERSION] = VENDOR_VERSION_AE_1;
7548
8011
  }
7549
8012
  setUint16(getDataView(rawExtraFieldAES), EXTRAFIELD_OFFSET_AES_COMPRESSION_METHOD, compressionMethod);
@@ -7556,6 +8019,10 @@ function getHeaderInfo(options) {
7556
8019
  throw new Error(ERR_INVALID_EXTRAFIELD_DATA);
7557
8020
  }
7558
8021
  const dosLastModDate = new Date(Math.ceil(Math.floor(lastModDate.getTime() / 1000) / 2) * 2000);
8022
+ const clampedLastModDate = dosLastModDate < MIN_DATE ? MIN_DATE : dosLastModDate > MAX_DATE ? MAX_DATE : dosLastModDate;
8023
+ const storedLastModDate = getLength(rawExtraFieldExtendedTimestamp) ?
8024
+ new Date(getTimeUnix(lastModDate) * 1000) :
8025
+ getLength(rawExtraFieldNTFS) ? lastModDate : clampedLastModDate;
7559
8026
  const {
7560
8027
  headerArray,
7561
8028
  headerView,
@@ -7565,7 +8032,7 @@ function getHeaderInfo(options) {
7565
8032
  bitFlag: getBitFlag(level, useUnicodeFileNames, dataDescriptor, encrypted, compressionMethod),
7566
8033
  compressionMethod,
7567
8034
  uncompressedSize,
7568
- lastModDate: dosLastModDate < MIN_DATE ? MIN_DATE : dosLastModDate > MAX_DATE ? MAX_DATE : dosLastModDate,
8035
+ lastModDate: clampedLastModDate,
7569
8036
  rawLastModDate: rawLastModDateOption,
7570
8037
  rawFilename,
7571
8038
  zip64CompressedSize,
@@ -7600,13 +8067,15 @@ function getHeaderInfo(options) {
7600
8067
  localHeaderView,
7601
8068
  headerArray,
7602
8069
  headerView,
7603
- lastModDate,
8070
+ lastModDate: storedLastModDate,
8071
+ lastModDateClamped: storedLastModDate === clampedLastModDate && dosLastModDate.getTime() != clampedLastModDate.getTime(),
7604
8072
  rawLastModDate,
7605
8073
  encrypted,
7606
8074
  compressed,
7607
8075
  version,
7608
8076
  compressionMethod,
7609
8077
  extraFieldExtendedTimestampFlag,
8078
+ extraFieldExtendedTimestampTime,
7610
8079
  rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
7611
8080
  localExtraFieldZip64Length,
7612
8081
  rawExtraFieldExtendedTimestamp,
@@ -7709,7 +8178,7 @@ function setEntryInfo({
7709
8178
  }, {
7710
8179
  zip64,
7711
8180
  zipCrypto,
7712
- passThrough,
8181
+ passThroughCompression,
7713
8182
  dataDescriptor
7714
8183
  }) {
7715
8184
  const {
@@ -7720,7 +8189,7 @@ function setEntryInfo({
7720
8189
  dataDescriptorView,
7721
8190
  dataDescriptorOffset
7722
8191
  } = dataDescriptorInfo;
7723
- if ((!encrypted || zipCrypto || passThrough) && crc32 !== UNDEFINED_VALUE) {
8192
+ if ((!encrypted || zipCrypto || passThroughCompression) && crc32 !== UNDEFINED_VALUE) {
7724
8193
  setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
7725
8194
  if (dataDescriptor) {
7726
8195
  setUint32(dataDescriptorView, dataDescriptorOffset, crc32);
@@ -7751,9 +8220,9 @@ function updateLocalHeader({
7751
8220
  uncompressedSize,
7752
8221
  zip64UncompressedSize,
7753
8222
  zip64CompressedSize
7754
- }, localHeaderView, { dataDescriptor, passThrough }) {
8223
+ }, localHeaderView, { dataDescriptor, passThroughCompression }) {
7755
8224
  if (!dataDescriptor) {
7756
- if (!encrypted || (passThrough && crc32 !== UNDEFINED_VALUE)) {
8225
+ if (!encrypted || (passThroughCompression && crc32 !== UNDEFINED_VALUE)) {
7757
8226
  setUint32(localHeaderView, HEADER_OFFSET_SIGNATURE + LOCAL_HEADER_COMMON_OFFSET, crc32);
7758
8227
  }
7759
8228
  if (!zip64CompressedSize) {
@@ -7772,14 +8241,15 @@ function updateLocalHeader({
7772
8241
 
7773
8242
 
7774
8243
  async function closeFile(zipWriter, comment, options) {
7775
- const directoryDataLength = createDirectoryRecords(zipWriter.fileEntries);
8244
+ const { directoryDataLength, zip64Entries } = createDirectoryRecords(zipWriter.fileEntries);
7776
8245
  const { directoryStart, directoryEnd, directoryArray } = await writeDirectoryRecords(zipWriter, directoryDataLength, options);
7777
8246
  const signatureLength = await writeDigitalSignatureRecord(zipWriter, directoryArray, options);
7778
- await writeEndOfDirectoryRecord(zipWriter, comment, options, { directoryStart, directoryEnd, directoryDataLength, signatureLength });
8247
+ await writeEndOfDirectoryRecord(zipWriter, comment, options, { directoryStart, directoryEnd, directoryDataLength, signatureLength, zip64Entries });
7779
8248
  }
7780
8249
 
7781
8250
  function createDirectoryRecords(files) {
7782
8251
  let directoryDataLength = 0;
8252
+ let zip64Entries = false;
7783
8253
  for (const [, fileEntry] of files) {
7784
8254
  const {
7785
8255
  rawFilename,
@@ -7789,14 +8259,22 @@ function createDirectoryRecords(files) {
7789
8259
  rawExtraFieldUnix,
7790
8260
  rawExtraField,
7791
8261
  rawCentralExtraField,
7792
- extendedTimestamp,
7793
8262
  extraFieldExtendedTimestampFlag,
7794
- lastModDate,
7795
- zip64UncompressedSize,
7796
- zip64CompressedSize,
8263
+ extraFieldExtendedTimestampTime,
8264
+ zip64Enabled,
7797
8265
  uncompressedSize,
7798
8266
  compressedSize
7799
8267
  } = fileEntry;
8268
+ let { zip64UncompressedSize, zip64CompressedSize } = fileEntry;
8269
+ if (!zip64Enabled) {
8270
+ if (zip64UncompressedSize && uncompressedSize < MAX_32_BITS) {
8271
+ zip64UncompressedSize = fileEntry.zip64UncompressedSize = false;
8272
+ }
8273
+ if (zip64CompressedSize && compressedSize < MAX_32_BITS) {
8274
+ zip64CompressedSize = fileEntry.zip64CompressedSize = false;
8275
+ }
8276
+ }
8277
+ zip64Entries = zip64Entries || zip64UncompressedSize || zip64CompressedSize;
7800
8278
  const zip64Offset = fileEntry.offset >= MAX_32_BITS;
7801
8279
  const zip64DiskNumberStart = fileEntry.diskNumberStart >= MAX_16_BITS;
7802
8280
  let rawExtraFieldZip64;
@@ -7825,16 +8303,15 @@ function createDirectoryRecords(files) {
7825
8303
  fileEntry.zip64Offset = zip64Offset;
7826
8304
  fileEntry.zip64DiskNumberStart = zip64DiskNumberStart;
7827
8305
  let rawExtraFieldTimestamp;
7828
- const lastModTimeUnix = getTimeUnix(lastModDate);
7829
- if (extendedTimestamp && inUnixTimeRange(lastModTimeUnix)) {
8306
+ if (extraFieldExtendedTimestampTime === UNDEFINED_VALUE) {
8307
+ rawExtraFieldTimestamp = EMPTY_UINT8_ARRAY;
8308
+ } else {
7830
8309
  const extraFieldTimestamp = createRecordWriter(9);
7831
8310
  extraFieldTimestamp.writeUint16(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
7832
8311
  extraFieldTimestamp.writeUint16(5);
7833
8312
  extraFieldTimestamp.writeUint8(extraFieldExtendedTimestampFlag);
7834
- extraFieldTimestamp.writeUint32(lastModTimeUnix);
8313
+ extraFieldTimestamp.writeUint32(extraFieldExtendedTimestampTime);
7835
8314
  rawExtraFieldTimestamp = extraFieldTimestamp.array;
7836
- } else {
7837
- rawExtraFieldTimestamp = EMPTY_UINT8_ARRAY;
7838
8315
  }
7839
8316
  fileEntry.rawExtraFieldExtendedTimestamp = rawExtraFieldTimestamp;
7840
8317
  const extraFieldLength = getLength(
@@ -7850,7 +8327,7 @@ function createDirectoryRecords(files) {
7850
8327
  }
7851
8328
  directoryDataLength += CENTRAL_FILE_HEADER_LENGTH + getLength(rawFilename, rawComment) + extraFieldLength;
7852
8329
  }
7853
- return directoryDataLength;
8330
+ return { directoryDataLength, zip64Entries };
7854
8331
  }
7855
8332
 
7856
8333
  async function writeDirectoryRecords(zipWriter, directoryDataLength, options) {
@@ -7970,7 +8447,7 @@ async function writeDigitalSignatureRecord(zipWriter, directoryArray, options) {
7970
8447
 
7971
8448
  async function writeEndOfDirectoryRecord(zipWriter, comment, options, cdInfo) {
7972
8449
  const { writer } = zipWriter;
7973
- const { directoryStart, directoryEnd, signatureLength } = cdInfo;
8450
+ const { directoryStart, directoryEnd, signatureLength, zip64Entries } = cdInfo;
7974
8451
  let { directoryDataLength } = cdInfo;
7975
8452
  let fileEntriesLength = zipWriter.fileEntries.size;
7976
8453
  let diskNumber = directoryStart.diskNumber;
@@ -7990,6 +8467,8 @@ async function writeEndOfDirectoryRecord(zipWriter, comment, options, cdInfo) {
7990
8467
  } else {
7991
8468
  zip64 = true;
7992
8469
  }
8470
+ } else if (zip64 === UNDEFINED_VALUE && zip64Entries) {
8471
+ zip64 = true;
7993
8472
  }
7994
8473
  const endOfdirectoryRecord = createRecordWriter(zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
7995
8474
  if (exceedsAvailableSize(writer, getLength(endOfdirectoryRecord.array) + commentLength)) {
@@ -8332,6 +8811,11 @@ function getHeaderArrayData({
8332
8811
  };
8333
8812
  }
8334
8813
 
8814
+ function isPrintableASCIIText(rawText) {
8815
+ return rawText.every(characterCode =>
8816
+ characterCode >= MIN_PRINTABLE_ASCII_CHARACTER_CODE && characterCode <= MAX_PRINTABLE_ASCII_CHARACTER_CODE);
8817
+ }
8818
+
8335
8819
  function getBitFlag(level, useUnicodeFileNames, dataDescriptor, encrypted, compressionMethod) {
8336
8820
  let bitFlag = 0;
8337
8821
  if (useUnicodeFileNames) {
@@ -8493,7 +8977,7 @@ function formatSupported(StreamClass, format) {
8493
8977
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8494
8978
  */
8495
8979
 
8496
- const VERSION = "2.11.1";
8980
+ const VERSION = "2.13.1";
8497
8981
 
8498
8982
  /*
8499
8983
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
@@ -9687,4 +10171,4 @@ try {
9687
10171
  }
9688
10172
  catch (e) { }
9689
10173
 
9690
- export { BlobReader, BlobWriter, Data64URIReader, Data64URIWriter, ERR_AMBIGUOUS_ARCHIVE, ERR_BAD_FORMAT, ERR_CENTRAL_DIRECTORY_NOT_FOUND, ERR_DUPLICATED_NAME, ERR_ENCRYPTED, ERR_ENCRYPTED_CENTRAL_DIRECTORY, ERR_ENTRY_DATA_OUT_OF_BOUNDS, ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND, ERR_EOCDR_NOT_FOUND, ERR_EXTRAFIELD_ZIP64_NOT_FOUND, ERR_HTTP_RANGE, ERR_HTTP_RESOURCE_CHANGED, ERR_INVALID_AUTHENTICATION_CODE, ERR_INVALID_CODEC_DEFINITION, ERR_INVALID_CODEC_MODULE, ERR_INVALID_COMMENT, ERR_INVALID_COMMENT_TYPE, ERR_INVALID_COMPRESSED_DATA, ERR_INVALID_CRC32, ERR_INVALID_DATE, ERR_INVALID_ENCRYPTION_STRENGTH, ERR_INVALID_ENTRY_COMMENT, ERR_INVALID_ENTRY_COMMENT_TYPE, ERR_INVALID_ENTRY_NAME, ERR_INVALID_EXTRAFIELD, ERR_INVALID_EXTRAFIELD_DATA, ERR_INVALID_EXTRAFIELD_DATA_TYPE, ERR_INVALID_EXTRAFIELD_TYPE, ERR_INVALID_FILENAME_VALIDATION, ERR_INVALID_FUNCTION_OPTION, ERR_INVALID_GID, ERR_INVALID_LEVEL, ERR_INVALID_MAX_APPENDED_DATA_SIZE, ERR_INVALID_MAX_WORKERS, ERR_INVALID_MSDOS_ATTRIBUTES, ERR_INVALID_MSDOS_DATA, ERR_INVALID_PASSWORD, ERR_INVALID_PASSWORD_TYPE, ERR_INVALID_SIGNAL, ERR_INVALID_SIGNATURE_DATA, ERR_INVALID_STRICTNESS, ERR_INVALID_UID, ERR_INVALID_UNCOMPRESSED_SIZE, ERR_INVALID_UNIX_EXTRA_FIELD_TYPE, ERR_INVALID_UNIX_ID_SIZE, ERR_INVALID_UNIX_MODE, ERR_INVALID_VERSION, ERR_ITERATOR_COMPLETED_TOO_SOON, ERR_LOCAL_FILE_HEADER_NOT_FOUND, ERR_OVERLAPPING_ENTRY, ERR_RESERVED_COMPRESSION_METHOD, ERR_SPLIT_ZIP_FILE, ERR_UNDEFINED_COMPRESSION_METHOD, ERR_UNDEFINED_READER, ERR_UNDEFINED_UNCOMPRESSED_SIZE, ERR_UNDETERMINED_SIZE, ERR_UNSAFE_FILENAME, ERR_UNSUPPORTED_COMPRESSION, ERR_UNSUPPORTED_CONTEXT, ERR_UNSUPPORTED_CRYPTO_API, ERR_UNSUPPORTED_ENCRYPTION, ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH, ERR_UNSUPPORTED_ENCRYPTION_USDZ, ERR_UNSUPPORTED_FORMAT, ERR_UNSUPPORTED_UINT64, ERR_WORKER_STARTUP_TIMEOUT, ERR_WRITER_NOT_INITIALIZED, ERR_ZIP_NOT_EMPTY, HttpRangeReader, HttpReader, Reader, SplitDataReader, SplitDataWriter, TextReader, TextWriter, Uint8ArrayReader, Uint8ArrayWriter, VERSION, WARNING_APPENDED_DATA, WARNING_COMPRESSED_PATCHED_DATA, WARNING_DUPLICATE_FILENAME, WARNING_MALFORMED_EXTRA_FIELD, WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG, WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD, WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES, WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY, WARNING_PREPENDED_CENTRAL_DIRECTORY, WARNING_PREPENDED_DATA, WARNING_TRAILING_CENTRAL_DIRECTORY_DATA, WARNING_UNKNOWN_VERSION, WARNING_UNKNOWN_ZIP64_EXTENSIBLE_DATA, WARNING_UNSORTED_CENTRAL_DIRECTORY, WARNING_WRAPPED_ENTRIES_COUNT, Writer, ZipReader, ZipReaderStream, ZipWriter, ZipWriterStream, configure, createBlobTempStream, createOPFSTempStream, createSyncAccessHandleTempStream, deflateSync as deflateRaw, getMimeType, getRegisteredCodecs, getSupportedCompressionMethods, inflateSync as inflateRaw, initStream, isZipFile, readUint8Array, registerCodec, resetConfiguration, terminateWorkers, unregisterCodec };
10174
+ export { BlobReader, BlobWriter, Data64URIReader, Data64URIWriter, ERR_ABORTED, ERR_AMBIGUOUS_ARCHIVE, ERR_BAD_FORMAT, ERR_CENTRAL_DIRECTORY_NOT_FOUND, ERR_DUPLICATED_NAME, ERR_ENCRYPTED, ERR_ENCRYPTED_CENTRAL_DIRECTORY, ERR_ENTRY_DATA_OUT_OF_BOUNDS, ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND, ERR_EOCDR_NOT_FOUND, ERR_EXTRAFIELD_ZIP64_NOT_FOUND, ERR_HTTP_RANGE, ERR_HTTP_RESOURCE_CHANGED, ERR_HTTP_STATUS, ERR_INVALID_AUTHENTICATION_CODE, ERR_INVALID_BASE_URI, ERR_INVALID_CODEC_DEFINITION, ERR_INVALID_CODEC_MODULE, ERR_INVALID_COMMENT, ERR_INVALID_COMMENT_TYPE, ERR_INVALID_COMPRESSED_DATA, ERR_INVALID_CRC32, ERR_INVALID_DATE, ERR_INVALID_ENCRYPTION_STRENGTH, ERR_INVALID_ENTRY, ERR_INVALID_ENTRY_COMMENT, ERR_INVALID_ENTRY_COMMENT_TYPE, ERR_INVALID_ENTRY_NAME, ERR_INVALID_EXTRAFIELD, ERR_INVALID_EXTRAFIELD_DATA, ERR_INVALID_EXTRAFIELD_DATA_TYPE, ERR_INVALID_EXTRAFIELD_TYPE, ERR_INVALID_FILENAME_VALIDATION, ERR_INVALID_FUNCTION_OPTION, ERR_INVALID_GID, ERR_INVALID_LEVEL, ERR_INVALID_MAX_APPENDED_DATA_SIZE, ERR_INVALID_MAX_WORKERS, ERR_INVALID_MSDOS_ATTRIBUTES, ERR_INVALID_MSDOS_DATA, ERR_INVALID_PASSWORD, ERR_INVALID_PASSWORD_TYPE, ERR_INVALID_PASS_THROUGH_VALUE, ERR_INVALID_READER, ERR_INVALID_SIGNAL, ERR_INVALID_SIGNATURE_DATA, ERR_INVALID_STRICTNESS, ERR_INVALID_UID, ERR_INVALID_UNCOMPRESSED_SIZE, ERR_INVALID_UNIX_EXTRA_FIELD_TYPE, ERR_INVALID_UNIX_ID_SIZE, ERR_INVALID_UNIX_MODE, ERR_INVALID_URI, ERR_INVALID_VERSION, ERR_ITERATOR_COMPLETED_TOO_SOON, ERR_LOCAL_FILE_HEADER_NOT_FOUND, ERR_OVERLAPPING_ENTRY, ERR_RESERVED_COMPRESSION_METHOD, ERR_SPLIT_ZIP_FILE, ERR_UNDEFINED_COMPRESSION_METHOD, ERR_UNDEFINED_CRC32, ERR_UNDEFINED_READER, ERR_UNDEFINED_UNCOMPRESSED_SIZE, ERR_UNDETERMINED_SIZE, ERR_UNSAFE_FILENAME, ERR_UNSUPPORTED_COMPRESSION, ERR_UNSUPPORTED_CONTEXT, ERR_UNSUPPORTED_CRYPTO_API, ERR_UNSUPPORTED_ENCRYPTION, ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH, ERR_UNSUPPORTED_ENCRYPTION_USDZ, ERR_UNSUPPORTED_FORMAT, ERR_UNSUPPORTED_SPLIT_USDZ, ERR_UNSUPPORTED_UINT64, ERR_WORKER_STARTUP_TIMEOUT, ERR_WRITER_NOT_INITIALIZED, ERR_WRITER_SIZE_NOT_WRITABLE, ERR_ZIP_CRYPTO_LAST_MOD_DATE, ERR_ZIP_NOT_EMPTY, HttpRangeReader, HttpReader, Reader, SplitDataReader, SplitDataWriter, TextReader, TextWriter, Uint8ArrayReader, Uint8ArrayWriter, VERSION, WARNING_APPENDED_DATA, WARNING_CLAMPED_LAST_MODIFICATION_DATE, WARNING_COMPRESSED_PATCHED_DATA, WARNING_COMPRESSION_UNAVAILABLE, WARNING_DUPLICATE_FILENAME, WARNING_MALFORMED_EXTRA_FIELD, WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG, WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD, WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES, WARNING_MISMATCHED_LOCAL_FILE_HEADER_FILENAME, WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY, WARNING_MULTIPLE_END_OF_CENTRAL_DIRECTORY, WARNING_PREPENDED_CENTRAL_DIRECTORY, WARNING_PREPENDED_DATA, WARNING_TRAILING_CENTRAL_DIRECTORY_DATA, WARNING_UNKNOWN_VERSION, WARNING_UNKNOWN_ZIP64_EXTENSIBLE_DATA, WARNING_UNSORTED_CENTRAL_DIRECTORY, WARNING_WRAPPED_ENTRIES_COUNT, Writer, ZipReader, ZipReaderStream, ZipWriter, ZipWriterStream, configure, createBlobTempStream, createOPFSTempStream, createSyncAccessHandleTempStream, deflateSync as deflateRaw, getMimeType, getRegisteredCodecs, getSupportedCompressionMethods, inflateSync as inflateRaw, initStream, isZipFile, readUint8Array, registerCodec, resetConfiguration, terminateWorkers, unregisterCodec };