@cj-tech-master/excelts 6.0.0-beta.4 → 6.0.0-beta.5

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 (65) hide show
  1. package/dist/browser/modules/archive/create-archive.d.ts +23 -0
  2. package/dist/browser/modules/archive/create-archive.js +13 -0
  3. package/dist/browser/modules/archive/fs/archive-file.d.ts +1 -1
  4. package/dist/browser/modules/archive/fs/types.d.ts +1 -1
  5. package/dist/browser/modules/archive/index.base.d.ts +6 -4
  6. package/dist/browser/modules/archive/index.base.js +5 -5
  7. package/dist/browser/modules/archive/read-archive.d.ts +27 -0
  8. package/dist/browser/modules/archive/read-archive.js +12 -0
  9. package/dist/browser/modules/archive/unzip/index.d.ts +0 -27
  10. package/dist/browser/modules/archive/unzip/index.js +0 -4
  11. package/dist/browser/modules/archive/{io → unzip}/remote-zip-reader.d.ts +1 -1
  12. package/dist/browser/modules/archive/{io → unzip}/remote-zip-reader.js +3 -3
  13. package/dist/browser/modules/archive/unzip/zip-reader.d.ts +1 -2
  14. package/dist/browser/modules/archive/unzip/zip-reader.js +0 -3
  15. package/dist/browser/modules/archive/zip/index.d.ts +0 -24
  16. package/dist/browser/modules/archive/zip/index.js +0 -4
  17. package/dist/browser/modules/archive/zip/zip-archive.d.ts +1 -2
  18. package/dist/browser/modules/archive/zip/zip-archive.js +42 -140
  19. package/dist/browser/modules/archive/zip/zip-editor.js +117 -207
  20. package/dist/browser/modules/archive/zip/zip-output-pipeline.d.ts +55 -0
  21. package/dist/browser/modules/archive/zip/zip-output-pipeline.js +127 -0
  22. package/dist/cjs/modules/archive/create-archive.js +16 -0
  23. package/dist/cjs/modules/archive/index.base.js +7 -9
  24. package/dist/cjs/modules/archive/read-archive.js +15 -0
  25. package/dist/cjs/modules/archive/unzip/index.js +0 -5
  26. package/dist/cjs/modules/archive/{io → unzip}/remote-zip-reader.js +3 -3
  27. package/dist/cjs/modules/archive/unzip/zip-reader.js +0 -4
  28. package/dist/cjs/modules/archive/zip/index.js +0 -5
  29. package/dist/cjs/modules/archive/zip/zip-archive.js +40 -139
  30. package/dist/cjs/modules/archive/zip/zip-editor.js +115 -205
  31. package/dist/cjs/modules/archive/zip/zip-output-pipeline.js +130 -0
  32. package/dist/esm/modules/archive/create-archive.js +13 -0
  33. package/dist/esm/modules/archive/index.base.js +5 -5
  34. package/dist/esm/modules/archive/read-archive.js +12 -0
  35. package/dist/esm/modules/archive/unzip/index.js +0 -4
  36. package/dist/esm/modules/archive/{io → unzip}/remote-zip-reader.js +3 -3
  37. package/dist/esm/modules/archive/unzip/zip-reader.js +0 -3
  38. package/dist/esm/modules/archive/zip/index.js +0 -4
  39. package/dist/esm/modules/archive/zip/zip-archive.js +42 -140
  40. package/dist/esm/modules/archive/zip/zip-editor.js +117 -207
  41. package/dist/esm/modules/archive/zip/zip-output-pipeline.js +127 -0
  42. package/dist/iife/excelts.iife.js +1 -1
  43. package/dist/iife/excelts.iife.min.js +1 -1
  44. package/dist/types/modules/archive/create-archive.d.ts +23 -0
  45. package/dist/types/modules/archive/fs/archive-file.d.ts +1 -1
  46. package/dist/types/modules/archive/fs/types.d.ts +1 -1
  47. package/dist/types/modules/archive/index.base.d.ts +6 -4
  48. package/dist/types/modules/archive/read-archive.d.ts +27 -0
  49. package/dist/types/modules/archive/unzip/index.d.ts +0 -27
  50. package/dist/types/modules/archive/{io → unzip}/remote-zip-reader.d.ts +1 -1
  51. package/dist/types/modules/archive/unzip/zip-reader.d.ts +1 -2
  52. package/dist/types/modules/archive/zip/index.d.ts +0 -24
  53. package/dist/types/modules/archive/zip/zip-archive.d.ts +1 -2
  54. package/dist/types/modules/archive/zip/zip-output-pipeline.d.ts +55 -0
  55. package/package.json +1 -1
  56. package/dist/browser/modules/archive/formats/index.d.ts +0 -9
  57. package/dist/browser/modules/archive/formats/index.js +0 -28
  58. package/dist/cjs/modules/archive/formats/index.js +0 -32
  59. package/dist/esm/modules/archive/formats/index.js +0 -28
  60. package/dist/types/modules/archive/formats/index.d.ts +0 -9
  61. /package/dist/browser/modules/archive/{formats → shared}/types.d.ts +0 -0
  62. /package/dist/browser/modules/archive/{formats → shared}/types.js +0 -0
  63. /package/dist/cjs/modules/archive/{formats → shared}/types.js +0 -0
  64. /package/dist/esm/modules/archive/{formats → shared}/types.js +0 -0
  65. /package/dist/types/modules/archive/{formats → shared}/types.d.ts +0 -0
