@zip.js/zip.js 2.8.30 → 2.8.31

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 (53) hide show
  1. package/deno.json +5 -4
  2. package/dist/zip-core.js +133 -334
  3. package/dist/zip-core.min.js +1 -1
  4. package/dist/zip-fs-core.js +115 -277
  5. package/dist/zip-fs-core.min.js +1 -1
  6. package/dist/zip-fs-native.js +170 -373
  7. package/dist/zip-fs-native.min.js +1 -1
  8. package/dist/zip-fs.js +169 -372
  9. package/dist/zip-fs.min.js +1 -1
  10. package/dist/zip-legacy.js +138 -339
  11. package/dist/zip-legacy.min.js +1 -1
  12. package/dist/zip-module.wasm +0 -0
  13. package/dist/zip-native.js +141 -342
  14. package/dist/zip-native.min.js +1 -1
  15. package/dist/zip-web-worker-native.js +1 -1
  16. package/dist/zip-web-worker.js +1 -1
  17. package/dist/zip.js +140 -341
  18. package/dist/zip.min.js +1 -1
  19. package/index-native.cjs +170 -373
  20. package/index-native.min.js +1 -1
  21. package/index.cjs +169 -372
  22. package/index.d.cts +2814 -0
  23. package/index.d.ts +238 -0
  24. package/index.min.js +1 -1
  25. package/lib/core/codec-worker.js +0 -10
  26. package/lib/core/configuration.js +21 -33
  27. package/lib/core/constants.js +3 -0
  28. package/lib/core/io.js +11 -19
  29. package/lib/core/streams/aes-crypto-stream.js +16 -20
  30. package/lib/core/streams/common-crypto.js +0 -2
  31. package/lib/core/streams/zip-crypto-stream.js +12 -16
  32. package/lib/core/streams/zip-entry-stream.js +2 -32
  33. package/lib/core/streams/zlib-js/zlib-streams.min.js +1 -1
  34. package/lib/core/streams/zlib-wasm/zlib-streams-loader.js +1 -3
  35. package/lib/core/streams/zlib-wasm/zlib-streams.wasm +0 -0
  36. package/lib/core/util/base64.js +68 -0
  37. package/lib/core/util/decode-text.js +0 -1
  38. package/lib/core/util/default-mime-type.js +0 -3
  39. package/lib/core/util/inflate.js +194 -0
  40. package/lib/core/util/mime-type.js +26 -22
  41. package/lib/core/util/opfs-temp-stream.js +1 -37
  42. package/lib/core/web-worker-inline-native.js +1 -1
  43. package/lib/core/web-worker-inline-template-native.js +5 -5
  44. package/lib/core/web-worker-inline-wasm.js +1 -1
  45. package/lib/core/zip-fs.js +6 -13
  46. package/lib/core/zip-reader.js +48 -127
  47. package/lib/core/zip-writer.js +27 -45
  48. package/lib/core/zlib-streams-inline-template.js +3 -2
  49. package/lib/core/zlib-streams-inline.js +1 -1
  50. package/lib/zip-core-base.js +3 -1
  51. package/package.json +9 -6
  52. package/reserved-property-names.js +50 -0
  53. package/lib/core/util/mini-lz.js +0 -198
@@ -113,6 +113,8 @@
113
113
  const FUNCTION_TYPE = "function";
114
114
  const OBJECT_TYPE = "object";
115
115
 
