@zip.js/zip.js 2.16.1 → 2.17.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 (45) hide show
  1. package/deno.json +1 -1
  2. package/dist/zip-core-external.js +169 -119
  3. package/dist/zip-core-external.min.js +1 -1
  4. package/dist/zip-core.js +138 -106
  5. package/dist/zip-core.min.js +1 -1
  6. package/dist/zip-fs-core-external.js +181 -121
  7. package/dist/zip-fs-core-external.min.js +1 -1
  8. package/dist/zip-fs-core.js +150 -108
  9. package/dist/zip-fs-core.min.js +1 -1
  10. package/dist/zip-fs-external.js +181 -121
  11. package/dist/zip-fs-external.min.js +1 -1
  12. package/dist/zip-fs-native.js +153 -111
  13. package/dist/zip-fs-native.min.js +1 -1
  14. package/dist/zip-fs.js +182 -121
  15. package/dist/zip-fs.min.js +1 -1
  16. package/dist/zip-legacy.js +140 -108
  17. package/dist/zip-legacy.min.js +1 -1
  18. package/dist/zip-native.js +141 -109
  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 +170 -119
  23. package/dist/zip.min.js +1 -1
  24. package/index-native.cjs +153 -111
  25. package/index-native.min.js +1 -1
  26. package/index.cjs +182 -121
  27. package/index.d.cts +58 -20
  28. package/index.d.ts +58 -20
  29. package/index.min.js +1 -1
  30. package/lib/core/codec-pool.js +2 -0
  31. package/lib/core/codec-worker-web.js +11 -3
  32. package/lib/core/codec-worker.js +2 -1
  33. package/lib/core/streams/codec-stream.js +2 -0
  34. package/lib/core/streams/zip-entry-stream.js +123 -102
  35. package/lib/core/streams/zlib-js/zlib-streams.min.js +1 -1
  36. package/lib/core/streams/zlib-wasm/zlib-streams.js +31 -12
  37. package/lib/core/version.js +1 -1
  38. package/lib/core/web-worker-base.js +1 -1
  39. package/lib/core/web-worker-inline-native.js +1 -1
  40. package/lib/core/web-worker-inline-wasm.js +1 -1
  41. package/lib/core/zip-fs.js +16 -3
  42. package/lib/core/zip-reader.js +3 -0
  43. package/lib/core/zip-writer.js +1 -0
  44. package/lib/zip-core-reader.js +1 -0
  45. package/package.json +1 -1
package/dist/zip-core.js CHANGED
@@ -1900,7 +1900,9 @@
1900
1900
 
1901
1901
  const ERR_INVALID_UNCOMPRESSED_SIZE = "Invalid uncompressed size";
1902
1902
  const ERR_INVALID_COMPRESSED_DATA = "Invalid compressed data";
1903
+ const ERR_CODEC_OUT_OF_MEMORY = "Codec out of memory";
1903
1904
  const ERR_INVALID_CRC32 = "Invalid CRC32";
1905
+ const Z_MEM_ERROR_CODE = "Z_MEM_ERROR";
1904
1906
  const FORMAT_DEFLATE_RAW = "deflate-raw";
1905
1907
  const FORMAT_DEFLATE64_RAW = "deflate64-raw";
1906
1908
  const FORMAT_GZIP = "gzip";
@@ -1935,13 +1937,13 @@
1935
1937
  readable = pipeThroughCompressionStream(readable, useCompressionStream, { level, chunkSize }, CompressionStream, CompressionStreamFallback);
1936
1938
  } catch (error) {
1937
1939
  if (!useCompressionStream && CompressionStreamFallback) {
1938
- throw error;
1940
+ throw mapMemoryError(error);
1939
1941
  }
1940
1942
  let gzipStream;
1941
1943
  try {
1942
1944
  gzipStream = new CompressionStream(FORMAT_GZIP);
1943
1945
  } catch {
1944
- throw error;
1946
+ throw mapMemoryError(error);
1945
1947
  }
1946
1948
  readable = pipeThroughBackpressured(readable, gzipStream);
1947
1949
  readable = pipeThrough(readable, new GzipToRawDeflateStream());
@@ -2005,50 +2007,30 @@
2005
2007
  }