@@ -19,13 +19,13 @@ exports.RemoteZipReader = exports.Crc32MismatchError = void 0;
19
19
  const binary_1 = require("../zip-spec/binary.js");
20
20
  const crc32_1 = require("../compression/crc32.js");
21
21
  const crypto_1 = require("../crypto/index.js");
22
- const zip_extract_core_1 = require("../unzip/zip-extract-core.js");
22
+ const zip_extract_core_1 = require("./zip-extract-core.js");
23
23
  const bytes_1 = require("../shared/bytes.js");
24
- const archive_sink_1 = require("./archive-sink.js");
24
+ const archive_sink_1 = require("../io/archive-sink.js");
25
25
  const zip_parser_core_1 = require("../zip-spec/zip-parser-core.js");
26
26
  const text_1 = require("../shared/text.js");
27
27
  const zip_records_1 = require("../zip-spec/zip-records.js");
28
- const random_access_1 = require("./random-access");
28
+ const random_access_1 = require("../io/random-access.js");
29
29
  /**
30
30
  * Error thrown when CRC32 validation fails
31
31
  */
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ZipReader = exports.UnzipEntry = void 0;
4
- exports.createZipReader = createZipReader;
5
4
  const zip_parser_1 = require("./zip-parser.js");
6
5
  const zip_extract_core_1 = require("./zip-extract-core.js");
7
6
  const stream_1 = require("./stream.js");
@@ -521,6 +520,3 @@ class ZipReader {
521
520
  }
522
521
  }
523
522
  exports.ZipReader = ZipReader;
524
- function createZipReader(source, options) {
525
- return new ZipReader(source, options);
526
- }
@@ -1,8 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ZipArchive = exports.ZipEditPlan = exports.editZipUrl = exports.editZip = exports.ZipEditor = void 0;
4
- exports.zip = zip;
5
- const formats_1 = require("../formats/index.js");
6
4
  var zip_editor_1 = require("./zip-editor");
7
5
  Object.defineProperty(exports, "ZipEditor", { enumerable: true, get: function () { return zip_editor_1.ZipEditor; } });
8
6
  Object.defineProperty(exports, "editZip", { enumerable: true, get: function () { return zip_editor_1.editZip; } });
@@ -11,6 +9,3 @@ var zip_edit_plan_1 = require("./zip-edit-plan");
11
9
  Object.defineProperty(exports, "ZipEditPlan", { enumerable: true, get: function () { return zip_edit_plan_1.ZipEditPlan; } });
12
10
  var zip_archive_1 = require("./zip-archive");
13
11
  Object.defineProperty(exports, "ZipArchive", { enumerable: true, get: function () { return zip_archive_1.ZipArchive; } });
14
- function zip(options) {
15
- return (0, formats_1.createArchive)(options);
16
- }
@@ -1,15 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ZipArchive = void 0;
4
- exports.createZipArchive = createZipArchive;
5
4
  const defaults_1 = require("../shared/defaults.js");
6
5
  const stream_1 = require("./stream.js");
7
6
  const zip_bytes_1 = require("./zip-bytes.js");