116
+ const EMPTY_UINT8_ARRAY = new Uint8Array();
117
+
116
118
  /*
117
119
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
118
120
 
@@ -164,6 +166,22 @@
164
166
  DecompressionStream: typeof DecompressionStream != UNDEFINED_TYPE && DecompressionStream
165
167
  };
166
168
 
169
+ const CONFIGURABLE_PROPERTY_NAMES = [
170
+ "baseURI",
171
+ "wasmURI",
172
+ "workerURI",
173
+ "chunkSize",
174
+ "maxWorkers",
175
+ "terminateWorkerTimeout",
176
+ "workerStarvationTimeout",
177
+ "useCompressionStream",
178
+ "useWebWorkers",
179
+ "CompressionStream",
180
+ "DecompressionStream",
181
+ "CompressionStreamZlib",
182
+ "DecompressionStreamZlib"
183
+ ];
184
+
167
185
  const config = Object.assign({}, DEFAULT_CONFIGURATION);
168
186
 
169
187
  function getConfiguration() {
@@ -175,43 +193,15 @@
175
193
  }
176
194
 
177
195
  function configure(configuration) {
178
- const {
179
- baseURI,
180
- chunkSize,
181
- maxWorkers,
182
- terminateWorkerTimeout,
183
- workerStarvationTimeout,
184
- useCompressionStream,
185
- useWebWorkers,
186
- CompressionStream,
187
- DecompressionStream,
188
- CompressionStreamZlib,
189
- DecompressionStreamZlib,
190
- workerURI,
191
- wasmURI
192
- } = configuration;
193
- setIfDefined("baseURI", baseURI);
194
- setIfDefined("wasmURI", wasmURI);
195
- setIfDefined("workerURI", workerURI);
196
- setIfDefined("chunkSize", chunkSize);
197
- setIfDefined("maxWorkers", maxWorkers);
198
- setIfDefined("terminateWorkerTimeout", terminateWorkerTimeout);
199
- setIfDefined("workerStarvationTimeout", workerStarvationTimeout);
200
- setIfDefined("useCompressionStream", useCompressionStream);
201
- setIfDefined("useWebWorkers", useWebWorkers);
202
- setIfDefined("CompressionStream", CompressionStream);
203
- setIfDefined("DecompressionStream", DecompressionStream);
204
- setIfDefined("CompressionStreamZlib", CompressionStreamZlib);
205
- setIfDefined("DecompressionStreamZlib", DecompressionStreamZlib);
206
- }
207
-
208
- function setIfDefined(propertyName, propertyValue) {
209
- if (propertyValue !== UNDEFINED_VALUE) {
210
- config[propertyName] = propertyValue;
211
- }
212
- }
213
-
214
- const A="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";function g(g){g({workerURI:g=>{const B="text/javascript",I=(g=>{g=(g=>{const B=(g=(g+"").replace(/[^A-Za-z0-9+/=]/g,"")).length,I=[];for(let E=0;B>E;E+=4){const B=A.indexOf(g[E])<<18|A.indexOf(g[E+1])<<12|(63&A.indexOf(g[E+2]))<<6|63&A.indexOf(g[E+3]);I.push(B>>16&255),"="!==g[E+2]&&I.push(B>>8&255),"="!==g[E+3]&&I.push(255&B);}return new Uint8Array(I)})(g);let B=new Uint8Array(1024),I=0;for(let A=0;A<g.length;){const C=g[A++];if(128&C){const Y=3+(127&C),Q=g[A++]<<8|g[A++],F=I-Q;E(I+Y);for(let A=0;Y>A;A++)B[I++]=B[F+A];}else {const Y=C;E(I+Y);for(let E=0;Y>E&&A<g.length;E++)B[I++]=g[A++];}}return (g=>{let B="";const I=g.length;let E=0;for(;I>E+2;E+=3){const I=g[E]<<16|g[E+1]<<8|g[E+2];B+=A[I>>18&63]+A[I>>12&63]+A[I>>6&63]+A[63&I];}const C=I-E;if(1===C){const I=g[E]<<16;B+=A[I>>18&63]+A[I>>12&63]+"==";}else if(2===C){const I=g[E]<<16|g[E+1]<<8;B+=A[I>>18&63]+A[I>>12&63]+A[I>>6&63]+"=";}return B})(new Uint8Array(B.buffer.slice(0,I)));function E(A){if(B.length<A){let g=2*B.length;for(;A>g;)g*=2;const E=new Uint8Array(g);E.set(B.subarray(0,I)),B=E;}}})("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");if(g){const A=atob(I),g=new Blob([A],{type:B});return URL.createObjectURL(g)}return "data:"+B+";base64,"+I}});}
196
+ for (const propertyName of CONFIGURABLE_PROPERTY_NAMES) {
197
+ const propertyValue = configuration[propertyName];
198
+ if (propertyValue !== UNDEFINED_VALUE) {
199
+ config[propertyName] = propertyValue;
200
+ }
201
+ }
202
+ }
203
+
204
+ const r=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258],t=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0],o=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],e=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],a=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],h=new Uint8Array(288);h.fill(8,0,144),h.fill(9,144,256),h.fill(7,256,280),h.fill(8,280,288);const l=new Uint8Array(30).fill(5);function n(r){const t=new Uint16Array(16);for(const o of r)t[o]++;t[0]=0;const o=new Uint16Array(17);for(let r=1;15>=r;r++)o[r+1]=o[r]+t[r];const e=new Uint16Array(r.length);for(let t=0;t<r.length;t++)r[t]&&(e[o[r[t]]++]=t);return {t:t,symbols:e}}const s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";function f(f){f({workerURI:f=>{const q="text/javascript",P=(s=>{let f=0,q=0,P=0,V=new Uint8Array(1024),d=0,u=0;for(;!u;){u=H(1);const r=H(2);if(0==r)K();else if(1==r)X(n(h),n(l));else {if(2!=r)throw Error("invalid deflate block type");X(...i());}}return V.subarray(0,d);function G(){if(f>=s.length)throw Error("unexpected end of deflate data");return s[f++]}function H(r){for(;r>P;)q|=G()<<P,P+=8;const t=q&(1<<r)-1;return q>>>=r,P-=r,t}function K(){q=0,P=0;const r=G()|G()<<8;f+=2,y(d+r);for(let t=0;r>t;t++)V[d++]=G();}function X(a,h){let l=b(a);for(;256!=l;){if(256>l)y(d+1),V[d++]=l;else {const a=l-257,n=r[a]+H(t[a]),s=b(h),f=o[s]+H(e[s]);y(d+n);const q=d-f;for(let r=0;n>r;r++)V[d++]=V[q+r];}l=b(a);}}function i(){const r=H(5)+257,t=H(5)+1,o=H(4)+4,e=new Uint8Array(19);for(let r=0;o>r;r++)e[a[r]]=H(3);const h=n(e),l=new Uint8Array(r+t);let s=0;for(;s<l.length;){const r=b(h);if(16>r)l[s++]=r;else if(16==r){const r=l[s-1];let t=H(2)+3;for(;t--;)l[s++]=r;}else s+=17==r?H(3)+3:H(7)+11;}return [n(l.subarray(0,r)),n(l.subarray(r))]}function b(r){const{t:t,symbols:o}=r;let e=0,a=0,h=0;for(let r=1;15>=r;r++){e|=H(1);const l=t[r];if(l>e-a)return o[h+(e-a)];h+=l,a=a+l<<1,e<<=1;}throw Error("invalid huffman code")}function y(r){if(V.length<r){let t=2*V.length;for(;r>t;)t*=2;const o=new Uint8Array(t);o.set(V.subarray(0,d)),V=o;}}})((r=>{const t=(r=(r+"").replace(/[^A-Za-z0-9+/=]/g,"")).length,o=[];for(let e=0;t>e;e+=4){const t=s.indexOf(r[e])<<18|s.indexOf(r[e+1])<<12|(63&s.indexOf(r[e+2]))<<6|63&s.indexOf(r[e+3]);o.push(t>>16&255),"="!==r[e+2]&&o.push(t>>8&255),"="!==r[e+3]&&o.push(255&t);}return new Uint8Array(o)})("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"));if(f){const r=new Blob([P],{type:q});return URL.createObjectURL(r)}return "data:"+q+";base64,"+(r=>{let t="";const o=r.length;let e=0;for(;o>e+2;e+=3){const o=r[e]<<16|r[e+1]<<8|r[e+2];t+=s[o>>18&63]+s[o>>12&63]+s[o>>6&63]+s[63&o];}const a=o-e;if(1===a){const o=r[e]<<16;t+=s[o>>18&63]+s[o>>12&63]+"==";}else if(2===a){const o=r[e]<<16|r[e+1]<<8;t+=s[o>>18&63]+s[o>>12&63]+s[o>>6&63]+"=";}return t})(P)}});}
215
205
 
216
206
  /*
217
207
  Copyright (c) 2022 Gildas Lormeau. All rights reserved.
@@ -1224,8 +1214,6 @@
1224
1214
  if (GET_RANDOM_VALUES_SUPPORTED) {
1225
1215
  return crypto.getRandomValues(array);
1226
1216
  } else {
1227
- // all supported runtimes expose crypto.getRandomValues; failing hard beats
1228
- // silently generating predictable encryption salts
1229
1217
  throw new Error(ERR_UNSUPPORTED_CRYPTO_API);
1230
1218
  }
1231
1219
  }
@@ -1288,12 +1276,7 @@
1288
1276
  constructor({ password, rawPassword, encryptionStrength, checkPasswordOnly }) {
1289
1277
  super({
1290
1278
  start() {
1291
- Object.assign(this, {
1292
- ready: new Promise(resolve => this.resolveReady = resolve),
1293
- password: encodePassword(password, rawPassword),
1294
- strength: encryptionStrength - 1,
1295
- pending: new Uint8Array()
1296
- });
1279
+ initAesCrypto(this, password, rawPassword, encryptionStrength);
1297
1280
  },
1298
1281
  async transform(chunk, controller) {
1299
1282
  const aesCrypto = this;
@@ -1328,7 +1311,7 @@
1328
1311
  await ready;
1329
1312
  const chunkToDecrypt = subarray(pending, 0, pending.length - SIGNATURE_LENGTH);
1330
1313
  const originalSignature = subarray(pending, pending.length - SIGNATURE_LENGTH);
1331
- let decryptedChunkArray = new Uint8Array();
1314
+ let decryptedChunkArray = EMPTY_UINT8_ARRAY;
1332
1315
  if (chunkToDecrypt.length) {
1333
1316
  const encryptedChunk = toBits(codecBytes, chunkToDecrypt);
1334
1317
  hmac.update(encryptedChunk);
@@ -1336,8 +1319,6 @@
1336
1319
  decryptedChunkArray = fromBits(codecBytes, decryptedChunk);
1337
1320
  }
1338
1321
  const signature = subarray(fromBits(codecBytes, hmac.digest()), 0, SIGNATURE_LENGTH);
1339
- // branch-free comparison: accumulate the differences instead of
1340
- // short-circuiting on the first mismatching byte
1341
1322
  let invalidSignature = pending.length < SIGNATURE_LENGTH ? 1 : 0;
1342
1323
  for (let indexSignature = 0; indexSignature < SIGNATURE_LENGTH; indexSignature++) {
1343
1324
  invalidSignature |= signature[indexSignature] ^ originalSignature[indexSignature];
@@ -1359,12 +1340,7 @@
1359
1340
  let stream;
1360
1341
  super({
1361
1342
  start() {
1362
- Object.assign(this, {
1363
- ready: new Promise(resolve => this.resolveReady = resolve),
1364
- password: encodePassword(password, rawPassword),
1365
- strength: encryptionStrength - 1,
1366
- pending: new Uint8Array()
1367
- });
1343
+ initAesCrypto(this, password, rawPassword, encryptionStrength);
1368
1344
  },
1369
1345
  async transform(chunk, controller) {
1370
1346
  const aesCrypto = this;
@@ -1374,7 +1350,7 @@
1374
1350
  resolveReady,
1375
1351
  ready
1376
1352
  } = aesCrypto;
1377
- let preamble = new Uint8Array();
1353
+ let preamble = EMPTY_UINT8_ARRAY;
1378
1354
  if (password) {
1379
1355
  preamble = await createEncryptionKeys(aesCrypto, strength, password);
1380
1356
  resolveReady();
@@ -1394,7 +1370,7 @@
1394
1370
  } = this;
1395
1371
  if (hmac && ctr) {
1396
1372
  await ready;
1397
- let encryptedChunkArray = new Uint8Array();
1373
+ let encryptedChunkArray = EMPTY_UINT8_ARRAY;
1398
1374
  if (pending.length) {
1399
1375
  const encryptedChunk = ctr.update(toBits(codecBytes, pending));
1400
1376
  hmac.update(encryptedChunk);
@@ -1409,6 +1385,15 @@
1409
1385
  }
1410
1386
  }
1411
1387
 
1388
+ function initAesCrypto(aesCrypto, password, rawPassword, encryptionStrength) {
1389
+ Object.assign(aesCrypto, {
1390
+ ready: new Promise(resolve => aesCrypto.resolveReady = resolve),
1391
+ password: encodePassword(password, rawPassword),
1392
+ strength: encryptionStrength - 1,
1393
+ pending: EMPTY_UINT8_ARRAY
1394
+ });
1395
+ }
1396
+
1412
1397
  function append(aesCrypto, input, output, paddingStart, paddingEnd, verifySignature) {
1413
1398
  const {
1414
1399
  ctr,
@@ -1570,20 +1555,13 @@
1570
1555
  constructor({ password, rawPassword, passwordVerification, checkPasswordOnly }) {
1571
1556
  super({
1572
1557
  start() {
1573
- Object.assign(this, {
1574
- password,
1575
- rawPassword,
1576
- passwordVerification
1577
- });
1578
- createKeys(this, password, rawPassword);
1558
+ initZipCrypto(this, password, rawPassword, passwordVerification);
1579
1559
  },
1580
1560
  transform(chunk, controller) {
1581
1561
  const zipCrypto = this;
1582
1562
  if (zipCrypto.password || zipCrypto.rawPassword) {
1583
1563
  const decryptedHeader = decrypt(zipCrypto, chunk.subarray(0, HEADER_LENGTH));
1584
1564
  zipCrypto.password = zipCrypto.rawPassword = null;
1585
- // verify the password with a branch-free comparison of the verification byte, mirroring
1586
- // the constant-time AES HMAC signature check
1587
1565
  if ((decryptedHeader.at(-1) ^ zipCrypto.passwordVerification) != 0) {
1588
1566
  throw new Error(ERR_INVALID_PASSWORD);
1589
1567
  }
@@ -1604,12 +1582,7 @@
1604
1582
  constructor({ password, rawPassword, passwordVerification }) {
1605
1583
  super({
1606
1584
  start() {
1607
- Object.assign(this, {
1608
- password,
1609
- rawPassword,
1610
- passwordVerification
1611
- });
1612
- createKeys(this, password, rawPassword);
1585
+ initZipCrypto(this, password, rawPassword, passwordVerification);
1613
1586
  },
1614
1587
  transform(chunk, controller) {
1615
1588
  const zipCrypto = this;
@@ -1633,6 +1606,15 @@
1633
1606
  }
1634
1607
  }
1635
1608
 
1609
+ function initZipCrypto(zipCrypto, password, rawPassword, passwordVerification) {
1610
+ Object.assign(zipCrypto, {
1611
+ password,
1612
+ rawPassword,
1613
+ passwordVerification
1614
+ });
1615
+ createKeys(zipCrypto, password, rawPassword);
1616
+ }
1617
+
1636
1618
  function decrypt(target, input) {
1637
1619
  const output = new Uint8Array(input.length);
1638
1620
  for (let index = 0; index < input.length; index++) {
@@ -1737,14 +1719,6 @@
1737
1719
  const stream = this;
1738
1720
  let crc32Stream, encryptionStream, gzipCrc32Stream;
1739
1721
  let readable = super.readable;
1740
- // The gzip trailer carries a CRC-32 of the uncompressed data (same polynomial as zip),
1741
- // computed in native code for free during compression. On the native CompressionStream,
1742
- // harvest it instead of running a separate CRC pass: compress as gzip, then strip the
1743
- // fixed 10-byte header and 8-byte trailer to recover the exact raw-deflate payload
1744
- // (byte-identical to a deflate-raw compression) while capturing the CRC. The CRC becomes
1745
- // available at end-of-stream, exactly like Crc32Stream, so nothing downstream (data
1746
- // descriptor, central directory, ZipCrypto) needs it any earlier. Not applied for the
1747
- // pure-JS/WASM ports (a separate slice-by-8 CRC pass is as fast or faster there).
1748
1722
  const useGzipCrc32 = signed && compressed && !deflate64 && (!encrypted || zipCrypto) &&
1749
1723
  Boolean(useCompressionStream && CompressionStream);
1750
1724
  if ((!encrypted || zipCrypto) && signed && !useGzipCrc32) {
@@ -1781,12 +1755,6 @@
1781
1755
  }
1782
1756
  }
1783
1757
 
1784
- // Converts a gzip stream into its raw-deflate payload while capturing the CRC-32 from the gzip
1785
- // trailer. The CompressionStream gzip header is always the fixed 10-byte form (FLG=0, no optional
1786
- // fields) per the Compression Streams spec, so it is stripped by length; the trailer is the last
1787
- // 8 bytes (CRC-32 LE, then ISIZE LE). Bounded memory: at most GZIP_TRAILER_LENGTH bytes are held
1788
- // back across chunks. The signature is read big-endian-agnostically as a number, matching the
1789
- // value Crc32Stream produces, so the writer path is unchanged.
1790
1758
  class GzipToRawDeflateStream extends TransformStream {
1791
1759
 
1792
1760
  constructor() {
@@ -1812,10 +1780,6 @@
1812
1780
  tail = pending;
1813
1781
  return;
1814
1782
  }
1815
- // Emit everything except the trailing GZIP_TRAILER_LENGTH bytes as a standalone,
1816
- // right-sized Uint8Array. Consumers may read chunk.buffer directly (e.g. custom
1817
- // writers), so an aliased subarray of a larger buffer would leak the held-back
1818
- // trailer bytes. Bytes are copied exactly once, into `output` or `tail`.
1819
1783
  const emitLength = available - GZIP_TRAILER_LENGTH;
1820
1784
  const output = new Uint8Array(emitLength);
1821
1785
  const fromTail = Math.min(emitLength, tail.length);
@@ -1904,11 +1868,6 @@
1904
1868
  throw error;
1905
1869
  }
1906
1870
  }
1907
- // The native CompressionStream/DecompressionStream and the pure-JS zlib port do not signal
1908
- // backpressure on their writable side (their `ready` never pends), so a plain pipeThrough drains
1909
- // the whole source into them and peak memory grows with the entry size. Awaiting each write()
1910
- // paces the source to the codec's consumption rate, keeping streaming memory bounded. The WASM
1911
- // codec already backpressures, so this is a no-op cost for it.
1912
1871
  return pipeThroughBackpressured(readable, codecStream);
1913
1872
  }
1914
1873
 
@@ -1916,10 +1875,6 @@
1916
1875
  return readable.pipeThrough(transformStream);
1917
1876
  }
1918
1877
 
1919
- // Like readable.pipeThrough(transformStream), but drives the writable side manually and awaits each
1920
- // write() so that a codec which under-reports backpressure cannot pull the whole source into memory.
1921
- // Errors propagate in both directions: a source error aborts the codec; a downstream cancel/error
1922
- // (surfaced through the codec's writable rejecting) cancels the source.
1923
1878
  function pipeThroughBackpressured(readable, transformStream) {
1924
1879
  const writer = transformStream.writable.getWriter();
1925
1880
  const reader = readable.getReader();
@@ -1948,7 +1903,7 @@
1948
1903
  try {
1949
1904
  await writer.abort(error);
1950
1905
  } catch {
1951
- // the writable may already be errored/closed
1906
+ // ignored: the writable may already be errored/closed
1952
1907
  }
1953
1908
  }
1954
1909
 
@@ -1956,13 +1911,10 @@
1956
1911
  try {
1957
1912
  await reader.cancel(error);
1958
1913
  } catch {
1959
- // the readable may already be errored/closed
1914
+ // ignored: the readable may already be errored/closed
1960
1915
  }
1961
1916
  }
1962
1917
 
1963
- // DecompressionStream implementations can fail with a message-less TypeError on malformed
1964
- // input; give these errors an identifiable message (errors raised by the other stages of
1965
- // the pipeline, e.g. ERR_INVALID_PASSWORD, always carry a message and pass through as-is)
1966
1918
  function mapInflateStreamError(readable) {
1967
1919
  const reader = readable.getReader();
1968
1920
  return new ReadableStream({
@@ -2287,9 +2239,6 @@
2287
2239
  try {
2288
2240
  await initModule(config);
2289
2241
  } catch {
2290
- // The WASM module failed to load. Fall back to the native CompressionStream only if the
2291
- // zlib codec that would otherwise run depends on that module; a self-contained codec
2292
- // supplied through config (e.g. the pure-JS port) stays usable and is kept as requested.
2293
2242
  const ZlibStream = options.codecType.startsWith(CODEC_DEFLATE) ?
2294
2243
  config.CompressionStreamZlib :
2295
2244
  config.DecompressionStreamZlib;
@@ -2367,7 +2316,6 @@
2367
2316
  return resultValue;
2368
2317
  } catch (error) {
2369
2318
  await closeWritable();
2370
- // unblock the pipe watcher if the worker died before closing its end of the stream
2371
2319
  abortPipe();
2372
2320
  try {
2373
2321
  await closed;
@@ -2392,8 +2340,6 @@
2392
2340
  const abortController = new AbortController();
2393
2341
  const { writable, readable } = new TransformStream();
2394
2342
  const closed = readable.pipeTo(writableSource, { preventClose: true, preventAbort: true, signal: abortController.signal });
2395
- // the pipe can fail before `closed` is awaited (e.g. the destination write fails);
2396
- // mark the rejection as handled so it cannot kill the process in the meantime
2397
2343
  closed.catch(() => { });
2398
2344
  return { writable, closed, abortPipe: () => abortController.abort() };
2399
2345
  }
@@ -2486,8 +2432,6 @@
2486
2432
  event.preventDefault();
2487
2433
  }
2488
2434
  const { rejectResult, writer, onTaskFinished } = workerData;
2489
- // the worker is unusable (e.g. its script failed to load); terminate it and
2490
- // fail the current task instead of letting it hang forever
2491
2435
  terminateWorker$1(workerData);
2492
2436
  if (rejectResult) {
2493
2437
  rejectResult(event.error || new Error(event.message || ERROR_EVENT_TYPE));
@@ -2539,8 +2483,6 @@
2539
2483
  async function onMessage({ data }, workerData) {
2540
2484
  const { type, value, messageId, result, error } = data;
2541
2485
  const { reader, writer, resolveResult, rejectResult, onTaskFinished, generation } = workerData;
2542
- // continuations below can settle after the worker slot has been reassigned to a new
2543
- // task (e.g. a pending pull read failing late); they must not touch the new task
2544
2486
  const stale = () => workerData.generation != generation;
2545
2487
  try {
2546
2488
  if (error) {
@@ -2796,26 +2738,24 @@
2796
2738
  class Reader extends Stream {
2797
2739
 
2798
2740
  get readable() {
2741
+ return this.createReadable();
2742
+ }
2743
+
2744
+ createReadable({ offset = 0, size, diskNumberStart, chunkSize = DEFAULT_CHUNK_SIZE } = {}) {
2799
2745
  const reader = this;
2800
- const { chunkSize = DEFAULT_CHUNK_SIZE } = reader;
2801
- const readable = new ReadableStream({
2802
- start() {
2803
- this.chunkOffset = 0;
2804
- },
2746
+ let chunkOffset = 0;
2747
+ return new ReadableStream({
2805
2748
  async pull(controller) {
2806
- const { offset = 0, size, diskNumberStart } = readable;
2807
- const { chunkOffset } = this;
2808
2749
  const dataSize = size === UNDEFINED_VALUE ? chunkSize : Math.min(chunkSize, size - chunkOffset);
2809
2750
  const data = await readUint8Array(reader, offset + chunkOffset, dataSize, diskNumberStart);
2810
2751
  controller.enqueue(data);
2811
2752
  if ((chunkOffset + chunkSize > size) || (size === UNDEFINED_VALUE && !data.length && dataSize)) {
2812
2753
  controller.close();
2813
2754
  } else {
2814
- this.chunkOffset += chunkSize;
2755
+ chunkOffset += chunkSize;
2815
2756
  }
2816
2757
  }
2817
2758
  });
2818
- return readable;
2819
2759
  }
2820
2760
  }
2821
2761
 
@@ -2954,8 +2894,6 @@
2954
2894
  }
2955
2895
  });
2956
2896
  writer.blob = new Response(transformStream.readable, { headers }).blob();
2957
- // mark early rejections (e.g. aborted pipe) as handled; awaiting getData() still
2958
- // surfaces them
2959
2897
  writer.blob.catch(() => { });
2960
2898
  }
2961
2899
 
@@ -3117,7 +3055,7 @@
3117
3055
  return eocdCache;
3118
3056
  }
3119
3057
  if (index >= size || length === 0) {
3120
- return new Uint8Array();
3058
+ return EMPTY_UINT8_ARRAY;
3121
3059
  } else {
3122
3060
  if (index + length > size) {
3123
3061
  length = size - index;
@@ -3174,8 +3112,6 @@
3174
3112
  async function getRequestData(httpReader, sendRequest) {
3175
3113
  const response = await sendRequest(HTTP_METHOD_GET, httpReader, getHeaders(httpReader));
3176
3114
  httpReader.data = new Uint8Array(await response.arrayBuffer());
3177
- // the downloaded content is authoritative, e.g. the Content-Length response header
3178
- // of the HEAD request can be the encoded size when the content is compressed
3179
3115
  httpReader.size = httpReader.data.length;
3180
3116
  }
3181
3117
 
@@ -3240,7 +3176,6 @@
3240
3176
  super();
3241
3177
  Object.assign(this, {
3242
3178
  url,
3243
- // an explicit fetch implementation takes precedence over useXHR
3244
3179
  reader: options.useXHR && !options.fetch ? new XHRReader(url, options) : new FetchReader(url, options)
3245
3180
  });
3246
3181
  }
@@ -3379,7 +3314,7 @@
3379
3314
  }
3380
3315
  }
3381
3316
  } else {
3382
- result = new Uint8Array();
3317
+ result = EMPTY_UINT8_ARRAY;
3383
3318
  }
3384
3319
  reader.lastDiskNumber = Math.max(currentDiskNumber, reader.lastDiskNumber);
3385
3320
  return result;
@@ -3424,8 +3359,6 @@
3424
3359
  writer.diskOffset += diskSourceWriter.size;
3425
3360
  writer.diskNumber++;
3426
3361
  diskWriter = null;
3427
- // the next disk is not opened yet but its space is available; leaving a
3428
- // stale value here would force a new disk for every subsequent write
3429
3362
  writer.availableSize = writer.maxSize;
3430
3363
  if (chunk.length > availableSize) {
3431
3364
  await this.write(chunk.subarray(availableSize));
@@ -3605,7 +3538,6 @@
3605
3538
  if (encoding && encoding.trim().toLowerCase() == "cp437") {
3606
3539
  return decodeCP437(value);
3607
3540
  } else {
3608
- // ignoreBOM keeps a leading U+FEFF in filenames/comments instead of dropping it
3609
3541
  return new TextDecoder(encoding, { ignoreBOM: true }).decode(value);
3610
3542
  }
3611
3543
  }
@@ -3853,8 +3785,6 @@
3853
3785
  const CHARSET_UTF8 = "utf-8";
3854
3786
  const PROPERTY_NAME_UTF8_SUFFIX = "UTF8";
3855
3787
  const CHARSET_CP437 = "cp437";
3856
- // bits of the general purpose flag that change how an entry is interpreted; the level bits (1-2) are excluded
3857
- // because they are informative only
3858
3788
  const BITFLAG_AMBIGUITY_MASK = BITFLAG_ENCRYPTED | BITFLAG_DATA_DESCRIPTOR | BITFLAG_LANG_ENCODING_FLAG;
3859
3789
  const ZIP64_PROPERTIES = [
3860
3790
  [PROPERTY_NAME_UNCOMPRESSED_SIZE, MAX_32_BITS],
@@ -3896,7 +3826,6 @@
3896
3826
  if (reader.size < END_OF_CENTRAL_DIR_LENGTH) {
3897
3827
  throw new Error(ERR_BAD_FORMAT);
3898
3828
  }
3899
- reader.chunkSize = getChunkSize(config);
3900
3829
  const strictness = getStrictness(getOptionValue$1(zipReader, options, OPTION_STRICTNESS), getOptionValue$1(zipReader, options, OPTION_CHECK_AMBIGUITY));
3901
3830
  const checkAmbiguity = strictness == STRICTNESS_STRICT;
3902
3831
  const rejectAmbiguousEndOfDirectory = strictness != STRICTNESS_TOLERANT;
@@ -3911,8 +3840,6 @@
3911
3840
  throw new Error(ERR_EOCDR_NOT_FOUND);
3912
3841
  }
3913
3842
  }
3914
- // two or more end-anchored records that each dereference to a valid central directory cannot be told
3915
- // apart (see comment_length ⟺ EOF): the archive is genuinely ambiguous, so refuse rather than guess
3916
3843
  if (rejectAmbiguousEndOfDirectory && endOfDirectoryReachingEndCount > 1) {
3917
3844
  throwAmbiguousArchive("multiple end of central directory records");
3918
3845
  }
@@ -3935,7 +3862,7 @@
3935
3862
  if (directoryDataOffset == MAX_32_BITS || directoryDataLength == MAX_32_BITS || filesLength == MAX_16_BITS || diskNumber == MAX_16_BITS) {
3936
3863
  const endOfDirectoryLocatorArray = endOfDirectoryInfo.offset >= ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH ?
3937
3864
  await readUint8Array(reader, endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH) :
3938
- new Uint8Array();
3865
+ EMPTY_UINT8_ARRAY;
3939
3866
  const endOfDirectoryLocatorView = getDataView$1(endOfDirectoryLocatorArray);
3940
3867
  if (endOfDirectoryLocatorArray.length == ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH &&
3941
3868
  getUint32(endOfDirectoryLocatorView, 0) == ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE) {
@@ -4002,12 +3929,6 @@
4002
3929
  }
4003
3930
  const expectedDirectoryDataOffset = centralDirectoryEndOffset - directoryDataLength - (reader.lastDiskOffset || 0);
4004
3931
  if (directoryDataOffset != expectedDirectoryDataOffset && diskNumber == lastDiskNumber) {
4005
- // the reconciled offset (the directory ends exactly where the canonical record begins) is anchored
4006
- // to the unforgeable end of the archive; the stored offset is not. Prefer the reconciled offset
4007
- // unless the stored one points at a directory and the reconciled one does not — that exception
4008
- // keeps a corrupt declared directory length from sending the read astray, while still moving off a
4009
- // stored offset that only looks valid because an append remnant left the previous (identically
4010
- // laid out) directory sitting there.
4011
3932
  const storedPointsAtDirectory = getUint32(directoryView, offset) == CENTRAL_FILE_HEADER_SIGNATURE;
4012
3933
  let reconcile = !storedPointsAtDirectory;
4013
3934
  if (!reconcile && expectedDirectoryDataOffset >= 0 && expectedDirectoryDataOffset + 4 <= reader.size) {
@@ -4164,11 +4085,11 @@
4164
4085
  const extractPrependedData = getOptionValue$1(zipReader, options, OPTION_EXTRACT_PREPENDED_DATA);
4165
4086
  const extractAppendedData = getOptionValue$1(zipReader, options, OPTION_EXTRACT_APPENDED_DATA);
4166
4087
  if (extractPrependedData) {
4167
- zipReader.prependedData = startOffset > 0 ? await readUint8Array(reader, 0, startOffset) : new Uint8Array();
4088
+ zipReader.prependedData = startOffset > 0 ? await readUint8Array(reader, 0, startOffset) : EMPTY_UINT8_ARRAY;
4168
4089
  }
4169
- zipReader.comment = commentLength ? await readUint8Array(reader, commentOffset + END_OF_CENTRAL_DIR_LENGTH, commentLength) : new Uint8Array();
4090
+ zipReader.comment = commentLength ? await readUint8Array(reader, commentOffset + END_OF_CENTRAL_DIR_LENGTH, commentLength) : EMPTY_UINT8_ARRAY;
4170
4091
  if (extractAppendedData) {
4171
- zipReader.appendedData = appendedDataOffset < reader.size ? await readUint8Array(reader, appendedDataOffset, reader.size - appendedDataOffset) : new Uint8Array();
4092
+ zipReader.appendedData = appendedDataOffset < reader.size ? await readUint8Array(reader, appendedDataOffset, reader.size - appendedDataOffset) : EMPTY_UINT8_ARRAY;
4172
4093
  }
4173
4094
  return true;
4174
4095
  }
@@ -4280,7 +4201,7 @@
4280
4201
  filenameLength
4281
4202
  } = localDirectory;
4282
4203
  const checkAmbiguity = getStrictness(getOptionValue$1(zipEntry, options, OPTION_STRICTNESS), getOptionValue$1(zipEntry, options, OPTION_CHECK_AMBIGUITY)) == STRICTNESS_STRICT;
4283
- let rawLocalFilename = new Uint8Array();
4204
+ let rawLocalFilename = EMPTY_UINT8_ARRAY;
4284
4205
  if (checkAmbiguity && (filenameLength || extraFieldLength)) {
4285
4206
  const trailingDataArray = await readUint8Array(reader, offset + HEADER_SIZE, filenameLength + extraFieldLength, diskNumberStart);
4286
4207
  rawLocalFilename = trailingDataArray.subarray(0, filenameLength);
@@ -4288,7 +4209,7 @@
4288
4209
  } else {
4289
4210
  localDirectory.rawExtraField = extraFieldLength ?
4290
4211
  await readUint8Array(reader, offset + HEADER_SIZE + filenameLength, extraFieldLength, diskNumberStart) :
4291
- new Uint8Array();
4212
+ EMPTY_UINT8_ARRAY;
4292
4213
  }
4293
4214
  readCommonFooter(zipEntry, localDirectory, dataView, 4, true);
4294
4215
  if (checkAmbiguity) {
@@ -4315,12 +4236,7 @@
4315
4236
  }
4316
4237
  const dataOffset = offset + HEADER_SIZE + filenameLength + extraFieldLength;
4317
4238
  const size = compressedSize;
4318
- const readable = reader.readable;
4319
- Object.assign(readable, {
4320
- diskNumberStart,
4321
- offset: dataOffset,
4322
- size
4323
- });
4239
+ const readable = reader.createReadable({ offset: dataOffset, size, diskNumberStart, chunkSize: getChunkSize(config) });
4324
4240
  const signal = getOptionValue$1(zipEntry, options, OPTION_SIGNAL);
4325
4241
  const checkPasswordOnly = getOptionValue$1(zipEntry, options, OPTION_CHECK_PASSWORD_ONLY);
4326
4242
  let checkOverlappingEntry = getOptionValue$1(zipEntry, options, OPTION_CHECK_OVERLAPPING_ENTRY);
@@ -4591,7 +4507,6 @@
4591
4507
  const view = getDataView$1(new Uint8Array(extraField.data));
4592
4508
  let uid, gid;
4593
4509
  if (isInfoZip) {
4594
- // Info-ZIP New Unix "ux" field (0x7875): version + variable-length uid/gid
4595
4510
  let offset = 0;
4596
4511
  const version = getUint8(view, offset++);
4597
4512
  const uidSize = getUint8(view, offset++);
@@ -4601,8 +4516,6 @@
4601
4516
  gid = unpackUnixId(extraField.data.subarray(offset, offset + gidSize));
4602
4517
  Object.assign(extraField, { version, uid, gid });
4603
4518
  } else if (extraField.data.length >= 4) {
4604
- // Info-ZIP Unix "Ux" field (0x7855): fixed 2-byte uid + gid (the file mode, if any, is
4605
- // carried in the external file attributes, not here)
4606
4519
  uid = getUint16(view, 0);
4607
4520
  gid = getUint16(view, 2);
4608
4521
  Object.assign(extraField, { uid, gid });
@@ -4654,7 +4567,6 @@
4654
4567
  timeProperties.forEach((propertyName, indexProperty) => {
4655
4568
  if (extraFieldExtendedTimestamp.data.length >= offset + 4) {
4656
4569
  const time = getUint32(extraFieldView, offset);
4657
- // the extended timestamp is a signed 32-bit time_t value
4658
4570
  directory[propertyName] = extraFieldExtendedTimestamp[propertyName] = new Date((time | 0) * 1000);
4659
4571
  const rawPropertyName = timeRawProperties[indexProperty];
4660
4572
  extraFieldExtendedTimestamp[rawPropertyName] = time;
@@ -4731,7 +4643,6 @@
4731
4643
 
4732
4644
  function getStrictness(strictness, checkAmbiguity) {
4733
4645
  if (strictness === UNDEFINED_VALUE) {
4734
- // `checkAmbiguity: true` is kept as a backward-compatible alias for the strictest mode
4735
4646
  return checkAmbiguity ? STRICTNESS_STRICT : STRICTNESS_BALANCED;
4736
4647
  }
4737
4648
  return strictness;
@@ -4742,81 +4653,45 @@
4742
4653
  return maxAppendedDataSize;
4743
4654
  }
4744
4655
  if (strictness == STRICTNESS_STRICT) {
4745
- // the comment must reach the end of the file: no trailing data tolerated
4746
4656
  return 0;
4747
4657
  }
4748
4658
  if (strictness == STRICTNESS_TOLERANT) {
4749
4659
  return Infinity;
4750
4660
  }
4751
- // balanced: tolerate up to a legal comment's worth of trailing data (a 16-bit length); beyond that the
4752
- // trailing bytes cannot hide inside a comment, so they are treated as a second thing bolted onto the file
4753
4661
  return MAX_16_BITS;
4754
4662
  }
4755
4663
 
4756
- // cap on how many out-of-window central directory probes the scan below may issue. A legitimate archive needs
4757
- // at most a couple (the canonical record, plus one more to detect genuine ambiguity); every other reachability
4758
- // check is served from the tail window already in memory. The cap keeps an archive whose comment is stuffed
4759
- // with unreachable end-anchored records from forcing an unbounded number of (potentially remote) reads.
4760
4664
  const MAX_END_OF_CENTRAL_DIR_PROBES = 64;
4761
4665
 
4762
- // reachability rankings for an end-anchored candidate record (see getCentralDirectoryReachability)
4763
4666
  const CENTRAL_DIRECTORY_UNREACHABLE = 0;
4764
4667
  const CENTRAL_DIRECTORY_PLAUSIBLE = 1;
4765
4668
  const CENTRAL_DIRECTORY_REACHABLE = 2;
4766
4669
 
4767
- // Locates the authoritative end of central directory record. The canonical record is the last one whose
4768
- // declared comment reaches exactly the end of the file ("end-anchored") and that points to a central directory
4769
- // ("reachable"); earlier signatures (stale append remnants, bytes embedded in a comment) are ignored. When two
4770
- // or more end-anchored records point to a central directory the archive is ambiguous, and the count is returned
4771
- // so the caller can refuse it. A record that reaches the end of the file but points to no central directory (an
4772
- // empty archive) is only "plausible": it cannot be corroborated, so it never counts towards ambiguity and is
4773
- // chosen only when no reachable record exists — otherwise an empty record forged in a comment could outrank the
4774
- // genuine directory. When no record is end-anchored (appended data or an oversized comment), falls back to the
4775
- // last record within the tolerated window that points to a directory (see seekEndOfCentralDirectory).
4776
4670
  async function findEndOfCentralDirectory(reader, rejectAmbiguous, maxAppendedDataSize) {
4777
4671
  const { size } = reader;
4778
- // an end-anchored record can only live within the last END_OF_CENTRAL_DIR_LENGTH + MAX_16_BITS bytes,
4779
- // since the comment length that ties it to the end of the file is a 16-bit field
4780
4672
  const anchoredLength = Math.min(size, END_OF_CENTRAL_DIR_LENGTH + MAX_16_BITS);
4781
- const anchoredOffset = size - anchoredLength;
4782
- const anchoredArray = await readUint8Array(reader, anchoredOffset, anchoredLength);
4783
- const anchoredView = getDataView$1(anchoredArray);
4784
4673
  const remoteProbeBudget = { count: MAX_END_OF_CENTRAL_DIR_PROBES };
4785
4674
  let endOfDirectoryInfo;
4786
4675
  let plausibleEndOfDirectoryInfo;
4787
4676
  let endOfDirectoryReachingEndCount = 0;
4788
- for (let indexByte = anchoredArray.length - END_OF_CENTRAL_DIR_LENGTH; indexByte >= 0; indexByte--) {
4789
- if (getUint32(anchoredView, indexByte) == END_OF_CENTRAL_DIR_SIGNATURE) {
4790
- const offset = anchoredOffset + indexByte;
4791
- const commentLength = getUint16(anchoredView, indexByte + 20);
4792
- // end-anchored: the declared comment extends exactly to the end of the file. The comment length is
4793
- // attacker-controlled, but the reconciliation against the (unforgeable) end of file is not.
4794
- if (offset + END_OF_CENTRAL_DIR_LENGTH + commentLength == size) {
4795
- const reachability = await getCentralDirectoryReachability(reader, anchoredView, anchoredOffset, indexByte, offset, size, remoteProbeBudget);
4796
- if (reachability == CENTRAL_DIRECTORY_REACHABLE) {
4797
- if (!endOfDirectoryInfo) {
4798
- endOfDirectoryInfo = {
4799
- offset,
4800
- buffer: anchoredArray.slice(indexByte, indexByte + END_OF_CENTRAL_DIR_LENGTH).buffer
4801
- };
4802
- }
4803
- endOfDirectoryReachingEndCount++;
4804
- // the canonical record (highest offset) is found first; a second one is enough to flag ambiguity
4805
- if (!rejectAmbiguous || endOfDirectoryReachingEndCount > 1) {
4806
- break;
4807
- }
4808
- } else if (reachability == CENTRAL_DIRECTORY_PLAUSIBLE && !plausibleEndOfDirectoryInfo) {
4809
- plausibleEndOfDirectoryInfo = {
4810
- offset,
4811
- buffer: anchoredArray.slice(indexByte, indexByte + END_OF_CENTRAL_DIR_LENGTH).buffer
4812
- };
4677
+ for await (const [anchoredView, anchoredOffset, anchoredArray, indexByte, offset] of scanEndOfCentralDirectory(reader, anchoredLength)) {
4678
+ const commentLength = getUint16(anchoredView, indexByte + 20);
4679
+ if (offset + END_OF_CENTRAL_DIR_LENGTH + commentLength == size) {
4680
+ const reachability = await getCentralDirectoryReachability(reader, anchoredView, anchoredOffset, indexByte, offset, size, remoteProbeBudget);
4681
+ if (reachability == CENTRAL_DIRECTORY_REACHABLE) {
4682
+ if (!endOfDirectoryInfo) {
4683
+ endOfDirectoryInfo = getEndOfCentralDirectoryInfo(anchoredArray, indexByte, offset);
4684
+ }
4685
+ endOfDirectoryReachingEndCount++;
4686
+ if (!rejectAmbiguous || endOfDirectoryReachingEndCount > 1) {
4687
+ break;
4813
4688
  }
4689
+ } else if (reachability == CENTRAL_DIRECTORY_PLAUSIBLE && !plausibleEndOfDirectoryInfo) {
4690
+ plausibleEndOfDirectoryInfo = getEndOfCentralDirectoryInfo(anchoredArray, indexByte, offset);
4814
4691
  }
4815
4692
  }
4816
4693
  }
4817
4694
  if (!endOfDirectoryInfo) {
4818
- // no record points to a directory: prefer a plausible (empty) end-anchored record before scanning the
4819
- // tolerated window for a bare signature
4820
4695
  endOfDirectoryInfo = plausibleEndOfDirectoryInfo;
4821
4696
  }
4822
4697
  if (!endOfDirectoryInfo) {
@@ -4825,69 +4700,53 @@
4825
4700
  return { endOfDirectoryInfo, endOfDirectoryReachingEndCount };
4826
4701
  }
4827
4702
 
4828
- // Fallback for findEndOfCentralDirectory when no record is end-anchored: appended data or an oversized comment
4829
- // pushed the record's declared comment past the end of the file, so its position can no longer be reconciled
4830
- // against the end of the file. Scans the tolerated window from the end and returns the first record that points
4831
- // to a central directory, so a stray signature embedded in appended data cannot hijack discovery (which the
4832
- // anchored scan already prevents for anchored records). Falls back to the first plausible (empty) record, then
4833
- // to the last bare signature, so a degenerate archive still opens as before. The window ends at the file, so the
4834
- // same in-window / metered reads as the anchored scan apply.
4835
4703
  async function seekEndOfCentralDirectory(reader, maxAppendedDataSize, remoteProbeBudget) {
4836
4704
  const { size } = reader;
4837
4705
  const searchLength = Math.min(size, maxAppendedDataSize == Infinity ? size :
4838
4706
  END_OF_CENTRAL_DIR_LENGTH + MAX_16_BITS + maxAppendedDataSize);
4839
- const searchOffset = size - searchLength;
4840
- const searchArray = await readUint8Array(reader, searchOffset, searchLength);
4841
- const searchView = getDataView$1(searchArray);
4842
4707
  let firstSignatureInfo, plausibleInfo;
4843
- for (let indexByte = searchArray.length - END_OF_CENTRAL_DIR_LENGTH; indexByte >= 0; indexByte--) {
4844
- if (getUint32(searchView, indexByte) == END_OF_CENTRAL_DIR_SIGNATURE) {
4845
- const offset = searchOffset + indexByte;
4846
- const record = { offset, buffer: searchArray.slice(indexByte, indexByte + END_OF_CENTRAL_DIR_LENGTH).buffer };
4847
- if (!firstSignatureInfo) {
4848
- firstSignatureInfo = record;
4849
- }
4850
- const reachability = await getCentralDirectoryReachability(reader, searchView, searchOffset, indexByte, offset, size, remoteProbeBudget);
4851
- if (reachability == CENTRAL_DIRECTORY_REACHABLE) {
4852
- return record;
4853
- }
4854
- if (reachability == CENTRAL_DIRECTORY_PLAUSIBLE && !plausibleInfo) {
4855
- plausibleInfo = record;
4856
- }
4708
+ for await (const [searchView, searchOffset, searchArray, indexByte, offset] of scanEndOfCentralDirectory(reader, searchLength)) {
4709
+ const record = getEndOfCentralDirectoryInfo(searchArray, indexByte, offset);
4710
+ if (!firstSignatureInfo) {
4711
+ firstSignatureInfo = record;
4712
+ }
4713
+ const reachability = await getCentralDirectoryReachability(reader, searchView, searchOffset, indexByte, offset, size, remoteProbeBudget);
4714
+ if (reachability == CENTRAL_DIRECTORY_REACHABLE) {
4715
+ return record;
4716
+ }
4717
+ if (reachability == CENTRAL_DIRECTORY_PLAUSIBLE && !plausibleInfo) {
4718
+ plausibleInfo = record;
4857
4719
  }
4858
4720
  }
4859
4721
  return plausibleInfo || firstSignatureInfo;
4860
4722
  }
4861
4723
 
4862
- // Ranks how strongly an end-anchored candidate record is backed by an actual central directory, used to decide
4863
- // which record is canonical and which count towards ambiguity. It is intentionally conservative and does not
4864
- // fully parse the directory (the caller does that for the canonical record):
4865
- // - REACHABLE: the record dereferences a central directory (a central file header signature at the
4866
- // reconciled offset), or, for a zip64 record, the zip64 locator that a genuine zip64 archive places
4867
- // immediately before it. Only these count towards ambiguity.
4868
- // - PLAUSIBLE: the record describes an empty archive, which has no central directory to dereference. Its
4869
- // fields are indistinguishable from an empty end of central directory record forged inside a comment, so it
4870
- // is accepted only as a last resort and never inflates the ambiguity count.
4871
- // - UNREACHABLE: neither — stale append remnant or signature bytes embedded in a comment.
4872
- // Signatures are read from the tail window (`view`, spanning `[anchoredOffset, size)`) when they fall inside it;
4873
- // only a target below the window costs a (possibly remote) read, metered by `remoteProbeBudget` so a stuffed
4874
- // comment cannot amplify into an unbounded number of requests.
4724
+ async function* scanEndOfCentralDirectory(reader, scanLength) {
4725
+ const scanOffset = reader.size - scanLength;
4726
+ const scanArray = await readUint8Array(reader, scanOffset, scanLength);
4727
+ const scanView = getDataView$1(scanArray);
4728
+ for (let indexByte = scanArray.length - END_OF_CENTRAL_DIR_LENGTH; indexByte >= 0; indexByte--) {
4729
+ if (getUint32(scanView, indexByte) == END_OF_CENTRAL_DIR_SIGNATURE) {
4730
+ yield [scanView, scanOffset, scanArray, indexByte, scanOffset + indexByte];
4731
+ }
4732
+ }
4733
+ }
4734
+
4735
+ function getEndOfCentralDirectoryInfo(scanArray, indexByte, offset) {
4736
+ return { offset, buffer: scanArray.slice(indexByte, indexByte + END_OF_CENTRAL_DIR_LENGTH).buffer };
4737
+ }
4738
+
4875
4739
  async function getCentralDirectoryReachability(reader, view, anchoredOffset, indexByte, offset, size, remoteProbeBudget) {
4876
4740
  const filesLength = getUint16(view, indexByte + 10);
4877
4741
  const directoryDataLength = getUint32(view, indexByte + 12);
4878
4742
  const directoryDataOffset = getUint32(view, indexByte + 16);
4879
4743
  if (filesLength == MAX_16_BITS || directoryDataLength == MAX_32_BITS || directoryDataOffset == MAX_32_BITS) {
4880
- // saturated fields imply a zip64 record; corroborate it with the zip64 end of central directory locator
4881
- // that sits immediately before it, so saturated bytes inside a comment cannot masquerade as one
4882
4744
  const locatorSignature = await readSignature(reader, view, anchoredOffset, offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH, size, remoteProbeBudget);
4883
4745
  return locatorSignature == ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE ? CENTRAL_DIRECTORY_REACHABLE : CENTRAL_DIRECTORY_UNREACHABLE;
4884
4746
  }
4885
4747
  if (!filesLength && !directoryDataLength) {
4886
- // a valid empty archive has no central directory to dereference
4887
4748
  return CENTRAL_DIRECTORY_PLAUSIBLE;
4888
4749
  }
4889
- // the central directory ends where this record starts; reconcile the stored offset against that actual
4890
- // position (see stored_cd_offset ⟺ eocd_pos − cd_size) so prepended data does not hide the directory
4891
4750
  for (const centralDirectoryOffset of [offset - directoryDataLength, directoryDataOffset]) {
4892
4751
  if (await readSignature(reader, view, anchoredOffset, centralDirectoryOffset, size, remoteProbeBudget) == CENTRAL_FILE_HEADER_SIGNATURE) {
4893
4752
  return CENTRAL_DIRECTORY_REACHABLE;
@@ -4896,15 +4755,11 @@
4896
4755
  return CENTRAL_DIRECTORY_UNREACHABLE;
4897
4756
  }
4898
4757
 
4899
- // Reads a 4-byte little-endian signature at `signatureOffset`, served from the tail window (`view`, spanning
4900
- // `[anchoredOffset, size)`) when it falls inside it and otherwise from a metered (possibly remote) read. Returns
4901
- // UNDEFINED_VALUE when the position is out of range or the out-of-window read budget is exhausted.
4902
4758
  async function readSignature(reader, view, anchoredOffset, signatureOffset, size, remoteProbeBudget) {
4903
4759
  if (signatureOffset < 0 || signatureOffset + 4 > size) {
4904
4760
  return UNDEFINED_VALUE;
4905
4761
  }
4906
4762
  if (signatureOffset >= anchoredOffset) {
4907
- // the target sits inside the tail window already in memory: no extra read needed
4908
4763
  return getUint32(view, signatureOffset - anchoredOffset);
4909
4764
  }
4910
4765
  if (remoteProbeBudget.count > 0) {
@@ -4912,7 +4767,6 @@
4912
4767
  const signatureArray = await readUint8Array(reader, signatureOffset, 4);
4913
4768
  return getUint32(getDataView$1(signatureArray), 0);
4914
4769
  }
4915
- // out of budget: leave this candidate unverified rather than issue another read
4916
4770
  return UNDEFINED_VALUE;
4917
4771
  }
4918
4772
 
@@ -4928,8 +4782,6 @@
4928
4782
  if (localDirectory.compressionMethod != zipEntry.compressionMethod) {
4929
4783
  throwAmbiguousArchive("mismatched local file header (compression method)");
4930
4784
  }
4931
- // when the data descriptor flag is set, the local signature and sizes are zeroed out; all-zero values are
4932
- // also tolerated when the flag is clear because some tools produce them (streaming writers predating bit 3)
4933
4785
  if (!localDirectory.bitFlag.dataDescriptor &&
4934
4786
  (localDirectory.signature || localDirectory.compressedSize || localDirectory.uncompressedSize) &&
4935
4787
  (localDirectory.signature != zipEntry.signature ||
@@ -5019,7 +4871,6 @@
5019
4871
  const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3";
5020
4872
  const ERR_INVALID_EXTRAFIELD_TYPE = "Extra field type exceeds 65535";
5021
4873
  const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB";
5022
- // same message as the constant exported by zip-reader.js
5023
4874
  const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
5024
4875
  const MIN_UNIX_TIME = -2147483648;
5025
4876
  const MAX_UNIX_TIME = 2147483647;
@@ -5102,12 +4953,12 @@
5102
4953
  rawExtraField,
5103
4954
  } = entry;
5104
4955
  const { level, languageEncodingFlag, dataDescriptor } = bitFlag;
5105
- rawExtraFieldZip64 = rawExtraFieldZip64 || new Uint8Array();
5106
- rawExtraFieldAES = rawExtraFieldAES || new Uint8Array();
5107
- rawExtraFieldExtendedTimestamp = rawExtraFieldExtendedTimestamp || new Uint8Array();
5108
- rawExtraFieldNTFS = rawExtraFieldNTFS || new Uint8Array();
5109
- rawExtraFieldUnix = rawExtraFieldUnix || new Uint8Array();
5110
- rawExtraField = rawExtraField || new Uint8Array();
4956
+ rawExtraFieldZip64 = rawExtraFieldZip64 || EMPTY_UINT8_ARRAY;
4957
+ rawExtraFieldAES = rawExtraFieldAES || EMPTY_UINT8_ARRAY;
4958
+ rawExtraFieldExtendedTimestamp = rawExtraFieldExtendedTimestamp || EMPTY_UINT8_ARRAY;
4959
+ rawExtraFieldNTFS = rawExtraFieldNTFS || EMPTY_UINT8_ARRAY;
4960
+ rawExtraFieldUnix = rawExtraFieldUnix || EMPTY_UINT8_ARRAY;
4961
+ rawExtraField = rawExtraField || EMPTY_UINT8_ARRAY;
5111
4962
  if (entry.extraFieldAES) {
5112
4963
  compressionMethod = COMPRESSION_METHOD_AES;
5113
4964
  }
@@ -5213,7 +5064,7 @@
5213
5064
  return false;
5214
5065
  }
5215
5066
 
5216
- async close(comment = new Uint8Array(), options = {}) {
5067
+ async close(comment = EMPTY_UINT8_ARRAY, options = {}) {
5217
5068
  const zipWriter = this;
5218
5069
  const { pendingAddFileCalls, writer } = this;
5219
5070
  const { writable } = writer;
@@ -5512,7 +5363,7 @@
5512
5363
  if (!zipCrypto && (password !== UNDEFINED_VALUE || rawPassword !== UNDEFINED_VALUE) && !(encryptionStrength >= 1 && encryptionStrength <= 3)) {
5513
5364
  throw new Error(ERR_INVALID_ENCRYPTION_STRENGTH);
5514
5365
  }
5515
- let rawExtraField = new Uint8Array();
5366
+ let rawExtraField = EMPTY_UINT8_ARRAY;
5516
5367
  const extraField = options[PROPERTY_NAME_EXTRA_FIELD];
5517
5368
  if (extraField) {
5518
5369
  let extraFieldSize = 0;
@@ -5573,8 +5424,6 @@
5573
5424
  let maximumCompressedSize = 0;
5574
5425
  let uncompressedSize = 0;
5575
5426
  if (passThrough) {
5576
- // the headers of a passThrough entry describe the payload verbatim: without a
5577
- // reader they would declare content that is not there
5578
5427
  if (!reader) {
5579
5428
  throw new Error(ERR_UNDEFINED_READER);
5580
5429
  }
@@ -5585,8 +5434,6 @@
5585
5434
  }
5586
5435
  const zip64Enabled = zip64 === true;
5587
5436
  const encrypted = getOptionValue(zipWriter, options, PROPERTY_NAME_ENCRYPTED);
5588
- // entries without a reader have no payload: write them as empty stored files instead of
5589
- // declaring a compressed or encrypted content that does not exist
5590
5437
  const encryptedEntry = Boolean(reader) && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
5591
5438
  if (!reader) {
5592
5439
  level = 0;
@@ -5724,7 +5571,6 @@
5724
5571
  fileEntry.diskNumberStart = writer.diskNumber;
5725
5572
  fileEntry.offset = getSegmentOffset(zipWriter, writer);
5726
5573
  if (usdz) {
5727
- // the padding depends on the entry offset, only known now that the writer is locked
5728
5574
  const previousMetadataSize = entryInfo.metadataSize;
5729
5575
  appendExtraFieldUSDZ(entryInfo, zipWriter.offset - writer.diskOffset);
5730
5576
  fileEntry.size += entryInfo.metadataSize - previousMetadataSize;
@@ -5767,10 +5613,6 @@
5767
5613
  if (releaseLockWriter) {
5768
5614
  releaseLockWriter();
5769
5615
  }
5770
- // A buffered entry uses a temporary stream (see `createTempStream`). When that stream is
5771
- // backed by a resource (a file, an OPFS handle, ...) it must be released on every exit path,
5772
- // including the error path where the stream is otherwise abandoned without being closed or
5773
- // cancelled. `dispose()` is optional and best-effort so it never masks the original outcome.
5774
5616
  if (bufferedWrite && fileWriter && fileWriter.dispose) {
5775
5617
  try {
5776
5618
  await fileWriter.dispose();
@@ -5797,7 +5639,7 @@
5797
5639
  async function skipDiskIfNeeded() {
5798
5640
  if (getLength(headerInfo.localHeaderArray) > writer.availableSize) {
5799
5641
  writer.availableSize = 0;
5800
- await writeData(writer, new Uint8Array());
5642
+ await writeData(writer, EMPTY_UINT8_ARRAY);
5801
5643
  }
5802
5644
  }
5803
5645
  }
@@ -5908,8 +5750,7 @@
5908
5750
  }
5909
5751
  const { writable } = writer;
5910
5752
  if (reader) {
5911
- reader.chunkSize = getChunkSize(config);
5912
- const readable = reader.readable;
5753
+ const readable = reader.createReadable ? reader.createReadable({ chunkSize: getChunkSize(config) }) : reader.readable;
5913
5754
  const size = reader.size;
5914
5755
  const workerOptions = {
5915
5756
  options: {
@@ -6009,13 +5850,9 @@
6009
5850
  : compressionMethod !== COMPRESSION_METHOD_STORE);
6010
5851
  let rawLocalExtraFieldZip64;
6011
5852
  const uncompressedFile = passThrough || !compressed;
6012
- // entries without a data descriptor are always buffered (cf. getFileEntry), so the
6013
- // zip64 extra field values can be patched into the local header before flushing it
6014
5853
  const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || !dataDescriptor || ((!zip64UncompressedSize && !zip64CompressedSize) || uncompressedFile));
6015
5854
  const writeLocalExtraFieldZip64 = zip64ExtraFieldComplete || (zip64 && dataDescriptor && (zip64UncompressedSize || zip64CompressedSize));
6016
5855
  if (zip64 && (zip64UncompressedSize || zip64CompressedSize)) {
6017
- // APPNOTE 4.5.3: the zip64 extra field of a local header must include both the
6018
- // uncompressed and compressed size fields
6019
5856
  const length = 4 + 16;
6020
5857
  const extraFieldZip64 = createRecordWriter(length);
6021
5858
  extraFieldZip64.uint16(EXTRAFIELD_TYPE_ZIP64);
@@ -6029,7 +5866,7 @@
6029
5866
  }
6030
5867
  }
6031
5868
  } else {
6032
- rawLocalExtraFieldZip64 = new Uint8Array();
5869
+ rawLocalExtraFieldZip64 = EMPTY_UINT8_ARRAY;
6033
5870
  }
6034
5871
  let rawExtraFieldAES;
6035
5872
  if (encrypted && !zipCrypto) {
@@ -6039,7 +5876,7 @@
6039
5876
  rawExtraFieldAES = extraFieldAES.array;
6040
5877
  rawExtraFieldAES[8] = encryptionStrength;
6041
5878
  } else {
6042
- rawExtraFieldAES = new Uint8Array();
5879
+ rawExtraFieldAES = EMPTY_UINT8_ARRAY;
6043
5880
  }
6044
5881
  let rawExtraFieldNTFS;
6045
5882
  let rawExtraFieldExtendedTimestamp;
@@ -6062,8 +5899,7 @@
6062
5899
  }
6063
5900
  rawExtraFieldExtendedTimestamp = extraFieldTimestamp.array;
6064
5901
  } else {
6065
- // the date cannot be stored as a 32-bit time_t; the NTFS field replaces it
6066
- rawExtraFieldExtendedTimestamp = new Uint8Array();
5902
+ rawExtraFieldExtendedTimestamp = EMPTY_UINT8_ARRAY;
6067
5903
  }
6068
5904
  try {
6069
5905
  const lastModTimeNTFS = getTimeNTFS(lastModDate);
@@ -6078,10 +5914,10 @@
6078
5914
  extraFieldNTFS.uint64(getTimeNTFS(creationDate) || lastModTimeNTFS);
6079
5915
  rawExtraFieldNTFS = extraFieldNTFS.array;
6080
5916
  } catch {
6081
- rawExtraFieldNTFS = new Uint8Array();
5917
+ rawExtraFieldNTFS = EMPTY_UINT8_ARRAY;
6082
5918
  }
6083
5919
  } else {
6084
- rawExtraFieldNTFS = rawExtraFieldExtendedTimestamp = new Uint8Array();
5920
+ rawExtraFieldNTFS = rawExtraFieldExtendedTimestamp = EMPTY_UINT8_ARRAY;
6085
5921
  }
6086
5922
  let rawExtraFieldUnix;
6087
5923
  try {
@@ -6107,10 +5943,10 @@
6107
5943
  extraFieldUnix.uint16((gid === UNDEFINED_VALUE ? 0 : gid) & MAX_16_BITS);
6108
5944
  rawExtraFieldUnix = extraFieldUnix.array;
6109
5945
  } else {
6110
- rawExtraFieldUnix = new Uint8Array();
5946
+ rawExtraFieldUnix = EMPTY_UINT8_ARRAY;
6111
5947
  }
6112
5948
  } catch {
6113
- rawExtraFieldUnix = new Uint8Array();
5949
+ rawExtraFieldUnix = EMPTY_UINT8_ARRAY;
6114
5950
  }
6115
5951
  if (compressionMethod === UNDEFINED_VALUE) {
6116
5952
  compressionMethod = compressed ? COMPRESSION_METHOD_DEFLATE : COMPRESSION_METHOD_STORE;
@@ -6177,7 +6013,7 @@
6177
6013
  version,
6178
6014
  compressionMethod,
6179
6015
  extraFieldExtendedTimestampFlag,
6180
- rawExtraFieldZip64: new Uint8Array(),
6016
+ rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
6181
6017
  localExtraFieldZip64Length,
6182
6018
  rawExtraFieldExtendedTimestamp,
6183
6019
  rawExtraFieldNTFS,
@@ -6190,7 +6026,6 @@
6190
6026
  function appendExtraFieldUSDZ(entryInfo, zipWriterOffset) {
6191
6027
  const { headerInfo } = entryInfo;
6192
6028
  let { localHeaderArray, extraFieldLength } = headerInfo;
6193
- let localHeaderArrayView;
6194
6029
  let extraBytesLength = 64 - ((zipWriterOffset + getLength(localHeaderArray)) % 64);
6195
6030
  if (extraBytesLength < 4) {
6196
6031
  extraBytesLength += 64;
@@ -6203,7 +6038,7 @@
6203
6038
  headerInfo.localHeaderArray = localHeaderArray = new Uint8Array(getLength(previousLocalHeaderArray) + extraBytesLength);
6204
6039
  arraySet(localHeaderArray, previousLocalHeaderArray);
6205
6040
  arraySet(localHeaderArray, rawExtraFieldUSDZ, getLength(previousLocalHeaderArray));
6206
- localHeaderArrayView = getDataView(localHeaderArray);
6041
+ const localHeaderArrayView = getDataView(localHeaderArray);
6207
6042
  setUint16(localHeaderArrayView, 28, extraFieldLength + extraBytesLength);
6208
6043
  headerInfo.localHeaderView = localHeaderArrayView;
6209
6044
  entryInfo.metadataSize += extraBytesLength;
@@ -6211,7 +6046,7 @@
6211
6046
 
6212
6047
  function packUnixId(id) {
6213
6048
  if (id === UNDEFINED_VALUE) {
6214
- return new Uint8Array();
6049
+ return EMPTY_UINT8_ARRAY;
6215
6050
  } else {
6216
6051
  const dataArray = new Uint8Array(4);
6217
6052
  const dataView = getDataView(dataArray);
@@ -6254,7 +6089,7 @@
6254
6089
  dataDescriptor,
6255
6090
  dataDescriptorSignature
6256
6091
  }) {
6257
- let dataDescriptorArray = new Uint8Array();
6092
+ let dataDescriptorArray = EMPTY_UINT8_ARRAY;
6258
6093
  let dataDescriptorView, dataDescriptorOffset = 0;
6259
6094
  let dataDescriptorLength = zip64 ? DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH : DATA_DESCRIPTOR_RECORD_LENGTH;
6260
6095
  if (dataDescriptorSignature) {
@@ -6338,7 +6173,6 @@
6338
6173
  }
6339
6174
  }
6340
6175
  if (zip64 && localExtraFieldZip64Length) {
6341
- // the local zip64 extra field always contains both size slots
6342
6176
  const localHeaderOffset = HEADER_SIZE + getLength(rawFilename) + 4;
6343
6177
  setBigUint64(localHeaderView, localHeaderOffset, BigInt(uncompressedSize));
6344
6178
  setBigUint64(localHeaderView, localHeaderOffset + 8, BigInt(compressedSize));
@@ -6392,7 +6226,7 @@
6392
6226
  }
6393
6227
  rawExtraFieldZip64 = extraFieldZip64.array;
6394
6228
  } else {
6395
- rawExtraFieldZip64 = new Uint8Array();
6229
+ rawExtraFieldZip64 = EMPTY_UINT8_ARRAY;
6396
6230
  }
6397
6231
  fileEntry.rawExtraFieldZip64 = rawExtraFieldZip64;
6398
6232
  fileEntry.zip64Offset = zip64Offset;
@@ -6407,7 +6241,7 @@
6407
6241
  extraFieldTimestamp.uint32(lastModTimeUnix);
6408
6242
  rawExtraFieldTimestamp = extraFieldTimestamp.array;
6409
6243
  } else {
6410
- rawExtraFieldTimestamp = new Uint8Array();
6244
+ rawExtraFieldTimestamp = EMPTY_UINT8_ARRAY;
6411
6245
  }
6412
6246
  fileEntry.rawExtraFieldExtendedTimestamp = rawExtraFieldTimestamp;
6413
6247
  const extraFieldLength = getLength(
@@ -6463,7 +6297,7 @@
6463
6297
  await writeData(writer, directoryArray.slice(directoryDiskOffset, offset));
6464
6298
  directoryDiskOffset = offset;
6465
6299
  writer.availableSize = 0;
6466
- await writeData(writer, new Uint8Array());
6300
+ await writeData(writer, EMPTY_UINT8_ARRAY);
6467
6301
  }
6468
6302
  if (indexFileEntry == 0) {
6469
6303
  cdStartDiskNumber = writer.diskNumber;
@@ -6536,7 +6370,7 @@
6536
6370
  const endOfdirectoryRecord = createRecordWriter(zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
6537
6371
  if (getLength(endOfdirectoryRecord.array) + commentLength > writer.availableSize) {
6538
6372
  writer.availableSize = 0;
6539
- await writeData(writer, new Uint8Array());
6373
+ await writeData(writer, EMPTY_UINT8_ARRAY);
6540
6374
  }
6541
6375
  lastDiskNumber = writer.diskNumber;
6542
6376
  if (zip64) {
@@ -6633,7 +6467,6 @@
6633
6467
  return Math.floor(date.getTime() / 1000);
6634
6468
  }
6635
6469
 
6636
- // the extended timestamp extra field stores dates as signed 32-bit time_t values
6637
6470
  function inUnixTimeRange(timeUnix) {
6638
6471
  return timeUnix >= MIN_UNIX_TIME && timeUnix <= MAX_UNIX_TIME;
6639
6472
  }
@@ -6818,36 +6651,12 @@
6818
6651
  const DEFAULT_THRESHOLD = 1024 * 1024;
6819
6652
  const DEFAULT_DIRECTORY_NAME = ".zip.js-temp";
6820
6653
 
6821
- // Builds a `createTempStream` factory (see `ZipWriter`'s option of the same name) that spills the
6822
- // data of a buffered entry to the Origin Private File System (OPFS) instead of keeping it in memory.
6823
- //
6824
- // It is meant for the buffered-write path (keep-order concurrent `add()`, non-seekable output, ...),
6825
- // where the compressed data of an entry has to be held until the writer is free. In memory that data
6826
- // grows with the entry size; here it is written to an OPFS file and streamed back, so peak memory
6827
- // stays bounded.
6828
- //
6829
- // It is hybrid on purpose: an entry stays fully in memory until it exceeds `thresholdBytes`, and only
6830
- // then spills to a file. Small entries never touch the disk, so a workload made of many tiny entries
6831
- // keeps the speed of the in-memory default; only genuinely large entries pay for (and benefit from)
6832
- // the file round-trip.
6833
- //
6834
- // OPFS is a browser/worker feature; there is no fallback here. Feature-detect
6835
- // `navigator.storage.getDirectory` (or inject `getDirectory`) before using it, and let the writer use
6836
- // its in-memory default elsewhere.
6837
- //
6838
- // Options:
6839
- // thresholdBytes spill to a file once a buffered entry exceeds this size (default 1 MiB).
6840
- // directoryName name of the OPFS sub-directory holding the temp files (default ".zip.js-temp").
6841
- // getDirectory returns (or resolves to) the root `FileSystemDirectoryHandle`. Defaults to
6842
- // `navigator.storage.getDirectory()`. Inject it to run inside a worker with a
6843
- // pre-obtained handle, or to test against a mock.
6844
6654
  function createOPFSTempStream(options = {}) {
6845
6655
  const {
6846
6656
  thresholdBytes = DEFAULT_THRESHOLD,
6847
6657
  directoryName = DEFAULT_DIRECTORY_NAME,
6848
6658
  getDirectory = () => navigator.storage.getDirectory()
6849
6659
  } = options;
6850
- // The temp directory is resolved once and shared by every entry of this factory.
6851
6660
  let directoryHandlePromise;
6852
6661
  function getTempDirectory() {
6853
6662
  if (!directoryHandlePromise) {
@@ -6856,15 +6665,12 @@
6856
6665
  }
6857
6666
  return directoryHandlePromise;
6858
6667
  }
6859
- return async function () {
6668
+ return function () {
6860
6669
  const memoryChunks = [];
6861
6670
  let bufferedSize = 0;
6862
6671
  let spilled = false;
6863
6672
  let fileName, fileHandle, fileWriter, fileReader;
6864
6673
 
6865
- // Move whatever is buffered in memory to a fresh OPFS file, then keep writing to that file.
6866
- // `FileSystemWritableFileStream` is a `WritableStream`, so it is driven through the standard
6867
- // writer API rather than its non-standard `write()`/`seek()` convenience methods.
6868
6674
  async function spillToFile() {
6869
6675
  const directoryHandle = await getTempDirectory();
6870
6676
  fileName = crypto.randomUUID();
@@ -6874,7 +6680,6 @@
6874
6680
  for (const chunk of memoryChunks) {
6875
6681
  await fileWriter.write(chunk);
6876
6682
  }
6877
- // Release the in-memory copy; from now on data lives in the file.
6878
6683
  memoryChunks.length = 0;
6879
6684
  }
6880
6685
 
@@ -6898,9 +6703,6 @@
6898
6703
  }
6899
6704
  });
6900
6705
 
6901
- // The writer always closes `writable` before reading `readable`, so `spilled` is final by the
6902
- // time `pull` runs. It is read lazily here (not in `start`, which runs at construction time,
6903
- // before anything is written and before `spilled` is known).
6904
6706
  let memoryIndex = 0;
6905
6707
  const readable = new ReadableStream({
6906
6708
  async pull(controller) {
@@ -6927,11 +6729,6 @@
6927
6729
  }
6928
6730
  }
6929
6731
  }, { highWaterMark: 0 });
6930
- // highWaterMark 0: do not pull (and possibly close on an empty buffer) until the consumer
6931
- // actually reads, which the writer only does once the data has been fully written.
6932
-
6933
- // Called by the writer on every exit path (success, error, abort). Best-effort: it must never
6934
- // throw. Closes any still-open file writer, then deletes the temp file.
6935
6732
  async function dispose() {
6936
6733
  if (fileWriter) {
6937
6734
  try {
@@ -7021,7 +6818,7 @@
7021
6818
  */
