@zip.js/zip.js 2.8.31 → 2.8.32

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/index.cjs CHANGED
@@ -2445,7 +2445,7 @@ function sendMessage(message, { worker, writer, transferStreams }) {
2445
2445
  const { value, readable, writable } = message;
2446
2446
  const transferables = [];
2447
2447
  if (value) {
2448
- message.value = value;
2448
+ message.value = value.byteOffset || value.byteLength != value.buffer.byteLength ? new Uint8Array(value) : value;
2449
2449
  transferables.push(message.value.buffer);
2450
2450
  }
2451
2451
  if (transferStreams && transferStreamsSupported) {
@@ -6646,13 +6646,13 @@ function getMimeType$1() {
6646
6646
  */
6647
6647
 
6648
6648
 
6649
- const DEFAULT_THRESHOLD = 1024 * 1024;
6650
- const DEFAULT_DIRECTORY_NAME = ".zip.js-temp";
6649
+ const DEFAULT_THRESHOLD$2 = 1024 * 1024;
6650
+ const DEFAULT_DIRECTORY_NAME$1 = ".zip.js-temp";
6651
6651
 
6652
6652
  function createOPFSTempStream(options = {}) {
6653
6653
  const {
6654
- thresholdBytes = DEFAULT_THRESHOLD,
6655
- directoryName = DEFAULT_DIRECTORY_NAME,
6654
+ thresholdBytes = DEFAULT_THRESHOLD$2,
6655
+ directoryName = DEFAULT_DIRECTORY_NAME$1,
6656
6656
  getDirectory = () => navigator.storage.getDirectory()
6657
6657
  } = options;
6658
6658
  let directoryHandlePromise;
@@ -6781,6 +6781,269 @@ function createOPFSTempStream(options = {}) {
6781
6781
  */
6782
6782
 
6783
6783
 
6784
+ const DEFAULT_THRESHOLD$1 = 1024 * 1024;
6785
+
6786
+ function createBlobTempStream(options = {}) {
6787
+ const {
6788
+ thresholdBytes = DEFAULT_THRESHOLD$1
6789
+ } = options;
6790
+ return function () {
6791
+ const memoryChunks = [];
6792
+ let bufferedSize = 0;
6793
+ let spilled = false;
6794
+ let blobWriter, blobPromise, blobReader;
6795
+
6796
+ async function spillToBlob() {
6797
+ const transformStream = new TransformStream();
6798
+ blobPromise = new Response(transformStream.readable).blob();
6799
+ blobWriter = transformStream.writable.getWriter();
6800
+ spilled = true;
6801
+ for (const chunk of memoryChunks) {
6802
+ await blobWriter.write(chunk);
6803
+ }
6804
+ memoryChunks.length = 0;
6805
+ }
6806
+
6807
+ const writable = new WritableStream({
6808
+ async write(chunk) {
6809
+ if (spilled) {
6810
+ await blobWriter.write(chunk);
6811
+ } else {
6812
+ memoryChunks.push(chunk);
6813
+ bufferedSize += chunk.length;
6814
+ if (bufferedSize > thresholdBytes) {
6815
+ await spillToBlob();
6816
+ }
6817
+ }
6818
+ },
6819
+ async close() {
6820
+ if (blobWriter) {
6821
+ await blobWriter.close();
6822
+ blobWriter = null;
6823
+ }
6824
+ }
6825
+ });
6826
+
6827
+ let memoryIndex = 0;
6828
+ const readable = new ReadableStream({
6829
+ async pull(controller) {
6830
+ if (spilled) {
6831
+ if (!blobReader) {
6832
+ const blob = await blobPromise;
6833
+ blobReader = blob.stream().getReader();
6834
+ }
6835
+ const { value, done } = await blobReader.read();
6836
+ if (done) {
6837
+ controller.close();
6838
+ } else {
6839
+ controller.enqueue(value);
6840
+ }
6841
+ } else if (memoryIndex < memoryChunks.length) {
6842
+ controller.enqueue(memoryChunks[memoryIndex++]);
6843
+ } else {
6844
+ controller.close();
6845
+ }
6846
+ },
6847
+ async cancel(reason) {
6848
+ if (blobReader) {
6849
+ await blobReader.cancel(reason);
6850
+ }
6851
+ }
6852
+ }, { highWaterMark: 0 });
6853
+ async function dispose() {
6854
+ if (blobWriter) {
6855
+ try {
6856
+ await blobWriter.abort();
6857
+ } catch {
6858
+ // ignored
6859
+ }
6860
+ blobWriter = null;
6861
+ }
6862
+ if (blobPromise) {
6863
+ blobPromise.catch(() => {
6864
+ // ignored
6865
+ });
6866
+ blobPromise = null;
6867
+ }
6868
+ memoryChunks.length = 0;
6869
+ }
6870
+
6871
+ return { writable, readable, dispose };
6872
+ };
6873
+ }
6874
+
6875
+ /*
6876
+ Copyright (c) 2025 Gildas Lormeau. All rights reserved.
6877
+
6878
+ Redistribution and use in source and binary forms, with or without
6879
+ modification, are permitted provided that the following conditions are met:
6880
+
6881
+ 1. Redistributions of source code must retain the above copyright notice,
6882
+ this list of conditions and the following disclaimer.
6883
+
6884
+ 2. Redistributions in binary form must reproduce the above copyright
6885
+ notice, this list of conditions and the following disclaimer in
6886
+ the documentation and/or other materials provided with the distribution.
6887
+
6888
+ 3. The names of the authors may not be used to endorse or promote products
6889
+ derived from this software without specific prior written permission.
6890
+
6891
+ THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
6892
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
6893
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
6894
+ INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
6895
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
6896
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
6897
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
6898
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
6899
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
6900
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
6901
+ */
6902
+
6903
+
6904
+ const DEFAULT_THRESHOLD = 1024 * 1024;
6905
+ const DEFAULT_DIRECTORY_NAME = ".zip.js-temp";
6906
+ const READ_CHUNK_SIZE = 512 * 1024;
6907
+ const ERR_UNSUPPORTED_CONTEXT = "createSyncAccessHandle is only available in dedicated workers";
6908
+
6909
+ function createSyncAccessHandleTempStream(options = {}) {
6910
+ const {
6911
+ thresholdBytes = DEFAULT_THRESHOLD,
6912
+ directoryName = DEFAULT_DIRECTORY_NAME,
6913
+ getDirectory
6914
+ } = options;
6915
+ if (!getDirectory &&
6916
+ (typeof FileSystemFileHandle == "undefined" || !FileSystemFileHandle.prototype.createSyncAccessHandle)) {
6917
+ throw new Error(ERR_UNSUPPORTED_CONTEXT);
6918
+ }
6919
+ const getRootDirectory = getDirectory || (() => navigator.storage.getDirectory());
6920
+ let directoryHandlePromise;
6921
+ function getTempDirectory() {
6922
+ if (!directoryHandlePromise) {
6923
+ directoryHandlePromise = Promise.resolve(getRootDirectory())
6924
+ .then(root => root.getDirectoryHandle(directoryName, { create: true }));
6925
+ }
6926
+ return directoryHandlePromise;
6927
+ }
6928
+ return function () {
6929
+ const memoryChunks = [];
6930
+ let bufferedSize = 0;
6931
+ let spilled = false;
6932
+ let fileName, accessHandle;
6933
+ let writeOffset = 0;
6934
+ let readOffset = 0;
6935
+
6936
+ async function spillToFile() {
6937
+ const directoryHandle = await getTempDirectory();
6938
+ fileName = crypto.randomUUID();
6939
+ const fileHandle = await directoryHandle.getFileHandle(fileName, { create: true });
6940
+ accessHandle = await fileHandle.createSyncAccessHandle();
6941
+ spilled = true;
6942
+ for (const chunk of memoryChunks) {
6943
+ accessHandle.write(chunk, { at: writeOffset });
6944
+ writeOffset += chunk.length;
6945
+ }
6946
+ memoryChunks.length = 0;
6947
+ }
6948
+
6949
+ const writable = new WritableStream({
6950
+ async write(chunk) {
6951
+ if (spilled) {
6952
+ accessHandle.write(chunk, { at: writeOffset });
6953
+ writeOffset += chunk.length;
6954
+ } else {
6955
+ memoryChunks.push(chunk);
6956
+ bufferedSize += chunk.length;
6957
+ if (bufferedSize > thresholdBytes) {
6958
+ await spillToFile();
6959
+ }
6960
+ }
6961
+ },
6962
+ close() {
6963
+ if (accessHandle) {
6964
+ accessHandle.flush();
6965
+ }
6966
+ }
6967
+ });
6968
+
6969
+ let memoryIndex = 0;
6970
+ const readable = new ReadableStream({
6971
+ pull(controller) {
6972
+ if (spilled) {
6973
+ const remaining = writeOffset - readOffset;
6974
+ if (remaining <= 0) {
6975
+ controller.close();
6976
+ return;
6977
+ }
6978
+ const buffer = new Uint8Array(Math.min(READ_CHUNK_SIZE, remaining));
6979
+ const read = accessHandle.read(buffer, { at: readOffset });
6980
+ if (read) {
6981
+ readOffset += read;
6982
+ controller.enqueue(buffer.subarray(0, read));
6983
+ } else {
6984
+ controller.close();
6985
+ }
6986
+ } else if (memoryIndex < memoryChunks.length) {
6987
+ controller.enqueue(memoryChunks[memoryIndex++]);
6988
+ } else {
6989
+ controller.close();
6990
+ }
6991
+ }
6992
+ }, { highWaterMark: 0 });
6993
+ async function dispose() {
6994
+ if (accessHandle) {
6995
+ try {
6996
+ accessHandle.close();
6997
+ } catch {
6998
+ // ignored
6999
+ }
7000
+ accessHandle = null;
7001
+ }
7002
+ if (fileName) {
7003
+ try {
7004
+ const directoryHandle = await getTempDirectory();
7005
+ await directoryHandle.removeEntry(fileName);
7006
+ } catch {
7007
+ // ignored
7008
+ }
7009
+ fileName = null;
7010
+ }
7011
+ memoryChunks.length = 0;
7012
+ }
7013
+
7014
+ return { writable, readable, dispose };
7015
+ };
7016
+ }
7017
+
7018
+ /*
7019
+ Copyright (c) 2025 Gildas Lormeau. All rights reserved.
7020
+
7021
+ Redistribution and use in source and binary forms, with or without
7022
+ modification, are permitted provided that the following conditions are met:
7023
+
7024
+ 1. Redistributions of source code must retain the above copyright notice,
7025
+ this list of conditions and the following disclaimer.
7026
+
7027
+ 2. Redistributions in binary form must reproduce the above copyright
7028
+ notice, this list of conditions and the following disclaimer in
7029
+ the documentation and/or other materials provided with the distribution.
7030
+
7031
+ 3. The names of the authors may not be used to endorse or promote products
7032
+ derived from this software without specific prior written permission.
7033
+
7034
+ THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
7035
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
7036
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
7037
+ INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
7038
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
7039
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
7040
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
7041
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
7042
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
7043
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7044
+ */
7045
+
7046
+
6784
7047
  try {
6785
7048
  configure({ baseURI: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)) });
6786
7049
  } catch {
@@ -9871,7 +10134,9 @@ exports.ZipReaderStream = ZipReaderStream;
9871
10134
  exports.ZipWriter = ZipWriter;
9872
10135
  exports.ZipWriterStream = ZipWriterStream;
9873
10136
  exports.configure = configure;
10137
+ exports.createBlobTempStream = createBlobTempStream;
9874
10138
  exports.createOPFSTempStream = createOPFSTempStream;
10139
+ exports.createSyncAccessHandleTempStream = createSyncAccessHandleTempStream;
9875
10140
  exports.fs = fs;
9876
10141
  exports.getMimeType = getMimeType;
9877
10142
  exports.terminateWorkers = terminateWorkersAndModule;
package/index.d.cts CHANGED
@@ -381,6 +381,45 @@ export interface OPFSTempStreamOptions {
381
381
  */
382
382
  export function createOPFSTempStream(options?: OPFSTempStreamOptions): () => Promise<TempStream>;
383
383
 
384
+ /**
385
+ * Options for {@link createBlobTempStream}.
386
+ */
387
+ export interface BlobTempStreamOptions {
388
+ /**
389
+ * Spill a buffered entry to a `Blob` once its buffered data exceeds this size, in bytes. Smaller entries stay in memory.
390
+ *
391
+ * @defaultValue 1048576
392
+ */
393
+ thresholdBytes?: number;
394
+ }
395
+
396
+ /**
397
+ * Builds a {@link ZipWriterConstructorOptions.createTempStream} factory that spills the data of buffered entries into a `Blob` instead of keeping it in memory.
398
+ *
399
+ * An entry stays in memory until it exceeds `thresholdBytes`, then its data is transferred incrementally into a `Blob` built with `new Response(stream).blob()` and streamed back afterwards.
400
+ * In Chromium-based browsers, `Blob` data is managed outside the page and paged to disk under memory pressure, so peak memory stays bounded on large buffered entries without any storage permission or cleanup obligation.
401
+ * In Firefox, the `Blob` stays in memory but the helper still reduces peak memory usage moderately (roughly 30% on large entries) by releasing staged chunks earlier.
402
+ * In Safari, building the `Blob` retains several copies of the staged data (roughly 4 times the entry size at peak); do not use this helper there.
403
+ * In non-browser runtimes, the helper stays functional but roughly doubles peak memory usage (staged bytes plus their `Blob` copy).
404
+ * Outside Chromium-based browsers, prefer {@link createOPFSTempStream} or a file-backed implementation.
405
+ *
406
+ * @param options The options.
407
+ * @returns A factory suitable for {@link ZipWriterConstructorOptions.createTempStream}.
408
+ */
409
+ export function createBlobTempStream(options?: BlobTempStreamOptions): () => TempStream;
410
+
411
+ /**
412
+ * Builds a {@link ZipWriterConstructorOptions.createTempStream} factory that spills the data of buffered entries to the Origin Private File System (OPFS) via `FileSystemSyncAccessHandle` instead of keeping it in memory.
413
+ *
414
+ * This is the fastest disk-backed temporary storage on the web platform: it behaves like {@link createOPFSTempStream} (same options, same bounded-memory profile) but writes roughly 2.5 times faster in Chromium and Firefox and reads back several times faster in Firefox and Safari, making disk-backed staging nearly as fast as the in-memory default.
415
+ *
416
+ * `FileSystemSyncAccessHandle` is only exposed in dedicated workers, so this helper requires running the {@link ZipWriter} inside a worker; it throws when created in an unsupported context unless `getDirectory` is provided.
417
+ *
418
+ * @param options The options.
419
+ * @returns A factory suitable for {@link ZipWriterConstructorOptions.createTempStream}.
420
+ */
421
+ export function createSyncAccessHandleTempStream(options?: OPFSTempStreamOptions): () => TempStream;
422
+
384
423
  /**
385
424
  * Represents an instance used to read or write unknown type of data.
386
425
  *
@@ -1823,7 +1862,7 @@ export interface ZipWriterConstructorOptions extends WorkerConfiguration {
1823
1862
  * The `writable` side receives compressed entry data. The `readable` side is consumed when the entry is replayed into the final zip stream.
1824
1863
  * The optional `dispose` method is called once the entry has been processed (on success, error, or abort) so a resource-backed buffer can release its resource.
1825
1864
  *
1826
- * See {@link createOPFSTempStream} for a ready-made OPFS-backed implementation.
1865
+ * See {@link createOPFSTempStream} for a ready-made OPFS-backed implementation, {@link createSyncAccessHandleTempStream} for a faster worker-only variant, and {@link createBlobTempStream} for a `Blob`-backed one.
1827
1866
  */
1828
1867
  createTempStream?: () => TempStream | Promise<TempStream>;
1829
1868
  /**
package/index.d.ts CHANGED
@@ -381,6 +381,45 @@ export interface OPFSTempStreamOptions {
381
381
  */
382
382
  export function createOPFSTempStream(options?: OPFSTempStreamOptions): () => Promise<TempStream>;
383
383
 
384
+ /**
385
+ * Options for {@link createBlobTempStream}.
386
+ */
387
+ export interface BlobTempStreamOptions {
388
+ /**
389
+ * Spill a buffered entry to a `Blob` once its buffered data exceeds this size, in bytes. Smaller entries stay in memory.
390
+ *
391
+ * @defaultValue 1048576
392
+ */
393
+ thresholdBytes?: number;
394
+ }
395
+
396
+ /**
397
+ * Builds a {@link ZipWriterConstructorOptions.createTempStream} factory that spills the data of buffered entries into a `Blob` instead of keeping it in memory.
398
+ *
399
+ * An entry stays in memory until it exceeds `thresholdBytes`, then its data is transferred incrementally into a `Blob` built with `new Response(stream).blob()` and streamed back afterwards.
400
+ * In Chromium-based browsers, `Blob` data is managed outside the page and paged to disk under memory pressure, so peak memory stays bounded on large buffered entries without any storage permission or cleanup obligation.
401
+ * In Firefox, the `Blob` stays in memory but the helper still reduces peak memory usage moderately (roughly 30% on large entries) by releasing staged chunks earlier.
402
+ * In Safari, building the `Blob` retains several copies of the staged data (roughly 4 times the entry size at peak); do not use this helper there.
403
+ * In non-browser runtimes, the helper stays functional but roughly doubles peak memory usage (staged bytes plus their `Blob` copy).
404
+ * Outside Chromium-based browsers, prefer {@link createOPFSTempStream} or a file-backed implementation.
405
+ *
406
+ * @param options The options.
407
+ * @returns A factory suitable for {@link ZipWriterConstructorOptions.createTempStream}.
408
+ */
409
+ export function createBlobTempStream(options?: BlobTempStreamOptions): () => TempStream;
410
+
411
+ /**
412
+ * Builds a {@link ZipWriterConstructorOptions.createTempStream} factory that spills the data of buffered entries to the Origin Private File System (OPFS) via `FileSystemSyncAccessHandle` instead of keeping it in memory.
413
+ *
414
+ * This is the fastest disk-backed temporary storage on the web platform: it behaves like {@link createOPFSTempStream} (same options, same bounded-memory profile) but writes roughly 2.5 times faster in Chromium and Firefox and reads back several times faster in Firefox and Safari, making disk-backed staging nearly as fast as the in-memory default.
415
+ *
416
+ * `FileSystemSyncAccessHandle` is only exposed in dedicated workers, so this helper requires running the {@link ZipWriter} inside a worker; it throws when created in an unsupported context unless `getDirectory` is provided.
417
+ *
418
+ * @param options The options.
419
+ * @returns A factory suitable for {@link ZipWriterConstructorOptions.createTempStream}.
420
+ */
421
+ export function createSyncAccessHandleTempStream(options?: OPFSTempStreamOptions): () => TempStream;
422
+
384
423
  /**
385
424
  * Represents an instance used to read or write unknown type of data.
386
425
  *
@@ -1823,7 +1862,7 @@ export interface ZipWriterConstructorOptions extends WorkerConfiguration {
1823
1862
  * The `writable` side receives compressed entry data. The `readable` side is consumed when the entry is replayed into the final zip stream.
1824
1863
  * The optional `dispose` method is called once the entry has been processed (on success, error, or abort) so a resource-backed buffer can release its resource.
1825
1864
  *
1826
- * See {@link createOPFSTempStream} for a ready-made OPFS-backed implementation.
1865
+ * See {@link createOPFSTempStream} for a ready-made OPFS-backed implementation, {@link createSyncAccessHandleTempStream} for a faster worker-only variant, and {@link createBlobTempStream} for a `Blob`-backed one.
1827
1866
  */
1828
1867
  createTempStream?: () => TempStream | Promise<TempStream>;
1829
1868
  /**