8
7
  const archive_sink_1 = require("../io/archive-sink.js");
9
8
  const archive_source_1 = require("../io/archive-source.js");
10
- const async_queue_1 = require("../shared/async-queue.js");
11
9
  const errors_1 = require("../shared/errors.js");
12
- const progress_1 = require("../shared/progress.js");
10
+ const zip_output_pipeline_1 = require("./zip-output-pipeline");
13
11
  const binary_1 = require("../../../utils/binary.js");
14
12
  const zip_records_1 = require("../zip-spec/zip-records.js");
15
13
  const env_1 = require("../../../utils/env.js");
@@ -92,147 +90,53 @@ class ZipArchive {
92
90
  const signalOpt = options.signal ?? this._streamDefaults.signal;
93
91
  const onProgress = options.onProgress ?? this._streamDefaults.onProgress;
94
92
  const progressIntervalMs = options.progressIntervalMs ?? this._streamDefaults.progressIntervalMs;
95
- const { controller, cleanup: cleanupAbortLink } = (0, errors_1.createLinkedAbortController)(signalOpt);
96
- const signal = controller.signal;
97
- const progress = new progress_1.ProgressEmitter({
98
- type: "zip",
99
- phase: "running",
100
- entriesTotal: this._entries.length,
101
- entriesDone: 0,
102
- bytesIn: 0,
103
- bytesOut: 0,
104
- zip64: this._options.zip64
105
- }, onProgress, { intervalMs: progressIntervalMs });
106
- const queue = (0, async_queue_1.createAsyncQueue)({
107
- onCancel: () => {
108
- // Consumer stopped reading; abort upstream work to avoid buffering.
109
- try {
110
- controller.abort("cancelled");
111
- }
112
- catch {
113
- // ignore
114
- }
115
- }
116
- });
117
- const zip = new stream_1.StreamingZip((err, data, final) => {
118
- if (err) {
119
- progress.update({ phase: progress.snapshot.phase === "aborted" ? "aborted" : "error" });
120
- queue.fail(err);
121
- return;
122
- }
123
- if (data.length) {
124
- progress.mutate(s => {
125
- s.bytesOut += data.length;
126
- });
127
- queue.push(data);
128
- }
129
- if (final) {
130
- if (progress.snapshot.phase === "running") {
131
- progress.update({ phase: "done" });
132
- }
133
- queue.close();
134
- }
135
- }, {
93
+ return (0, zip_output_pipeline_1.createZipOperation)(this._entries.length, {
136
94
  comment: this._options.comment,
137
95
  zip64: this._options.zip64,
138
96
  encoding: this._options.encoding
139
- });
140
- const onAbort = () => {
141
- const err = (0, errors_1.createAbortError)(signal.reason);
142
- progress.update({ phase: "aborted" });
143
- try {
144
- zip.abort(err);
145
- }
146
- catch {
147
- // ignore
148
- }
149
- queue.fail(err);
150
- };
151
- signal.addEventListener("abort", onAbort, { once: true });
152
- (async () => {
153
- try {
154
- for (let i = 0; i < this._entries.length; i++) {
155
- (0, errors_1.throwIfAborted)(signal);
156
- const entry = this._entries[i];
157
- let entryBytesIn = 0;
158
- progress.update({ currentEntry: { name: entry.name, index: i, bytesIn: 0 } });
159
- const file = new stream_1.ZipDeflateFile(entry.name, (0, zip_entry_options_1.buildZipDeflateFileOptions)(entry.options, {
160
- level: this._options.level,
161
- modTime: this._options.modTime,
162
- timestamps: this._options.timestamps,
163
- smartStore: this._options.smartStore,
164
- zip64: this._options.zip64,
165
- path: this._options.path,
166
- encoding: this._options.encoding
167
- }));
168
- zip.add(file);
169
- const onChunk = (chunk) => {
170
- entryBytesIn += chunk.length;
171
- progress.mutate(s => {
172
- s.bytesIn += chunk.length;
173
- s.currentEntry = { name: entry.name, index: i, bytesIn: entryBytesIn };
174
- });
175
- };
176
- if ((0, archive_source_1.isSyncArchiveSource)(entry.source)) {
177
- const bytes = (0, archive_source_1.toUint8ArraySync)(entry.source);
178
- (0, errors_1.throwIfAborted)(signal);
179
- onChunk(bytes);
180
- await file.push(bytes, true);
181
- }
182
- else {
183
- for await (const chunk of (0, archive_source_1.toAsyncIterable)(entry.source, { signal, onChunk })) {
184
- (0, errors_1.throwIfAborted)(signal);
185
- await file.push(chunk, false);
186
- }
187
- (0, errors_1.throwIfAborted)(signal);
188
- await file.push(new Uint8Array(0), true);
189
- }
190
- await file.complete();
191
- progress.set("entriesDone", progress.snapshot.entriesDone + 1);
192
- }
97
+ }, { signal: signalOpt, onProgress, progressIntervalMs }, async ({ zip, signal, progress }) => {
98
+ for (let i = 0; i < this._entries.length; i++) {
193
99
  (0, errors_1.throwIfAborted)(signal);
194
- zip.end();
195
- }
196
- catch (e) {
197
- const err = (0, errors_1.toError)(e);
198
- if (err.name === "AbortError") {
199
- progress.update({ phase: "aborted" });
200
- try {
201
- zip.abort(err);
202
- }
203
- catch {
204
- // ignore
205
- }
100
+ const entry = this._entries[i];
101
+ let entryBytesIn = 0;
102
+ progress.update({ currentEntry: { name: entry.name, index: i, bytesIn: 0 } });
103
+ const file = new stream_1.ZipDeflateFile(entry.name, (0, zip_entry_options_1.buildZipDeflateFileOptions)(entry.options, {
104
+ level: this._options.level,
105
+ modTime: this._options.modTime,
106
+ timestamps: this._options.timestamps,
107
+ smartStore: this._options.smartStore,
108
+ zip64: this._options.zip64,
109
+ path: this._options.path,
110
+ encoding: this._options.encoding
111
+ }));
112
+ zip.add(file);
113
+ const onChunk = (chunk) => {
114
+ entryBytesIn += chunk.length;
115
+ progress.mutate(s => {
116
+ s.bytesIn += chunk.length;
117
+ s.currentEntry = { name: entry.name, index: i, bytesIn: entryBytesIn };
118
+ });
119
+ };
120
+ if ((0, archive_source_1.isSyncArchiveSource)(entry.source)) {
121
+ const bytes = (0, archive_source_1.toUint8ArraySync)(entry.source);
122
+ (0, errors_1.throwIfAborted)(signal);
123
+ onChunk(bytes);
124
+ await file.push(bytes, true);
206
125
  }
207
126
  else {
208
- progress.update({ phase: "error" });
209
- }
210
- queue.fail(err);
211
- }
212
- finally {
213
- try {
214
- signal.removeEventListener("abort", onAbort);
215
- }
216
- catch {
217
- // ignore
127
+ for await (const chunk of (0, archive_source_1.toAsyncIterable)(entry.source, { signal, onChunk })) {
128
+ (0, errors_1.throwIfAborted)(signal);
129
+ await file.push(chunk, false);
130
+ }
131
+ (0, errors_1.throwIfAborted)(signal);
132
+ await file.push(new Uint8Array(0), true);
218
133
  }
219
- cleanupAbortLink();
220
- progress.emitNow();
134
+ await file.complete();
135
+ progress.set("entriesDone", progress.snapshot.entriesDone + 1);
221
136
  }
222
- })();
223
- return {
224
- iterable: queue.iterable,
225
- signal,
226
- abort(reason) {
227
- controller.abort(reason);
228
- },
229
- pointer() {
230
- return progress.snapshot.bytesOut;
231
- },
232
- progress() {
233
- return progress.snapshotCopy();
234
- }
235
- };
137
+ (0, errors_1.throwIfAborted)(signal);
138
+ zip.end();
139
+ });
236
140
  }
237
141
  /**
238
142
  * Browser-only fast path: stream sources through CompressionStream while
@@ -448,6 +352,3 @@ class ZipArchive {
448
352
  }
449
353
  }
450
354
  exports.ZipArchive = ZipArchive;
451
- function createZipArchive(options) {
452
- return new ZipArchive(options);
453
- }
@@ -7,12 +7,11 @@ const timestamps_1 = require("../zip-spec/timestamps.js");
7
7
  const text_1 = require("../shared/text.js");
8
8
  const defaults_1 = require("../shared/defaults.js");
9
9
  const random_access_1 = require("../io/random-access.js");
10
- const remote_zip_reader_1 = require("../io/remote-zip-reader.js");
10
+ const remote_zip_reader_1 = require("../unzip/remote-zip-reader.js");
11
11
  const archive_source_1 = require("../io/archive-source.js");
12
12
  const archive_sink_1 = require("../io/archive-sink.js");
13
- const async_queue_1 = require("../shared/async-queue.js");
14
13
  const errors_1 = require("../shared/errors.js");
15
- const progress_1 = require("../shared/progress.js");
14
+ const zip_output_pipeline_1 = require("./zip-output-pipeline");
16
15
  const stream_1 = require("./stream.js");
17
16
  const zip_bytes_1 = require("./zip-bytes.js");
18
17
  const zip_records_1 = require("../zip-spec/zip-records.js");
@@ -365,226 +364,137 @@ class ZipEditor {
365
364
  const signalOpt = options.signal ?? this._streamDefaults.signal;
366
365
  const onProgress = options.onProgress ?? this._streamDefaults.onProgress;
367
366
  const progressIntervalMs = options.progressIntervalMs ?? this._streamDefaults.progressIntervalMs;
368
- const { controller, cleanup: cleanupAbortLink } = (0, errors_1.createLinkedAbortController)(signalOpt);
369
- const signal = controller.signal;
370
367
  const preservedMeta = this._buildRawPreservedEntries();
371
368
  const sets = this._buildSetEntries();
372
- const preservedRaw = [];
373
- const preservedRecompressed = [];
374
- for (const p of preservedMeta) {
375
- const compressedData = this._remote.getRawCompressedStream(p.info.path, { signal });
376
- if (compressedData) {
377
- preservedRaw.push({ ...p, compressedData });
378
- continue;
379
- }
380
- this._emitWarning(p.info.path, "raw_unavailable", `Cannot read raw compressed payload for entry "${p.info.path}".`);
381
- if (this._options.preserve === "strict") {
382
- throw new Error(`Cannot preserve entry "${p.info.path}" because its raw compressed payload is unavailable.`);
369
+ return (0, zip_output_pipeline_1.createZipOperation)(preservedMeta.length + sets.length, {
370
+ comment: this._options.comment,
371
+ zip64: this._options.zip64,
372
+ codec: this._stringCodec
373
+ }, { signal: signalOpt, onProgress, progressIntervalMs }, async ({ zip, signal, progress }) => {
374
+ // Classify preserved entries using the pipeline's linked signal so that
375
+ // abort() properly cancels raw compressed streams.
376
+ const preservedRaw = [];
377
+ const preservedRecompressed = [];
378
+ for (const p of preservedMeta) {
379
+ const compressedData = this._remote.getRawCompressedStream(p.info.path, { signal });
380
+ if (compressedData) {
381
+ preservedRaw.push({ ...p, compressedData });
382
+ continue;
383
+ }
384
+ this._emitWarning(p.info.path, "raw_unavailable", `Cannot read raw compressed payload for entry "${p.info.path}".`);
385
+ if (this._options.preserve === "strict") {
386
+ throw new Error(`Cannot preserve entry "${p.info.path}" because its raw compressed payload is unavailable.`);
387
+ }
388
+ // We cannot re-encrypt entries; best-effort must not silently output decrypted content.
389
+ if (p.info.isEncrypted) {
390
+ this._emitWarning(p.info.path, "encryption_unsupported", `Cannot best-effort preserve encrypted entry "${p.info.path}" without raw passthrough.`);
391
+ continue;
392
+ }
393
+ // Best-effort fallback: extract and re-add the entry.
394
+ preservedRecompressed.push({ name: p.outName, info: p.info });
383
395
  }
384
- // We cannot re-encrypt entries; best-effort must not silently output decrypted content.
385
- if (p.info.isEncrypted) {
386
- this._emitWarning(p.info.path, "encryption_unsupported", `Cannot best-effort preserve encrypted entry "${p.info.path}" without raw passthrough.`);
387
- continue;
396
+ // Update entriesTotal now that we know how many entries survived classification.
397
+ const actualTotal = preservedRaw.length + preservedRecompressed.length + sets.length;
398
+ progress.set("entriesTotal", actualTotal);
399
+ // 1) Preserved entries: passthrough raw payload.
400
+ for (let i = 0; i < preservedRaw.length; i++) {
401
+ (0, errors_1.throwIfAborted)(signal);
402
+ const entry = preservedRaw[i];
403
+ progress.update({ currentEntry: { name: entry.outName, index: i, bytesIn: 0 } });
404
+ const rawFile = this._buildPreservedRawFile(entry.outName, entry.info, entry.compressedData, this._options.zip64);
405
+ zip.add(rawFile);
406
+ // StreamingZip auto-starts passthrough files; await completion for accurate progress.
407
+ await rawFile.done();
408
+ progress.set("entriesDone", progress.snapshot.entriesDone + 1);
388
409
  }
389
- // Best-effort fallback: extract and re-add the entry.
390
- // This may require holding the entry in memory.
391
- preservedRecompressed.push({ name: p.outName, info: p.info });
392
- }
393
- const progress = new progress_1.ProgressEmitter({
394
- type: "zip",
395
- phase: "running",
396
- entriesTotal: preservedRaw.length + preservedRecompressed.length + sets.length,
397
- entriesDone: 0,
398
- bytesIn: 0,
399
- bytesOut: 0,
400
- zip64: this._options.zip64
401
- }, onProgress, { intervalMs: progressIntervalMs });
402
- const queue = (0, async_queue_1.createAsyncQueue)({
403
- onCancel: () => {
410
+ // 1b) Best-effort preserved entries: extract and re-add.
411
+ for (let k = 0; k < preservedRecompressed.length; k++) {
412
+ (0, errors_1.throwIfAborted)(signal);
413
+ const idx = preservedRaw.length + k;
414
+ const entry = preservedRecompressed[k];
415
+ let entryBytesIn = 0;
416
+ progress.update({ currentEntry: { name: entry.name, index: idx, bytesIn: 0 } });
417
+ let data;
404
418
  try {
405
- controller.abort("cancelled");
419
+ data = await this._remote.extractEntry(entry.info);
406
420
  }
407
- catch {
408
- // ignore
421
+ catch (e) {
422
+ const err = (0, errors_1.toError)(e);
423
+ this._emitWarning(entry.info.path, "unknown", `Failed to extract entry "${entry.info.path}" for best-effort preserve: ${err.message}`);
424
+ progress.set("entriesDone", progress.snapshot.entriesDone + 1);
425
+ continue;
409
426
  }
410
- }
411
- });
412
- const zip = new stream_1.StreamingZip((err, data, final) => {
413
- if (err) {
414
- progress.update({ phase: progress.snapshot.phase === "aborted" ? "aborted" : "error" });
415
- queue.fail(err);
416
- return;
417
- }
418
- if (data.length) {
427
+ const fallbackLevel = entry.info.compressionMethod === 0 ? 0 : this._options.level;
428
+ const file = new stream_1.ZipDeflateFile(entry.name, (0, zip_entry_options_1.buildZipDeflateFileOptions)({
429
+ level: fallbackLevel,
430
+ modTime: entry.info.lastModified,
431
+ comment: entry.info.comment,
432
+ externalAttributes: entry.info.externalAttributes,
433
+ versionMadeBy: entry.info.versionMadeBy
434
+ }, {
435
+ level: this._options.level,
436
+ modTime: this._options.modTime,
437
+ timestamps: this._options.timestamps,
438
+ smartStore: this._options.smartStore,
439
+ zip64: this._options.zip64,
440
+ path: this._options.path,
441
+ encoding: this._options.encoding
442
+ }));
443
+ zip.add(file);
444
+ entryBytesIn += data.length;
419
445
  progress.mutate(s => {
420
- s.bytesOut += data.length;
446
+ s.bytesIn += data.length;
447
+ s.currentEntry = { name: entry.name, index: idx, bytesIn: entryBytesIn };
421
448
  });
422
- queue.push(data);
423
- }
424
- if (final) {
425
- if (progress.snapshot.phase === "running") {
426
- progress.update({ phase: "done" });
427
- }
428
- queue.close();
449
+ await file.push(data, true);
450
+ await file.complete();
451
+ progress.set("entriesDone", progress.snapshot.entriesDone + 1);
429
452
  }
430
- }, {
431
- comment: this._options.comment,
432
- zip64: this._options.zip64,
433
- codec: this._stringCodec
434
- });
435
- const onAbort = () => {
436
- const err = (0, errors_1.createAbortError)(signal.reason);
437
- progress.update({ phase: "aborted" });
438
- try {
439
- zip.abort(err);
440
- }
441
- catch {
442
- // ignore
443
- }
444
- queue.fail(err);
445
- };
446
- signal.addEventListener("abort", onAbort, { once: true });
447
- (async () => {
448
- try {
449
- // 1) Preserved entries: passthrough raw payload.
450
- for (let i = 0; i < preservedRaw.length; i++) {
451
- (0, errors_1.throwIfAborted)(signal);
452
- const entry = preservedRaw[i];
453
- progress.update({ currentEntry: { name: entry.outName, index: i, bytesIn: 0 } });
454
- const rawFile = this._buildPreservedRawFile(entry.outName, entry.info, entry.compressedData, this._options.zip64);
455
- zip.add(rawFile);
456
- // StreamingZip auto-starts passthrough files; await completion for accurate progress.
457
- await rawFile.done();
458
- progress.set("entriesDone", progress.snapshot.entriesDone + 1);
459
- }
460
- // 1b) Best-effort preserved entries: extract and re-add.
461
- for (let k = 0; k < preservedRecompressed.length; k++) {
462
- (0, errors_1.throwIfAborted)(signal);
463
- const idx = preservedRaw.length + k;
464
- const entry = preservedRecompressed[k];
465
- let entryBytesIn = 0;
466
- progress.update({ currentEntry: { name: entry.name, index: idx, bytesIn: 0 } });
467
- let data;
468
- try {
469
- data = await this._remote.extractEntry(entry.info);
470
- }
471
- catch (e) {
472
- const err = (0, errors_1.toError)(e);
473
- this._emitWarning(entry.info.path, "unknown", `Failed to extract entry "${entry.info.path}" for best-effort preserve: ${err.message}`);
474
- progress.set("entriesDone", progress.snapshot.entriesDone + 1);
475
- continue;
476
- }
477
- const fallbackLevel = entry.info.compressionMethod === 0 ? 0 : this._options.level;
478
- const file = new stream_1.ZipDeflateFile(entry.name, (0, zip_entry_options_1.buildZipDeflateFileOptions)({
479
- level: fallbackLevel,
480
- modTime: entry.info.lastModified,
481
- comment: entry.info.comment,
482
- externalAttributes: entry.info.externalAttributes,
483
- versionMadeBy: entry.info.versionMadeBy
484
- }, {
485
- level: this._options.level,
486
- modTime: this._options.modTime,
487
- timestamps: this._options.timestamps,
488
- smartStore: this._options.smartStore,
489
- zip64: this._options.zip64,
490
- path: this._options.path,
491
- encoding: this._options.encoding
492
- }));
493
- zip.add(file);
494
- entryBytesIn += data.length;
453
+ // 2) Set/update entries: compress from source.
454
+ for (let j = 0; j < sets.length; j++) {
455
+ (0, errors_1.throwIfAborted)(signal);
456
+ const idx = preservedRaw.length + preservedRecompressed.length + j;
457
+ const entry = sets[j];
458
+ let entryBytesIn = 0;
459
+ progress.update({ currentEntry: { name: entry.name, index: idx, bytesIn: 0 } });
460
+ const file = new stream_1.ZipDeflateFile(entry.name, (0, zip_entry_options_1.buildZipDeflateFileOptions)(entry.options, {
461
+ level: this._options.level,
462
+ modTime: this._options.modTime,
463
+ timestamps: this._options.timestamps,
464
+ smartStore: this._options.smartStore,
465
+ zip64: this._options.zip64,
466
+ path: this._options.path,
467
+ encoding: this._options.encoding
468
+ }));
469
+ zip.add(file);
470
+ const onChunk = (chunk) => {
471
+ entryBytesIn += chunk.length;
495
472
  progress.mutate(s => {
496
- s.bytesIn += data.length;
473
+ s.bytesIn += chunk.length;
497
474
  s.currentEntry = { name: entry.name, index: idx, bytesIn: entryBytesIn };
498
475
  });
499
- await file.push(data, true);
500
- await file.complete();
501
- progress.set("entriesDone", progress.snapshot.entriesDone + 1);
502
- }
503
- // 2) Set/update entries: compress from source.
504
- for (let j = 0; j < sets.length; j++) {
476
+ };
477
+ if ((0, archive_source_1.isSyncArchiveSource)(entry.source)) {
478
+ const bytes = (0, archive_source_1.toUint8ArraySync)(entry.source);
505
479
  (0, errors_1.throwIfAborted)(signal);
506
- const idx = preservedRaw.length + preservedRecompressed.length + j;
507
- const entry = sets[j];
508
- let entryBytesIn = 0;
509
- progress.update({ currentEntry: { name: entry.name, index: idx, bytesIn: 0 } });
510
- const file = new stream_1.ZipDeflateFile(entry.name, (0, zip_entry_options_1.buildZipDeflateFileOptions)(entry.options, {
511
- level: this._options.level,
512
- modTime: this._options.modTime,
513
- timestamps: this._options.timestamps,
514
- smartStore: this._options.smartStore,
515
- zip64: this._options.zip64,
516
- path: this._options.path,
517
- encoding: this._options.encoding
518
- }));
519
- zip.add(file);
520
- const onChunk = (chunk) => {
521
- entryBytesIn += chunk.length;
522
- progress.mutate(s => {
523
- s.bytesIn += chunk.length;
524
- s.currentEntry = { name: entry.name, index: idx, bytesIn: entryBytesIn };
525
- });
526
- };
527
- if ((0, archive_source_1.isSyncArchiveSource)(entry.source)) {
528
- const bytes = (0, archive_source_1.toUint8ArraySync)(entry.source);
529
- (0, errors_1.throwIfAborted)(signal);
530
- onChunk(bytes);
531
- await file.push(bytes, true);
532
- }
533
- else {
534
- // Streaming path (includes Blob via toAsyncIterable(Blob) which prefers Blob.stream())
535
- for await (const chunk of (0, archive_source_1.toAsyncIterable)(entry.source, { signal, onChunk })) {
536
- (0, errors_1.throwIfAborted)(signal);
537
- await file.push(chunk, false);
538
- }
539
- (0, errors_1.throwIfAborted)(signal);
540
- await file.push(new Uint8Array(0), true);
541
- }
542
- await file.complete();
543
- progress.set("entriesDone", progress.snapshot.entriesDone + 1);
544
- }
545
- (0, errors_1.throwIfAborted)(signal);
546
- zip.end();
547
- }
548
- catch (e) {
549
- const err = (0, errors_1.toError)(e);
550
- if (err.name === "AbortError") {
551
- progress.update({ phase: "aborted" });
552
- try {
553
- zip.abort(err);
554
- }
555
- catch {
556
- // ignore
557
- }
480
+ onChunk(bytes);
481
+ await file.push(bytes, true);
558
482
  }
559
483
  else {
560
- progress.update({ phase: "error" });
561
- }
562
- queue.fail(err);
563
- }
564
- finally {
565
- try {
566
- signal.removeEventListener("abort", onAbort);
567
- }
568
- catch {
569
- // ignore
484
+ // Streaming path (includes Blob via toAsyncIterable(Blob) which prefers Blob.stream())
485
+ for await (const chunk of (0, archive_source_1.toAsyncIterable)(entry.source, { signal, onChunk })) {
486
+ (0, errors_1.throwIfAborted)(signal);
487
+ await file.push(chunk, false);
488
+ }
489
+ (0, errors_1.throwIfAborted)(signal);
490
+ await file.push(new Uint8Array(0), true);
570
491
  }
571
- cleanupAbortLink();
572
- progress.emitNow();
492
+ await file.complete();
493
+ progress.set("entriesDone", progress.snapshot.entriesDone + 1);
573
494
  }
574
- })();
575
- return {
576
- iterable: queue.iterable,
577
- signal,
578
- abort(reason) {
579
- controller.abort(reason);
580
- },
581
- pointer() {
582
- return progress.snapshot.bytesOut;
583
- },
584
- progress() {
585
- return progress.snapshotCopy();
586
- }
587
- };
495
+ (0, errors_1.throwIfAborted)(signal);
496
+ zip.end();
497
+ });
588
498
  }
589
499
  /**
590
500
  * Get the output as a single Uint8Array.