7022
6819
 
7023
6820
 
7024
- g(configure);
6821
+ f(configure);
7025
6822
 
7026
6823
  exports.BlobReader = BlobReader;
7027
6824
  exports.BlobWriter = BlobWriter;
@@ -7047,6 +6844,7 @@
7047
6844
  exports.ERR_INVALID_SIGNATURE = ERR_INVALID_SIGNATURE;
7048
6845
  exports.ERR_INVALID_UNCOMPRESSED_SIZE = ERR_INVALID_UNCOMPRESSED_SIZE;
7049
6846
  exports.ERR_INVALID_VERSION = ERR_INVALID_VERSION;
6847
+ exports.ERR_ITERATOR_COMPLETED_TOO_SOON = ERR_ITERATOR_COMPLETED_TOO_SOON;
7050
6848
  exports.ERR_LOCAL_FILE_HEADER_NOT_FOUND = ERR_LOCAL_FILE_HEADER_NOT_FOUND;
7051
6849
  exports.ERR_OVERLAPPING_ENTRY = ERR_OVERLAPPING_ENTRY;
7052
6850
  exports.ERR_SPLIT_ZIP_FILE = ERR_SPLIT_ZIP_FILE;
@@ -7055,6 +6853,7 @@
7055
6853
  exports.ERR_UNSUPPORTED_COMPRESSION = ERR_UNSUPPORTED_COMPRESSION$1;
7056
6854
  exports.ERR_UNSUPPORTED_ENCRYPTION = ERR_UNSUPPORTED_ENCRYPTION;
7057
6855
  exports.ERR_UNSUPPORTED_FORMAT = ERR_UNSUPPORTED_FORMAT;
6856
+ exports.ERR_WRITER_NOT_INITIALIZED = ERR_WRITER_NOT_INITIALIZED;
7058
6857
  exports.ERR_ZIP_NOT_EMPTY = ERR_ZIP_NOT_EMPTY;
7059
6858
  exports.HttpRangeReader = HttpRangeReader;
7060
6859
  exports.HttpReader = HttpReader;