@zip.js/zip.js 2.7.32 → 2.7.33

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.
@@ -84,10 +84,18 @@ async function runWorker(stream, workerOptions) {
84
84
  } else if (workerData.worker) {
85
85
  clearTerminateTimeout(workerData);
86
86
  if (Number.isFinite(terminateWorkerTimeout) && terminateWorkerTimeout >= 0) {
87
- workerData.terminateTimeout = setTimeout(() => {
88
- pool = pool.filter(data => data != workerData);
89
- workerData.terminate();
90
- }, terminateWorkerTimeout);
87
+ if (workerData.terminated) {
88
+ workerData.terminated = false;
89
+ } else {
90
+ workerData.terminateTimeout = setTimeout(async () => {
91
+ pool = pool.filter(data => data != workerData);
92
+ try {
93
+ await workerData.terminate();
94
+ } catch (_error) {
95
+ // ignored
96
+ }
97
+ }, terminateWorkerTimeout);
98
+ }
91
99
  }
92
100
  } else {
93
101
  pool = pool.filter(data => data != workerData);
@@ -103,9 +111,9 @@ function clearTerminateTimeout(workerData) {
103
111
  }
104
112
  }
105
113
 
106
- function terminateWorkers() {
107
- pool.forEach(workerData => {
114
+ async function terminateWorkers() {
115
+ await Promise.allSettled(pool.map(workerData => {
108
116
  clearTerminateTimeout(workerData);
109
- workerData.terminate();
110
- });
117
+ return workerData.terminate();
118
+ }));
111
119
  }
@@ -34,6 +34,7 @@ import {
34
34
  } from "./constants.js";
35
35
  import {
36
36
  CodecStream,
37
+ ChunkStream,
37
38
  MESSAGE_EVENT_TYPE,
38
39
  MESSAGE_START,
39
40
  MESSAGE_PULL,
@@ -43,7 +44,7 @@ import {
43
44
  } from "./streams/codec-stream.js";
44
45
 
45
46
  // deno-lint-ignore valid-typeof
46
- const WEB_WORKERS_SUPPORTED = typeof Worker != UNDEFINED_TYPE;
47
+ let WEB_WORKERS_SUPPORTED = typeof Worker != UNDEFINED_TYPE;
47
48
 
48
49
  export {
49
50
  CodecWorker
@@ -55,19 +56,37 @@ class CodecWorker {
55
56
  const { signal } = streamOptions;
56
57
  Object.assign(workerData, {
57
58
  busy: true,
58
- readable: readable.pipeThrough(new ProgressWatcherStream(readable, streamOptions, config), { signal }),
59
+ readable: readable
60
+ .pipeThrough(new ChunkStream(config.chunkSize))
61
+ .pipeThrough(new ProgressWatcherStream(readable, streamOptions), { signal }),
59
62
  writable,
60
63
  options: Object.assign({}, options),
61
64
  scripts,
62
65
  transferStreams,
63
66
  terminate() {
64
- const { worker, busy } = workerData;
65
- if (worker && !busy) {
66
- worker.terminate();
67
- workerData.interface = null;
68
- }
67
+ return new Promise(resolve => {
68
+ const { worker, busy } = workerData;
69
+ if (worker) {
70
+ if (busy) {
71
+ workerData.resolveTerminated = resolve;
72
+ } else {
73
+ worker.terminate();
74
+ resolve();
75
+ }
76
+ workerData.interface = null;
77
+ } else {
78
+ resolve();
79
+ }
80
+ });
69
81
  },
70
82
  onTaskFinished() {
83
+ const { resolveTerminated } = workerData;
84
+ if (resolveTerminated) {
85
+ workerData.resolveTerminated = null;
86
+ workerData.terminated = true;
87
+ workerData.worker.terminate();
88
+ resolveTerminated();
89
+ }
71
90
  workerData.busy = false;
72
91
  onTaskFinished(workerData);
73
92
  }
@@ -78,7 +97,7 @@ class CodecWorker {
78
97
 
79
98
  class ProgressWatcherStream extends TransformStream {
80
99
 
81
- constructor(readableSource, { onstart, onprogress, size, onend }, { chunkSize }) {
100
+ constructor(readableSource, { onstart, onprogress, size, onend }) {
82
101
  let chunkOffset = 0;
83
102
  super({
84
103
  start() {
@@ -99,7 +118,7 @@ class ProgressWatcherStream extends TransformStream {
99
118
  callHandler(onend, chunkOffset);
100
119
  }
101
120
  }
102
- }, { highWaterMark: 1, size: () => chunkSize });
121
+ });
103
122
  }
104
123
  }
105
124
 
@@ -117,10 +136,18 @@ function createWorkerInterface(workerData, config) {
117
136
  };
118
137
  }
119
138
 
120
- function createWebWorkerInterface(workerData, { baseURL, chunkSize }) {
139
+ function createWebWorkerInterface(workerData, config) {
140
+ const { baseURL, chunkSize } = config;
121
141
  if (!workerData.interface) {
142
+ let worker;
143
+ try {
144
+ worker = getWebWorker(workerData.scripts[0], baseURL, workerData);
145
+ } catch (error) {
146
+ WEB_WORKERS_SUPPORTED = false;
147
+ return createWorkerInterface(workerData, config);
148
+ }
122
149
  Object.assign(workerData, {
123
- worker: getWebWorker(workerData.scripts[0], baseURL, workerData),
150
+ worker,
124
151
  interface: {
125
152
  run: () => runWebWorker(workerData, { chunkSize })
126
153
  }
@@ -130,16 +157,18 @@ function createWebWorkerInterface(workerData, { baseURL, chunkSize }) {
130
157
  }
131
158
 
132
159
  async function runWorker({ options, readable, writable, onTaskFinished }, config) {
133
- const codecStream = new CodecStream(options, config);
134
160
  try {
161
+ const codecStream = new CodecStream(options, config);
135
162
  await readable.pipeThrough(codecStream).pipeTo(writable, { preventClose: true, preventAbort: true });
136
163
  const {
137
164
  signature,
138
- size
165
+ inputSize,
166
+ outputSize
139
167
  } = codecStream;
140
168
  return {
141
169
  signature,
142
- size
170
+ inputSize,
171
+ outputSize
143
172
  };
144
173
  } finally {
145
174
  onTaskFinished();
@@ -186,19 +215,20 @@ async function runWebWorker(workerData, config) {
186
215
  }
187
216
 
188
217
  function watchClosedStream(writableSource) {
189
- const writer = writableSource.getWriter();
190
218
  let resolveStreamClosed;
191
219
  const closed = new Promise(resolve => resolveStreamClosed = resolve);
192
220
  const writable = new WritableStream({
193
221
  async write(chunk) {
222
+ const writer = writableSource.getWriter();
194
223
  await writer.ready;
195
224
  await writer.write(chunk);
225
+ writer.releaseLock();
196
226
  },
197
227
  close() {
198
- writer.releaseLock();
199
228
  resolveStreamClosed();
200
229
  },
201
230
  abort(reason) {
231
+ const writer = writableSource.getWriter();
202
232
  return writer.abort(reason);
203
233
  }
204
234
  });
@@ -302,6 +332,7 @@ async function onMessage({ data }, workerData) {
302
332
  }
303
333
  }
304
334
  } catch (error) {
335
+ sendMessage({ type: MESSAGE_CLOSE, messageId }, workerData);
305
336
  close(error);
306
337
  }
307
338
 
@@ -65,7 +65,8 @@ export {
65
65
  ERR_INVALID_PASSWORD,
66
66
  ERR_INVALID_SIGNATURE,
67
67
  ERR_ABORT_CHECK_PASSWORD,
68
- CodecStream
68
+ CodecStream,
69
+ ChunkStream
69
70
  };
70
71
 
71
72
  class CodecStream extends TransformStream {
@@ -80,13 +81,27 @@ class CodecStream extends TransformStream {
80
81
  } else if (codecType.startsWith(CODEC_INFLATE)) {
81
82
  Stream = InflateStream;
82
83
  }
83
- let size = 0;
84
+ let outputSize = 0;
85
+ let inputSize = 0;
84
86
  const stream = new Stream(options, config);
85
87
  const readable = super.readable;
86
- const transformStream = new TransformStream({
88
+ const inputSizeStream = new TransformStream({
87
89
  transform(chunk, controller) {
88
90
  if (chunk && chunk.length) {
89
- size += chunk.length;
91
+ inputSize += chunk.length;
92
+ controller.enqueue(chunk);
93
+ }
94
+ },
95
+ flush() {
96
+ Object.assign(codec, {
97
+ inputSize
98
+ });
99
+ }
100
+ });
101
+ const outputSizeStream = new TransformStream({
102
+ transform(chunk, controller) {
103
+ if (chunk && chunk.length) {
104
+ outputSize += chunk.length;
90
105
  controller.enqueue(chunk);
91
106
  }
92
107
  },
@@ -94,14 +109,46 @@ class CodecStream extends TransformStream {
94
109
  const { signature } = stream;
95
110
  Object.assign(codec, {
96
111
  signature,
97
- size
112
+ outputSize,
113
+ inputSize
98
114
  });
99
115
  }
100
116
  });
101
117
  Object.defineProperty(codec, "readable", {
102
118
  get() {
103
- return readable.pipeThrough(stream).pipeThrough(transformStream);
119
+ return readable.pipeThrough(inputSizeStream).pipeThrough(stream).pipeThrough(outputSizeStream);
104
120
  }
105
121
  });
106
122
  }
123
+ }
124
+
125
+ class ChunkStream extends TransformStream {
126
+
127
+ constructor(chunkSize) {
128
+ let pendingChunk;
129
+ super({
130
+ transform,
131
+ flush(controller) {
132
+ if (pendingChunk && pendingChunk.length) {
133
+ controller.enqueue(pendingChunk);
134
+ }
135
+ }
136
+ });
137
+
138
+ function transform(chunk, controller) {
139
+ if (pendingChunk) {
140
+ const newChunk = new Uint8Array(pendingChunk.length + chunk.length);
141
+ newChunk.set(pendingChunk);
142
+ newChunk.set(chunk, pendingChunk.length);
143
+ chunk = newChunk;
144
+ pendingChunk = null;
145
+ }
146
+ if (chunk.length > chunkSize) {
147
+ controller.enqueue(chunk.slice(0, chunkSize));
148
+ transform(chunk.slice(chunkSize), controller);
149
+ } else {
150
+ pendingChunk = chunk;
151
+ }
152
+ }
153
+ }
107
154
  }
@@ -148,9 +148,13 @@ function pipeThroughCommpressionStream(readable, useCompressionStream, options,
148
148
  readable = pipeThrough(readable, new CompressionStream(COMPRESSION_FORMAT, options));
149
149
  } catch (error) {
150
150
  if (useCompressionStream) {
151
- readable = pipeThrough(readable, new CodecStream(COMPRESSION_FORMAT, options));
151
+ try {
152
+ readable = pipeThrough(readable, new CodecStream(COMPRESSION_FORMAT, options));
153
+ } catch (error) {
154
+ return readable;
155
+ }
152
156
  } else {
153
- throw error;
157
+ return readable;
154
158
  }
155
159
  }
156
160
  return readable;
@@ -26,12 +26,13 @@
26
26
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
27
  */
28
28
 
29
- /* global self, importScripts, addEventListener, postMessage, ReadableStream, WritableStream */
29
+ /* global self, importScripts, addEventListener, postMessage, ReadableStream, WritableStream, AbortController */
30
30
 
31
31
  import { UNDEFINED_VALUE } from "./constants.js";
32
32
  import { StreamAdapter } from "./streams/stream-adapter.js";
33
33
  import {
34
34
  CodecStream,
35
+ ChunkStream,
35
36
  MESSAGE_EVENT_TYPE,
36
37
  MESSAGE_START,
37
38
  MESSAGE_PULL,
@@ -43,7 +44,7 @@ import {
43
44
  const pendingPullMessages = new Map();
44
45
  const pendingDataMessages = new Map();
45
46
 
46
- let messageId = 0;
47
+ let abortController, messageId = 0, importScriptSupported = true;
47
48
 
48
49
  addEventListener(MESSAGE_EVENT_TYPE, ({ data }) => {
49
50
  const { type, messageId, value, done } = data;
@@ -61,6 +62,9 @@ addEventListener(MESSAGE_EVENT_TYPE, ({ data }) => {
61
62
  pendingDataMessages.delete(messageId);
62
63
  resolve();
63
64
  }
65
+ if (type == MESSAGE_CLOSE) {
66
+ abortController.abort();
67
+ }
64
68
  } catch (error) {
65
69
  sendErrorMessage(error);
66
70
  }
@@ -70,7 +74,16 @@ async function init(message) {
70
74
  try {
71
75
  const { options, scripts, config } = message;
72
76
  if (scripts && scripts.length) {
73
- importScripts.apply(UNDEFINED_VALUE, scripts);
77
+ try {
78
+ if (importScriptSupported) {
79
+ importScripts.apply(UNDEFINED_VALUE, scripts);
80
+ } else {
81
+ await imporModuleScripts(scripts);
82
+ }
83
+ } catch (error) {
84
+ importScriptSupported = false;
85
+ await imporModuleScripts(scripts);
86
+ }
74
87
  }
75
88
  if (self.initCodec) {
76
89
  self.initCodec();
@@ -83,7 +96,7 @@ async function init(message) {
83
96
  if (self.Inflate) {
84
97
  config.DecompressionStream = new StreamAdapter(self.Inflate);
85
98
  }
86
- const strategy = { highWaterMark: 1, size: () => config.chunkSize };
99
+ const strategy = { highWaterMark: 1 };
87
100
  const readable = message.readable || new ReadableStream({
88
101
  async pull(controller) {
89
102
  const result = new Promise(resolve => pendingPullMessages.set(messageId, resolve));
@@ -107,7 +120,12 @@ async function init(message) {
107
120
  }
108
121
  }, strategy);
109
122
  const codecStream = new CodecStream(options, config);
110
- await readable.pipeThrough(codecStream).pipeTo(writable, { preventClose: true, preventAbort: true });
123
+ abortController = new AbortController();
124
+ const { signal } = abortController;
125
+ await readable
126
+ .pipeThrough(codecStream)
127
+ .pipeThrough(new ChunkStream(config.chunkSize))
128
+ .pipeTo(writable, { signal, preventClose: true, preventAbort: true });
111
129
  try {
112
130
  await writable.getWriter().close();
113
131
  } catch (_error) {
@@ -115,13 +133,15 @@ async function init(message) {
115
133
  }
116
134
  const {
117
135
  signature,
118
- size
136
+ inputSize,
137
+ outputSize
119
138
  } = codecStream;
120
139
  sendMessage({
121
140
  type: MESSAGE_CLOSE,
122
141
  result: {
123
142
  signature,
124
- size
143
+ inputSize,
144
+ outputSize
125
145
  }
126
146
  });
127
147
  } catch (error) {
@@ -129,6 +149,12 @@ async function init(message) {
129
149
  }
130
150
  }
131
151
 
152
+ async function imporModuleScripts(scripts) {
153
+ for (const script of scripts) {
154
+ await import(script);
155
+ }
156
+ }
157
+
132
158
  function sendMessage(message) {
133
159
  let { value } = message;
134
160
  if (value) {
@@ -164,7 +164,7 @@ class ZipWriter {
164
164
  const { pendingAddFileCalls, writer } = this;
165
165
  const { writable } = writer;
166
166
  while (pendingAddFileCalls.size) {
167
- await Promise.all(Array.from(pendingAddFileCalls));
167
+ await Promise.allSettled(Array.from(pendingAddFileCalls));
168
168
  }
169
169
  await closeFile(this, comment, options);
170
170
  const preventClose = getOptionValue(zipWriter, options, "preventClose");
@@ -420,7 +420,7 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
420
420
  } else if (fileEntry.offset >= MAX_32_BITS) {
421
421
  throw new Error(ERR_UNSUPPORTED_FORMAT);
422
422
  }
423
- zipWriter.offset += fileEntry.length;
423
+ zipWriter.offset += fileEntry.size;
424
424
  return fileEntry;
425
425
  } catch (error) {
426
426
  if ((bufferedWrite && writingBufferedEntryData) || (!bufferedWrite && writingEntryData)) {
@@ -571,10 +571,10 @@ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryI
571
571
  streamOptions: { signal, size, onstart, onprogress, onend }
572
572
  };
573
573
  const result = await runWorker({ readable, writable }, workerOptions);
574
- writable.size += result.size;
574
+ uncompressedSize = result.inputSize;
575
+ compressedSize = result.outputSize;
575
576
  signature = result.signature;
576
- uncompressedSize = reader.size = readable.size;
577
- compressedSize = result.size;
577
+ writable.size += uncompressedSize;
578
578
  } else {
579
579
  await writeData(writable, localHeaderArray);
580
580
  }
@@ -616,7 +616,7 @@ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryI
616
616
  creationDate,
617
617
  lastAccessDate,
618
618
  encrypted,
619
- length: metadataSize + compressedSize,
619
+ size: metadataSize + compressedSize,
620
620
  compressionMethod,
621
621
  version,
622
622
  headerArray,
@@ -1088,10 +1088,13 @@ async function closeFile(zipWriter, comment, options) {
1088
1088
 
1089
1089
  async function writeData(writable, array) {
1090
1090
  const streamWriter = writable.getWriter();
1091
- await streamWriter.ready;
1092
- writable.size += getLength(array);
1093
- await streamWriter.write(array);
1094
- streamWriter.releaseLock();
1091
+ try {
1092
+ await streamWriter.ready;
1093
+ writable.size += getLength(array);
1094
+ await streamWriter.write(array);
1095
+ } finally {
1096
+ streamWriter.releaseLock();
1097
+ }
1095
1098
  }
1096
1099
 
1097
1100
  function getTimeNTFS(date) {