2006
2008
  }
2007
2009
 
2008
- function pipeThroughGzipDecompressionStream(readable, gzipStream, outputSize, crc32) {
2010
+ function pipeThroughGzipDecompressionStream(readable, gzipStream, outputSize, crc32, sourceErrors) {
2009
2011
  const writer = gzipStream.writable.getWriter();
2010
2012
  const reader = gzipStream.readable.getReader();
2011
2013
  const outputCrc32 = crc32 === UNDEFINED_VALUE ? new Crc32() : UNDEFINED_VALUE;
2012
2014
  let outputLength = 0;
2013
- let inputDone = false;
2014
2015
  let trailerWritten = false;
2015
- let idleCheckArmed = false;
2016
- let readCount = 0;
2017
- let readPending = false;
2018
- let resolveTrailerReady, rejectTrailerReady;
2019
- const trailerReady = new Promise((resolve, reject) => {
2020
- resolveTrailerReady = resolve;
2021
- rejectTrailerReady = reject;
2022
- });
2023
- trailerReady.catch(() => { });
2024
- pump();
2025
- return new ReadableStream({
2026
- async pull(controller) {
2027
- try {
2028
- const { value, done } = await read();
2029
- if (done) {
2030
- controller.close();
2031
- } else {
2032
- outputLength += value.length;
2033
- if (outputLength > outputSize) {
2034
- throw new Error(ERR_INVALID_UNCOMPRESSED_SIZE);
2035
- }
2036
- if (outputCrc32) {
2037
- outputCrc32.append(value);
2038
- }
2039
- controller.enqueue(value);
2040
- }
2041
- } catch (error) {
2042
- rejectTrailerReady(error);
2043
- await cancel(reader, error);
2044
- throw trailerWritten ? getTrailerError(error) : error;
2045
- }
2016
+ let settled = false;
2017
+ let resolvePull, controller;
2018
+ const output = new ReadableStream({
2019
+ start(streamController) {
2020
+ controller = streamController;
2021
+ },
2022
+ pull() {
2023
+ resumePump();
2046
2024
  },
2047
2025
  cancel(reason) {
2048
- rejectTrailerReady(reason);
2026
+ settled = true;
2027
+ resumePump();
2049
2028
  return reader.cancel(reason);
2050
2029
  }
2051
2030
  });
2031
+ pump();
2032
+ drain();
2033
+ return output;
2052
2034
 
2053
2035
  async function pump() {
2054
2036
  const inputReader = readable.getReader();
@@ -2057,19 +2039,16 @@
2057
2039
  header.set(GZIP_HEADER_BYTES);
2058
2040
  await writer.write(header);
2059
2041
  for (; ;) {
2042
+ await outputCapacity();
2060
2043
  await writer.ready;
2061
- const { value, done } = await inputReader.read();
2044
+ const { value, done } = await readSource(inputReader, sourceErrors);
2062
2045
  if (done) {
2063
2046
  break;
2064
2047
  }
2065
2048
  await writer.write(value);
2066
2049
  }
2067
- inputDone = true;
2068
2050
  if (outputCrc32) {
2069
- if (readPending) {
2070
- armIdleCheck();
2071
- }
2072
- await trailerReady;
2051
+ await writer.write(new Uint8Array(0));
2073
2052
  }
2074
2053
  const trailer = new Uint8Array(GZIP_TRAILER_LENGTH);
2075
2054
  const dataView = getDataView(trailer);
@@ -2084,54 +2063,68 @@
2084
2063
  }
2085
2064
  }
2086
2065
 
2087
- function read() {
2088
- readCount++;
2089
- readPending = true;
2090
- const result = reader.read();
2091
- result.then(onReadSettled, onReadSettled);
2092
- if (inputDone && outputCrc32) {
2093
- armIdleCheck();
2066
+ async function drain() {
2067
+ try {
2068
+ for (; ;) {
2069
+ const { value, done } = await read();
2070
+ if (done) {
2071
+ break;
2072
+ }
2073
+ outputLength += value.length;
2074
+ if (outputLength > outputSize) {
2075
+ throw new Error(ERR_INVALID_UNCOMPRESSED_SIZE);
2076
+ }
2077
+ if (outputCrc32) {
2078
+ outputCrc32.append(value);
2079
+ }
2080
+ controller.enqueue(value);
2081
+ }
2082
+ if (!settled) {
2083
+ settled = true;
2084
+ controller.close();
2085
+ }
2086
+ } catch (error) {
2087
+ fail(error);
2088
+ await cancel(reader, error);
2094
2089
  }
2095
- return result;
2096
- }
2097
-
2098
- function onReadSettled() {
2099
- readPending = false;
2100
2090
  }
2101
2091
 
2102
- async function armIdleCheck() {
2103
- if (!idleCheckArmed) {
2104
- idleCheckArmed = true;
2105
- const count = readCount;
2106
- await nextTask();
2107
- idleCheckArmed = false;
2108
- if (readPending) {
2109
- if (readCount == count) {
2110
- resolveTrailerReady();
2111
- } else {
2112
- armIdleCheck();
2092
+ function read() {
2093
+ return reader.read().catch(error => {
2094
+ if (trailerWritten) {
2095
+ if (!outputCrc32) {
2096
+ throw mapError(error, ERR_INVALID_CRC32);
2113
2097
  }
2098
+ if (outputLength != outputSize) {
2099
+ throw mapError(error, ERR_INVALID_UNCOMPRESSED_SIZE);
2100
+ }
2101
+ return { done: true };
2114
2102
  }
2115
- }
2103
+ throw mapCodecError(error, sourceErrors);
2104
+ });
2116
2105
  }
2117
2106
 
2118
- function getTrailerError(error) {
2119
- const trailerError = new Error(outputLength == outputSize ? ERR_INVALID_CRC32 : ERR_INVALID_UNCOMPRESSED_SIZE);
2120
- trailerError.cause = error;
2121
- return trailerError;
2107
+ function outputCapacity() {
2108
+ if (!settled && controller.desiredSize <= 0) {
2109
+ return new Promise(resolve => resolvePull = resolve);
2110
+ }
2122
2111
  }
2123
- }
2124
2112
 
2125
- function nextTask() {
2126
- return new Promise(resolve => {
2127
- const { port1, port2 } = new MessageChannel();
2128
- port2.onmessage = () => {
2129
- port1.close();
2130
- port2.close();
2113
+ function resumePump() {
2114
+ if (resolvePull) {
2115
+ const resolve = resolvePull;
2116
+ resolvePull = UNDEFINED_VALUE;
2131
2117
  resolve();
2132
- };
2133
- port1.postMessage(UNDEFINED_VALUE);
2134
- });
2118
+ }
2119
+ }
2120
+
2121
+ function fail(error) {
2122
+ if (!settled) {
2123
+ settled = true;
2124
+ controller.error(error);
2125
+ resumePump();
2126
+ }
2127
+ }
2135
2128
  }
2136
2129
 
2137
2130
  class InflateStream extends TransformStream {
@@ -2150,11 +2143,12 @@
2150
2143
  }
2151
2144
  }
2152
2145
  if (compressed) {
2146
+ const sourceErrors = new Set();
2153
2147
  const codecStreams = format && getCodecStreams(format);
2148
+ let gzipStream;
2154
2149
  if (codecStreams) {
2155
- readable = pipeThroughBackpressured(readable, createCodecStream(codecStreams.DecompressionStream, format, { chunkSize, compressionMethod, rawBitFlag, uncompressedSize: outputSize }));
2150
+ readable = pipeThroughBackpressured(readable, createCodecStream(codecStreams.DecompressionStream, format, { chunkSize, compressionMethod, rawBitFlag, uncompressedSize: outputSize }), sourceErrors);
2156
2151
  } else {
2157
- let gzipStream;
2158
2152
  const GzipDecompressionStream = getGzipCodecStream(useCompressionStream, DecompressionStream, DecompressionStreamFallback);
2159
2153
  if (checkCrc32 && !deflate64 && crc32 !== UNDEFINED_VALUE && outputSize !== UNDEFINED_VALUE && GzipDecompressionStream) {
2160
2154
  try {
@@ -2165,24 +2159,25 @@
2165
2159
  }
2166
2160
  if (!gzipStream) {
2167
2161
  try {
2168
- readable = pipeThroughCompressionStream(readable, useCompressionStream, { chunkSize, deflate64 }, DecompressionStream, DecompressionStreamFallback);
2162
+ readable = pipeThroughCompressionStream(readable, useCompressionStream, { chunkSize, deflate64 }, DecompressionStream, DecompressionStreamFallback, sourceErrors);
2169
2163
  } catch (error) {
2170
2164
  if (deflate64 || outputSize === UNDEFINED_VALUE || (!useCompressionStream && DecompressionStreamFallback)) {
2171
- throw error;
2165
+ throw mapMemoryError(error);
2172
2166
  }
2173
2167
  try {
2174
2168
  gzipStream = new DecompressionStream(FORMAT_GZIP);
2175
2169
  } catch {
2176
- throw error;
2170
+ throw mapMemoryError(error);
2177
2171
  }
2178
2172
  }
2179
2173
  }
2180
- if (gzipStream) {
2181
- gzipCrc32 = true;
2182
- readable = pipeThroughGzipDecompressionStream(readable, gzipStream, outputSize, crc32);
2183
- }
2184
2174
  }
2185
- readable = mapInflateStreamError(readable);
2175
+ if (gzipStream) {
2176
+ gzipCrc32 = true;
2177
+ readable = pipeThroughGzipDecompressionStream(readable, gzipStream, outputSize, crc32, sourceErrors);
2178
+ } else {
2179
+ readable = mapInflateStreamError(readable, sourceErrors);
2180
+ }
2186
2181
  }
2187
2182
  if (checkCrc32 && !gzipCrc32) {
2188
2183
  crc32Stream = new Crc32Stream();
@@ -2255,7 +2250,7 @@
2255
2250
  }
2256
2251
  }
2257
2252
 
2258
- function pipeThroughCompressionStream(readable, useCompressionStream, options, CompressionStreamNative, CompressionStreamFallback) {
2253
+ function pipeThroughCompressionStream(readable, useCompressionStream, options, CompressionStreamNative, CompressionStreamFallback, sourceErrors) {
2259
2254
  const Stream = useCompressionStream && CompressionStreamNative ?
2260
2255
  CompressionStreamNative :
2261
2256
  CompressionStreamFallback || CompressionStreamNative;
@@ -2270,14 +2265,14 @@
2270
2265
  throw error;
2271
2266
  }
2272
2267
  }
2273
- return pipeThroughBackpressured(readable, codecStream);
2268
+ return pipeThroughBackpressured(readable, codecStream, sourceErrors);
2274
2269
  }
2275
2270
 
2276
2271
  function pipeThrough(readable, transformStream) {
2277
2272
  return toCompatibleReadable(readable).pipeThrough(transformStream);
2278
2273
  }
2279
2274
 
2280
- function pipeThroughBackpressured(readable, transformStream) {
2275
+ function pipeThroughBackpressured(readable, transformStream, sourceErrors) {
2281
2276
  const writer = transformStream.writable.getWriter();
2282
2277
  const reader = readable.getReader();
2283
2278
  pump();
@@ -2287,7 +2282,7 @@
2287
2282
  try {
2288
2283
  for (; ;) {
2289
2284
  await writer.ready;
2290
- const result = await reader.read();
2285
+ const result = await readSource(reader, sourceErrors);
2291
2286
  if (result.done) {
2292
2287
  await writer.close();
2293
2288
  break;
@@ -2317,7 +2312,36 @@
2317
2312
  }
2318
2313
  }
2319
2314
 
2320
- function mapInflateStreamError(readable) {
2315
+ function readSource(reader, sourceErrors) {
2316
+ const result = reader.read();
2317
+ return sourceErrors ? result.catch(error => {
2318
+ sourceErrors.add(error);
2319
+ throw error;
2320
+ }) : result;
2321
+ }
2322
+
2323
+ function mapCodecError(error, sourceErrors) {
2324
+ if (sourceErrors.has(error)) {
2325
+ return error;
2326
+ }
2327
+ return mapError(error, isMemoryError(error) ? ERR_CODEC_OUT_OF_MEMORY : ERR_INVALID_COMPRESSED_DATA);
2328
+ }
2329
+
2330
+ function mapMemoryError(error) {
2331
+ return isMemoryError(error) ? mapError(error, ERR_CODEC_OUT_OF_MEMORY) : error;
2332
+ }
2333
+
2334
+ function isMemoryError(error) {
2335
+ return isErrorObject(error) && error.code == Z_MEM_ERROR_CODE;
2336
+ }
2337
+
2338
+ function mapError(error, message) {
2339
+ const mappedError = new Error(message);
2340
+ mappedError.cause = error;
2341
+ return mappedError;
2342
+ }
2343
+
2344
+ function mapInflateStreamError(readable, sourceErrors) {
2321
2345
  const reader = readable.getReader();
2322
2346
  return new ReadableStream({
2323
2347
  async pull(controller) {
@@ -2330,12 +2354,7 @@
2330
2354
  }
2331
2355
  } catch (error) {
2332
2356
  await cancel(reader, error);
2333
- if (error && error.message) {
2334
- throw error;
2335
- }
2336
- const mappedError = new Error(ERR_INVALID_COMPRESSED_DATA);
2337
- mappedError.cause = error;
2338
- throw mappedError;
2357
+ throw mapCodecError(error, sourceErrors);
2339
2358
  }
2340
2359
  },
2341
2360
  cancel(reason) {
@@ -2699,10 +2718,11 @@
2699
2718
  }
2700
2719
  codecStream = new CodecStream(options, config);
2701
2720
  chunkStream = new ChunkStream(getChunkSize(config));
2721
+ const { signal } = workerOptions.streamOptions;
2702
2722
  await readable
2703
2723
  .pipeThrough(codecStream)
2704
2724
  .pipeThrough(chunkStream)
2705
- .pipeTo(writable, { preventClose: true, preventAbort: true });
2725
+ .pipeTo(writable, { preventClose: true, preventAbort: true, signal });
2706
2726
  const {
2707
2727
  crc32,
2708
2728
  inputSize,
@@ -2770,6 +2790,7 @@
2770
2790
  const MODULE_WORKER_OPTIONS = { type: "module" };
2771
2791
  const ERROR_EVENT_TYPE = "error";
2772
2792
  const MESSAGE_ERROR_EVENT_TYPE = "messageerror";
2793
+ const ABORT_EVENT_TYPE = "abort";
2773
2794
 
2774
2795
  let webWorkerSource, webWorkerURI, webWorkerOptions;
2775
2796
  let transferStreamsSupported = true;
@@ -2946,6 +2967,13 @@
2946
2967
  Object.assign(workerData, { destinationFailed: true, destinationError: error });
2947
2968
  }
2948
2969
  });
2970
+ const { signal } = workerData.workerOptions.streamOptions;
2971
+ if (signal) {
2972
+ const onAbort = () => abortController.abort(signal.reason);
2973
+ const removeAbortListener = () => signal.removeEventListener(ABORT_EVENT_TYPE, onAbort);
2974
+ signal.addEventListener(ABORT_EVENT_TYPE, onAbort);
2975
+ closed.then(removeAbortListener, removeAbortListener);
2976
+ }
2949
2977
  return {
2950
2978
  writable, closed, abortPipe: () => {
2951
2979
  aborting = true;
@@ -3208,9 +3236,6 @@
3208
3236
  responseError = errorValue.value;
3209
3237
  } else {
3210
3238
  responseError = Object.assign(new Error(message), { stack, code, name });
3211
- if (cause) {
3212
- responseError.cause = Object.assign(new Error(cause.message), { name: cause.name });
3213
- }
3214
3239
  }
3215
3240
  if (isErrorObject(responseError)) {
3216
3241
  try {
@@ -3220,6 +3245,9 @@
3220
3245
  if (codecImportFailed) {
3221
3246
  responseError.codecImportFailed = true;
3222
3247
  }
3248
+ if (cause && !isErrorObject(responseError.cause)) {
3249
+ responseError.cause = Object.assign(new Error(cause.message), { name: cause.name });
3250
+ }
3223
3251
  if (errorValue) {
3224
3252
  if (responseError.name !== name) {
3225
3253
  responseError.name = name;
@@ -5542,6 +5570,7 @@
5542
5570
  ({ writable } = writer);
5543
5571
  const readable = toCompatibleReadable(reader.createReadable({ offset: dataOffset, size }));
5544
5572
  const { outputSize: writtenSize } = await runWorker({ readable, writable }, workerOptions);
5573
+ throwIfAborted(signal);
5545
5574
  if (writtenSize != outputSize) {
5546
5575
  throw Object.assign(new Error(ERR_INVALID_UNCOMPRESSED_SIZE), { outputSize: writtenSize });
5547
5576
  }
@@ -6337,6 +6366,7 @@
6337
6366
  ERR_AMBIGUOUS_ARCHIVE: ERR_AMBIGUOUS_ARCHIVE,
6338
6367
  ERR_BAD_FORMAT: ERR_BAD_FORMAT,
6339
6368
  ERR_CENTRAL_DIRECTORY_NOT_FOUND: ERR_CENTRAL_DIRECTORY_NOT_FOUND,
6369
+ ERR_CODEC_OUT_OF_MEMORY: ERR_CODEC_OUT_OF_MEMORY,
6340
6370
  ERR_ENCRYPTED: ERR_ENCRYPTED,
6341
6371
  ERR_ENCRYPTED_CENTRAL_DIRECTORY: ERR_ENCRYPTED_CENTRAL_DIRECTORY,
6342
6372
  ERR_ENTRY_DATA_OUT_OF_BOUNDS: ERR_ENTRY_DATA_OUT_OF_BOUNDS,
@@ -7686,6 +7716,7 @@
7686
7716
  const result = await runWorker({ readable, writable }, workerOptions);
7687
7717
  compressedSize = result.outputSize;
7688
7718
  writer.size += compressedSize;
7719
+ throwIfAborted(signal);
7689
7720
  if (!passThroughCompression) {
7690
7721
  uncompressedSize = result.inputSize;
7691
7722
  if (!encrypted || zipCrypto) {
@@ -8865,7 +8896,7 @@
8865
8896
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8866
8897
  */
8867
8898
 
8868
- const VERSION = "2.16.1";
8899
+ const VERSION = "2.17.0";
8869
8900
 
8870
8901
  /*
8871
8902
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
@@ -9322,6 +9353,7 @@
9322
9353
  exports.ERR_AMBIGUOUS_ARCHIVE = ERR_AMBIGUOUS_ARCHIVE;
9323
9354
  exports.ERR_BAD_FORMAT = ERR_BAD_FORMAT;
9324
9355
  exports.ERR_CENTRAL_DIRECTORY_NOT_FOUND = ERR_CENTRAL_DIRECTORY_NOT_FOUND;
9356
+ exports.ERR_CODEC_OUT_OF_MEMORY = ERR_CODEC_OUT_OF_MEMORY;
9325
9357
  exports.ERR_DUPLICATED_NAME = ERR_DUPLICATED_NAME;
9326
9358
  exports.ERR_ENCRYPTED = ERR_ENCRYPTED;
9327
9359
  exports.ERR_ENCRYPTED_CENTRAL_DIRECTORY = ERR_ENCRYPTED_CENTRAL_DIRECTORY;