documonster 0.19.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README_zh.md +1 -1
- package/dist/esm/modules/archive/compression/compress.base.js +20 -6
- package/dist/esm/modules/archive/compression/compress.browser.js +45 -32
- package/dist/esm/modules/archive/compression/compress.js +74 -18
- package/dist/esm/modules/archive/compression/deflate-fallback.js +14 -3
- package/dist/esm/modules/archive/compression/worker-pool/pool.browser.js +9 -3
- package/dist/esm/modules/archive/compression/worker-pool/worker-script.js +35 -7
- package/dist/esm/modules/archive/core/errors.js +26 -4
- package/dist/esm/modules/archive/index.base.js +1 -1
- package/dist/esm/modules/archive/unzip/zip-extract-core.js +74 -34
- package/dist/esm/modules/archive/unzip/zip-parser.js +55 -9
- package/dist/esm/modules/archive/zip-spec/zip-parser-core.js +14 -2
- package/dist/esm/modules/csv/parse/scanner/scanner.js +3 -0
- package/dist/esm/modules/csv/parse/sync.js +3 -2
- package/dist/esm/modules/csv/stream/parser.js +40 -4
- package/dist/esm/modules/csv/worker/worker-script.generated.js +1 -1
- package/dist/esm/modules/excel/core/cell.js +22 -2
- package/dist/esm/modules/excel/core/table.js +39 -2
- package/dist/esm/modules/excel/core/worksheet-core.js +39 -0
- package/dist/esm/modules/excel/core/worksheet-load.js +3 -1
- package/dist/esm/modules/excel/stream/workbook-reader.browser.js +34 -11
- package/dist/esm/modules/excel/surface/cell.js +64 -23
- package/dist/esm/modules/excel/utils/cell-format.js +3 -2
- package/dist/esm/modules/excel/xlsb/read/package.js +3 -1
- package/dist/esm/modules/excel/xlsx/read/package.js +17 -1
- package/dist/esm/modules/pdf/builder/document-builder.js +3 -1
- package/dist/esm/modules/pdf/builder/pdf-editor.js +218 -58
- package/dist/esm/modules/pdf/core/pdf-kdf.browser.js +9 -1
- package/dist/esm/modules/pdf/core/pdf-kdf.js +8 -0
- package/dist/esm/modules/pdf/core/pdf-writer.js +159 -149
- package/dist/esm/modules/pdf/core/pdfa.js +7 -3
- package/dist/esm/modules/pdf/errors.js +25 -0
- package/dist/esm/modules/pdf/index.js +1 -1
- package/dist/esm/modules/pdf/reader/pdf-decrypt.js +136 -74
- package/dist/esm/modules/pdf/reader/pdf-document.js +314 -105
- package/dist/esm/modules/pdf/reader/pdf-parser.js +29 -11
- package/dist/esm/modules/pdf/reader/pdf-reader.js +8 -1
- package/dist/esm/modules/pdf/reader/stream-filters.js +139 -77
- package/dist/esm/modules/pdf/render/pdf-exporter.js +3 -1
- package/dist/esm/modules/pdf/word-bridge.js +22 -48
- package/dist/esm/modules/word/advanced/field-engine.js +75 -56
- package/dist/esm/modules/word/builder/document-handle.js +15 -1
- package/dist/esm/modules/word/convert/docx-to-semantic.js +84 -83
- package/dist/esm/modules/word/convert/html/html-renderer.js +107 -78
- package/dist/esm/modules/word/convert/markdown/markdown-import.js +43 -10
- package/dist/esm/modules/word/convert/markdown/markdown-renderer.js +98 -130
- package/dist/esm/modules/word/convert/odt/odt.js +149 -55
- package/dist/esm/modules/word/core/text-utils.js +9 -0
- package/dist/esm/modules/word/errors.js +1 -1
- package/dist/esm/modules/word/layout/layout-constants.js +20 -23
- package/dist/esm/modules/word/layout/layout-full.js +259 -280
- package/dist/esm/modules/word/layout/layout.js +140 -197
- package/dist/esm/modules/word/query/final-view.js +49 -0
- package/dist/esm/modules/word/query/heading.js +81 -0
- package/dist/esm/modules/word/query/merge.js +39 -22
- package/dist/esm/modules/word/query/numbering-counter.js +108 -0
- package/dist/esm/modules/word/query/page-field.js +212 -0
- package/dist/esm/modules/word/query/search.js +15 -14
- package/dist/esm/modules/word/query/split.js +15 -25
- package/dist/esm/modules/word/query/style-resolve.js +196 -53
- package/dist/esm/modules/word/query/style-resolver.js +24 -0
- package/dist/esm/modules/word/reader/chart-parser.js +17 -7
- package/dist/esm/modules/word/reader/comments-parser.js +4 -4
- package/dist/esm/modules/word/reader/doc-props-parsers.js +10 -9
- package/dist/esm/modules/word/reader/docx-reader.js +46 -32
- package/dist/esm/modules/word/reader/metadata-parsers.js +5 -5
- package/dist/esm/modules/word/reader/numbering-parser.js +4 -3
- package/dist/esm/modules/word/reader/part-xml.js +26 -0
- package/dist/esm/modules/word/reader/reader-context.js +3 -3
- package/dist/esm/modules/word/reader/settings-parser.js +3 -3
- package/dist/esm/modules/word/reader/styles-parser.js +3 -3
- package/dist/esm/modules/word/reader/theme-parser.js +4 -3
- package/dist/esm/modules/word/surface/query.js +1 -1
- package/dist/esm/modules/word/writer/docx-packager.js +4 -1
- package/dist/esm/modules/word/writer/streaming-writer.js +11 -2
- package/dist/esm/modules/xml/dom.js +4 -8
- package/dist/esm/modules/xml/errors.js +1 -3
- package/dist/esm/modules/xml/sax.js +8 -7
- package/dist/esm/modules/xml/to-object.js +4 -8
- package/dist/esm/utils/crypto.browser.js +147 -0
- package/dist/esm/utils/crypto.js +14 -0
- package/dist/esm/utils/limits.js +19 -0
- package/dist/iife/documonster.archive.iife.min.js +39 -11
- package/dist/iife/documonster.csv.iife.min.js +17 -17
- package/dist/iife/documonster.draw.iife.min.js +1 -1
- package/dist/iife/documonster.excel.iife.min.js +88 -60
- package/dist/iife/documonster.formula.iife.min.js +1 -1
- package/dist/iife/documonster.markdown.iife.min.js +1 -1
- package/dist/iife/documonster.mermaid.iife.min.js +1 -1
- package/dist/iife/documonster.pdf.iife.min.js +44 -42
- package/dist/iife/documonster.stream.iife.min.js +1 -1
- package/dist/iife/documonster.word.iife.min.js +95 -67
- package/dist/iife/documonster.xml.iife.min.js +6 -6
- package/dist/types/modules/archive/compression/compress.base.d.ts +12 -3
- package/dist/types/modules/archive/compression/compress.browser.d.ts +7 -4
- package/dist/types/modules/archive/compression/compress.d.ts +9 -4
- package/dist/types/modules/archive/compression/deflate-fallback.d.ts +3 -1
- package/dist/types/modules/archive/compression/worker-pool/pool.browser.d.ts +4 -1
- package/dist/types/modules/archive/compression/worker-pool/types.d.ts +4 -0
- package/dist/types/modules/archive/core/errors.d.ts +31 -2
- package/dist/types/modules/archive/index.base.d.ts +1 -1
- package/dist/types/modules/archive/unzip/zip-extract-core.d.ts +9 -2
- package/dist/types/modules/archive/unzip/zip-parser.d.ts +33 -0
- package/dist/types/modules/archive/zip-spec/zip-parser-core.d.ts +6 -0
- package/dist/types/modules/csv/parse/scanner/types.d.ts +5 -0
- package/dist/types/modules/csv/stream/parser.d.ts +16 -0
- package/dist/types/modules/csv/worker/worker-script.generated.d.ts +1 -1
- package/dist/types/modules/excel/core/table.d.ts +15 -0
- package/dist/types/modules/excel/core/worksheet-core.d.ts +26 -0
- package/dist/types/modules/excel/stream/workbook-reader.browser.d.ts +11 -0
- package/dist/types/modules/excel/surface/cell.d.ts +8 -8
- package/dist/types/modules/excel/xlsx/types.d.ts +16 -0
- package/dist/types/modules/pdf/builder/document-builder.d.ts +7 -0
- package/dist/types/modules/pdf/builder/pdf-editor.d.ts +49 -5
- package/dist/types/modules/pdf/core/pdf-kdf.browser.d.ts +4 -0
- package/dist/types/modules/pdf/core/pdf-kdf.d.ts +4 -0
- package/dist/types/modules/pdf/core/pdf-writer.d.ts +49 -10
- package/dist/types/modules/pdf/core/pdfa.d.ts +2 -0
- package/dist/types/modules/pdf/errors.d.ts +19 -0
- package/dist/types/modules/pdf/index.d.ts +2 -2
- package/dist/types/modules/pdf/reader/pdf-document.d.ts +83 -5
- package/dist/types/modules/pdf/reader/pdf-parser.d.ts +2 -2
- package/dist/types/modules/pdf/reader/pdf-reader.d.ts +7 -0
- package/dist/types/modules/pdf/reader/stream-filters.d.ts +5 -1
- package/dist/types/modules/pdf/types.d.ts +7 -0
- package/dist/types/modules/word/convert/conversion-ir.d.ts +2 -0
- package/dist/types/modules/word/core/text-utils.d.ts +7 -1
- package/dist/types/modules/word/errors.d.ts +3 -3
- package/dist/types/modules/word/index.base.d.ts +1 -1
- package/dist/types/modules/word/layout/layout-constants.d.ts +13 -9
- package/dist/types/modules/word/query/final-view.d.ts +26 -0
- package/dist/types/modules/word/query/heading.d.ts +30 -0
- package/dist/types/modules/word/query/numbering-counter.d.ts +47 -0
- package/dist/types/modules/word/query/page-field.d.ts +79 -0
- package/dist/types/modules/word/query/search.d.ts +8 -2
- package/dist/types/modules/word/query/split.d.ts +4 -1
- package/dist/types/modules/word/query/style-resolve.d.ts +58 -11
- package/dist/types/modules/word/query/style-resolver.d.ts +29 -0
- package/dist/types/modules/word/reader/chart-parser.d.ts +2 -2
- package/dist/types/modules/word/reader/comments-parser.d.ts +1 -1
- package/dist/types/modules/word/reader/doc-props-parsers.d.ts +4 -4
- package/dist/types/modules/word/reader/metadata-parsers.d.ts +2 -2
- package/dist/types/modules/word/reader/numbering-parser.d.ts +1 -1
- package/dist/types/modules/word/reader/part-xml.d.ts +14 -0
- package/dist/types/modules/word/reader/reader-context.d.ts +1 -1
- package/dist/types/modules/word/reader/settings-parser.d.ts +1 -1
- package/dist/types/modules/word/reader/styles-parser.d.ts +1 -1
- package/dist/types/modules/word/reader/theme-parser.d.ts +1 -1
- package/dist/types/modules/word/surface/query.d.ts +2 -1
- package/dist/types/modules/word/types.d.ts +5 -1
- package/dist/types/modules/word/writer/docx-packager.d.ts +7 -0
- package/dist/types/modules/word/writer/streaming-writer.d.ts +7 -0
- package/dist/types/modules/xml/errors.d.ts +9 -0
- package/dist/types/modules/xml/index.d.ts +1 -0
- package/dist/types/modules/xml/sax.d.ts +2 -1
- package/dist/types/utils/crypto.browser.d.ts +10 -0
- package/dist/types/utils/crypto.d.ts +10 -0
- package/dist/types/utils/limits.d.ts +12 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -211,7 +211,7 @@ const buffer = await Workbook.toBuffer(wb);
|
|
|
211
211
|
|
|
212
212
|
```html
|
|
213
213
|
<!-- Script tag (no bundler) — one IIFE per module, each under the shared `Documonster` global -->
|
|
214
|
-
<script src="https://unpkg.com/documonster@0.
|
|
214
|
+
<script src="https://unpkg.com/documonster@0.20.0/dist/iife/documonster.excel.iife.min.js"></script>
|
|
215
215
|
<script>
|
|
216
216
|
const { Workbook, Cell } = Documonster.Excel;
|
|
217
217
|
const wb = Workbook.create();
|
package/README_zh.md
CHANGED
|
@@ -198,7 +198,7 @@ const buffer = await Workbook.toBuffer(wb);
|
|
|
198
198
|
|
|
199
199
|
```html
|
|
200
200
|
<!-- Script 标签(无需打包工具)— 每个模块一个 IIFE,共享同一个 `Documonster` 全局 -->
|
|
201
|
-
<script src="https://unpkg.com/documonster@0.
|
|
201
|
+
<script src="https://unpkg.com/documonster@0.20.0/dist/iife/documonster.excel.iife.min.js"></script>
|
|
202
202
|
<script>
|
|
203
203
|
const { Workbook, Cell } = Documonster.Excel;
|
|
204
204
|
const wb = Workbook.create();
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* see deflate-fallback.ts for pure JS implementation
|
|
10
10
|
*/
|
|
11
11
|
import { ByteQueue } from "../core/byte-queue.js";
|
|
12
|
-
import { ArchiveError } from "../core/errors.js";
|
|
12
|
+
import { ArchiveError, ArchiveLimitError } from "../core/errors.js";
|
|
13
13
|
/**
|
|
14
14
|
* Default threshold (in bytes) to choose the lower-overhead path.
|
|
15
15
|
*
|
|
@@ -106,18 +106,23 @@ export function hasDeflateRawDecompressionStream() {
|
|
|
106
106
|
export function hasDeflateRawWebStreams() {
|
|
107
107
|
return hasDeflateRawCompressionStream() && hasDeflateRawDecompressionStream();
|
|
108
108
|
}
|
|
109
|
-
export async function streamToUint8Array(reader) {
|
|
109
|
+
export async function streamToUint8Array(reader, maxOutputLength) {
|
|
110
110
|
const out = new ByteQueue();
|
|
111
111
|
while (true) {
|
|
112
112
|
const { done, value } = await reader.read();
|
|
113
113
|
if (done) {
|
|
114
114
|
break;
|
|
115
115
|
}
|
|
116
|
+
if (maxOutputLength !== undefined && out.length + value.length > maxOutputLength) {
|
|
117
|
+
// Stop pulling: the transform is cancelled by the caller, so nothing
|
|
118
|
+
// beyond this chunk is ever produced or buffered.
|
|
119
|
+
throw new ArchiveLimitError("maxOutputLength", maxOutputLength);
|
|
120
|
+
}
|
|
116
121
|
out.append(value);
|
|
117
122
|
}
|
|
118
123
|
return out.read(out.length);
|
|
119
124
|
}
|
|
120
|
-
export async function transformWithStream(data, stream) {
|
|
125
|
+
export async function transformWithStream(data, stream, maxOutputLength) {
|
|
121
126
|
const writer = stream.writable.getWriter();
|
|
122
127
|
const reader = stream.readable.getReader();
|
|
123
128
|
// Start reading immediately to avoid potential backpressure deadlocks
|
|
@@ -132,7 +137,16 @@ export async function transformWithStream(data, stream) {
|
|
|
132
137
|
// though the caller had caught the failure and recovered via the pure-JS
|
|
133
138
|
// fallback. A promise with both handlers already attached can never become
|
|
134
139
|
// one, so abandoning it is safe on every path below.
|
|
135
|
-
const read = streamToUint8Array(reader).then(value => ({ ok: true, value }), (error) =>
|
|
140
|
+
const read = streamToUint8Array(reader, maxOutputLength).then(value => ({ ok: true, value }), (error) => {
|
|
141
|
+
// A limit hit leaves the transform mid-flight; cancel it so the
|
|
142
|
+
// pending write settles and no further output is produced.
|
|
143
|
+
if (error instanceof ArchiveLimitError) {
|
|
144
|
+
reader.cancel(error).catch(() => {
|
|
145
|
+
// ignore
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return { ok: false, error };
|
|
149
|
+
});
|
|
136
150
|
try {
|
|
137
151
|
let writeError;
|
|
138
152
|
try {
|
|
@@ -191,9 +205,9 @@ export async function compressWithStream(data) {
|
|
|
191
205
|
* @param data - Compressed data (deflate-raw format)
|
|
192
206
|
* @returns Decompressed data
|
|
193
207
|
*/
|
|
194
|
-
export async function decompressWithStream(data) {
|
|
208
|
+
export async function decompressWithStream(data, maxOutputLength) {
|
|
195
209
|
const ds = new DecompressionStream("deflate-raw");
|
|
196
|
-
return transformWithStream(data, ds);
|
|
210
|
+
return transformWithStream(data, ds, maxOutputLength);
|
|
197
211
|
}
|
|
198
212
|
// =============================================================================
|
|
199
213
|
// Adler-32 Checksum (RFC 1950)
|
|
@@ -16,9 +16,10 @@ import { crc32 } from "./crc32.browser.js";
|
|
|
16
16
|
import { inflateRaw, deflateRawCompressed, deflateRawStore } from "./deflate-fallback.js";
|
|
17
17
|
import { deflateWithPool, inflateWithPool, hasWorkerSupport } from "./worker-pool/index.browser.js";
|
|
18
18
|
import { DEFAULT_COMPRESS_LEVEL } from "../core/defaults.js";
|
|
19
|
-
import { ArchiveError, createAbortError, isAbortError, throwIfAborted } from "../core/errors.js";
|
|
19
|
+
import { ArchiveError, ArchiveLimitError, createAbortError, isAbortError, throwIfAborted } from "../core/errors.js";
|
|
20
20
|
import { readUint32LE } from "../zip-spec/binary.js";
|
|
21
21
|
import { concatUint8Arrays } from "../../../utils/binary.js";
|
|
22
|
+
import { assertLimitOption } from "../../../utils/limits.js";
|
|
22
23
|
// Re-export shared types and GZIP utilities
|
|
23
24
|
export {};
|
|
24
25
|
export { hasCompressionStream, hasWorkerSupport,
|
|
@@ -59,15 +60,17 @@ function rethrowIfAborted(err, signal) {
|
|
|
59
60
|
}
|
|
60
61
|
const deflateStrategy = {
|
|
61
62
|
hasNative: hasDeflateRawCompressionStream,
|
|
62
|
-
native: compressWithStream,
|
|
63
|
-
worker: deflateWithPool,
|
|
64
|
-
jsFallback: deflateRawCompressed
|
|
63
|
+
native: data => compressWithStream(data),
|
|
64
|
+
worker: (data, { level, signal, allowTransfer }) => deflateWithPool(data, { level, signal, allowTransfer }),
|
|
65
|
+
jsFallback: (data, options) => deflateRawCompressed(data, options.level)
|
|
65
66
|
};
|
|
66
67
|
const inflateStrategy = {
|
|
67
68
|
hasNative: hasDeflateRawDecompressionStream,
|
|
68
|
-
native: decompressWithStream,
|
|
69
|
-
worker
|
|
70
|
-
|
|
69
|
+
native: (data, options) => decompressWithStream(data, options.maxOutputLength),
|
|
70
|
+
// The worker enforces the bound while it inflates and reports a hit as an
|
|
71
|
+
// ArchiveLimitError, exactly like the in-process paths.
|
|
72
|
+
worker: (data, { signal, allowTransfer, maxOutputLength }) => inflateWithPool(data, { signal, allowTransfer, maxOutputLength }),
|
|
73
|
+
jsFallback: (data, options) => inflateRaw(data, options.maxOutputLength)
|
|
71
74
|
};
|
|
72
75
|
/**
|
|
73
76
|
* Unified compression/decompression with automatic strategy selection.
|
|
@@ -79,26 +82,31 @@ async function processWithStrategy(strategy, data, options) {
|
|
|
79
82
|
// If the user explicitly requested workers, honor it.
|
|
80
83
|
if (useWorker === true && workerSupported) {
|
|
81
84
|
try {
|
|
82
|
-
return await strategy.worker(data,
|
|
83
|
-
level: options.level,
|
|
84
|
-
signal: options.signal,
|
|
85
|
-
allowTransfer: options.allowTransfer
|
|
86
|
-
});
|
|
85
|
+
return await strategy.worker(data, options);
|
|
87
86
|
}
|
|
88
87
|
catch (err) {
|
|
89
88
|
// If the user aborts, do NOT fall back to main-thread work.
|
|
90
89
|
rethrowIfAborted(err, options.signal);
|
|
90
|
+
// A limit hit is a verdict on the data; retrying elsewhere would only
|
|
91
|
+
// reach the same one.
|
|
92
|
+
if (err instanceof ArchiveLimitError) {
|
|
93
|
+
throw err;
|
|
94
|
+
}
|
|
91
95
|
// Fall through to best available in-process path.
|
|
92
96
|
}
|
|
93
97
|
}
|
|
94
98
|
// Default: use native stream if supported (fastest, no worker overhead).
|
|
95
99
|
if (canUseNative) {
|
|
96
100
|
try {
|
|
97
|
-
return await strategy.native(data);
|
|
101
|
+
return await strategy.native(data, options);
|
|
98
102
|
}
|
|
99
103
|
catch (err) {
|
|
100
104
|
// Respect aborts — never silently retry an aborted operation.
|
|
101
105
|
rethrowIfAborted(err, options.signal);
|
|
106
|
+
// A limit hit is a verdict on the data, not a spurious native failure.
|
|
107
|
+
if (err instanceof ArchiveLimitError) {
|
|
108
|
+
throw err;
|
|
109
|
+
}
|
|
102
110
|
// Native CompressionStream / DecompressionStream can intermittently
|
|
103
111
|
// reject input that is in fact valid (observed in Chromium under heavy
|
|
104
112
|
// concurrent stream creation: a `DecompressionStream` rejects a deflate
|
|
@@ -107,19 +115,15 @@ async function processWithStrategy(strategy, data, options) {
|
|
|
107
115
|
// set" / corruption error, fall back to the deterministic pure-JS
|
|
108
116
|
// implementation. If the data is genuinely corrupt the JS path throws
|
|
109
117
|
// too, so this never masks a real error.
|
|
110
|
-
return strategy.jsFallback(data, options
|
|
118
|
+
return strategy.jsFallback(data, options);
|
|
111
119
|
}
|
|
112
120
|
}
|
|
113
121
|
// Use worker in fallback environments (no native deflate-raw) when appropriate.
|
|
114
122
|
if (useWorker !== true && shouldUseWorker(data, options)) {
|
|
115
|
-
return strategy.worker(data,
|
|
116
|
-
level: options.level,
|
|
117
|
-
signal: options.signal,
|
|
118
|
-
allowTransfer: options.allowTransfer
|
|
119
|
-
});
|
|
123
|
+
return strategy.worker(data, options);
|
|
120
124
|
}
|
|
121
125
|
// Fallback to pure JS implementation.
|
|
122
|
-
return strategy.jsFallback(data, options
|
|
126
|
+
return strategy.jsFallback(data, options);
|
|
123
127
|
}
|
|
124
128
|
// =============================================================================
|
|
125
129
|
// Public API
|
|
@@ -150,13 +154,15 @@ export function compressSync(data, options = {}) {
|
|
|
150
154
|
* Decompress data using browser's native DecompressionStream or JS fallback
|
|
151
155
|
*/
|
|
152
156
|
export async function decompress(data, options = {}) {
|
|
157
|
+
assertLimitOption("maxOutputLength", options.maxOutputLength);
|
|
153
158
|
return processWithStrategy(inflateStrategy, data, options);
|
|
154
159
|
}
|
|
155
160
|
/**
|
|
156
161
|
* Decompress data synchronously using pure JS implementation
|
|
157
162
|
*/
|
|
158
|
-
export function decompressSync(data) {
|
|
159
|
-
|
|
163
|
+
export function decompressSync(data, options = {}) {
|
|
164
|
+
assertLimitOption("maxOutputLength", options.maxOutputLength);
|
|
165
|
+
return inflateRaw(data, options.maxOutputLength);
|
|
160
166
|
}
|
|
161
167
|
// =============================================================================
|
|
162
168
|
// GZIP API
|
|
@@ -269,10 +275,11 @@ export function gzipSync(data, options = {}) {
|
|
|
269
275
|
* - Inherits Worker Pool support from decompress() for large files
|
|
270
276
|
*/
|
|
271
277
|
export async function gunzip(data, options = {}) {
|
|
278
|
+
assertLimitOption("maxOutputLength", options.maxOutputLength);
|
|
272
279
|
throwIfAborted(options.signal);
|
|
273
280
|
if (hasGzipDecompressionStream()) {
|
|
274
281
|
const ds = new DecompressionStream("gzip");
|
|
275
|
-
const out = await transformWithStream(data, ds);
|
|
282
|
+
const out = await transformWithStream(data, ds, options.maxOutputLength);
|
|
276
283
|
throwIfAborted(options.signal);
|
|
277
284
|
return out;
|
|
278
285
|
}
|
|
@@ -284,9 +291,10 @@ export async function gunzip(data, options = {}) {
|
|
|
284
291
|
/**
|
|
285
292
|
* Gunzip data synchronously using the JS fallback.
|
|
286
293
|
*/
|
|
287
|
-
export function gunzipSync(data) {
|
|
294
|
+
export function gunzipSync(data, options = {}) {
|
|
295
|
+
assertLimitOption("maxOutputLength", options.maxOutputLength);
|
|
288
296
|
const { deflateData, expectedCrc32, expectedSize } = parseGzipPayload(data);
|
|
289
|
-
const out = inflateRaw(deflateData);
|
|
297
|
+
const out = inflateRaw(deflateData, options.maxOutputLength);
|
|
290
298
|
verifyGzipOutput(out, expectedCrc32, expectedSize);
|
|
291
299
|
return out;
|
|
292
300
|
}
|
|
@@ -344,11 +352,12 @@ export function zlibSync(data, options = {}) {
|
|
|
344
352
|
* 2. Fallback: parse header + decompress (inflate-raw) + verify Adler-32
|
|
345
353
|
*/
|
|
346
354
|
export async function unzlib(data, options = {}) {
|
|
355
|
+
assertLimitOption("maxOutputLength", options.maxOutputLength);
|
|
347
356
|
throwIfAborted(options.signal);
|
|
348
357
|
// Native "deflate" format is Zlib
|
|
349
358
|
if (hasDeflateDecompressionStream()) {
|
|
350
359
|
const ds = new DecompressionStream("deflate");
|
|
351
|
-
const out = await transformWithStream(data, ds);
|
|
360
|
+
const out = await transformWithStream(data, ds, options.maxOutputLength);
|
|
352
361
|
throwIfAborted(options.signal);
|
|
353
362
|
return out;
|
|
354
363
|
}
|
|
@@ -359,10 +368,14 @@ export async function unzlib(data, options = {}) {
|
|
|
359
368
|
}
|
|
360
369
|
/**
|
|
361
370
|
* Decompress Zlib data (sync)
|
|
371
|
+
*
|
|
372
|
+
* @param options - `maxOutputLength` bounds the output; decoding stops with a
|
|
373
|
+
* `ArchiveLimitError` as soon as it is exceeded
|
|
362
374
|
*/
|
|
363
|
-
export function unzlibSync(data) {
|
|
375
|
+
export function unzlibSync(data, options = {}) {
|
|
376
|
+
assertLimitOption("maxOutputLength", options.maxOutputLength);
|
|
364
377
|
const { deflateData, expectedAdler32 } = parseZlibPayload(data);
|
|
365
|
-
const out = inflateRaw(deflateData);
|
|
378
|
+
const out = inflateRaw(deflateData, options.maxOutputLength);
|
|
366
379
|
verifyAdler32(out, expectedAdler32);
|
|
367
380
|
return out;
|
|
368
381
|
}
|
|
@@ -397,14 +410,14 @@ export async function decompressAuto(data, options = {}) {
|
|
|
397
410
|
/**
|
|
398
411
|
* Decompress data synchronously, automatically detecting the format
|
|
399
412
|
*/
|
|
400
|
-
export function decompressAutoSync(data) {
|
|
413
|
+
export function decompressAutoSync(data, options = {}) {
|
|
401
414
|
const format = detectCompressionFormat(data);
|
|
402
415
|
switch (format) {
|
|
403
416
|
case "gzip":
|
|
404
|
-
return gunzipSync(data);
|
|
417
|
+
return gunzipSync(data, options);
|
|
405
418
|
case "zlib":
|
|
406
|
-
return unzlibSync(data);
|
|
419
|
+
return unzlibSync(data, options);
|
|
407
420
|
case "deflate-raw":
|
|
408
|
-
return decompressSync(data);
|
|
421
|
+
return decompressSync(data, options);
|
|
409
422
|
}
|
|
410
423
|
}
|
|
@@ -5,9 +5,11 @@
|
|
|
5
5
|
* - deflate-raw: Raw DEFLATE (for ZIP files)
|
|
6
6
|
* - gzip: GZIP format (for tar.gz, HTTP compression)
|
|
7
7
|
*/
|
|
8
|
+
import { kMaxLength } from "buffer";
|
|
8
9
|
import { promisify } from "util";
|
|
9
10
|
import * as nodeZlib from "zlib";
|
|
10
11
|
import { DEFAULT_COMPRESS_LEVEL } from "../core/defaults.js";
|
|
12
|
+
import { ArchiveLimitError } from "../core/errors.js";
|
|
11
13
|
import { uint8ArrayToNodeBufferView } from "../../../utils/binary.js";
|
|
12
14
|
// Re-export shared types and utilities
|
|
13
15
|
export { hasCompressionStream,
|
|
@@ -35,6 +37,7 @@ export function bufferToUint8Array(buffer) {
|
|
|
35
37
|
const deflateRawAsync = promisify(nodeZlib.deflateRaw);
|
|
36
38
|
const inflateRawAsync = promisify(nodeZlib.inflateRaw);
|
|
37
39
|
import { resolveCompressThresholdBytes, detectCompressionFormat } from "./compress.base.js";
|
|
40
|
+
import { assertLimitOption } from "../../../utils/limits.js";
|
|
38
41
|
/**
|
|
39
42
|
* Compress data using Node.js native zlib
|
|
40
43
|
*
|
|
@@ -79,30 +82,75 @@ export function compressSync(data, options = {}) {
|
|
|
79
82
|
const zlibOptions = { level };
|
|
80
83
|
return bufferToUint8Array(nodeZlib.deflateRawSync(input, zlibOptions));
|
|
81
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* zlib options for an optional output bound. zlib rejects a bound below 1, so
|
|
87
|
+
* a zero bound is requested as 1 and {@link inflateBounded} rejects any output.
|
|
88
|
+
*/
|
|
89
|
+
function boundOptions(maxOutputLength) {
|
|
90
|
+
// Every decompressing entry point resolves its bound here first.
|
|
91
|
+
assertLimitOption("maxOutputLength", maxOutputLength);
|
|
92
|
+
return maxOutputLength === undefined
|
|
93
|
+
? undefined
|
|
94
|
+
: { maxOutputLength: Math.max(1, Math.min(maxOutputLength, kMaxLength)) };
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Settle a zlib inflate run with {@link boundOptions}: zlib stops as soon as
|
|
98
|
+
* the inflater crosses the bound and throws `ERR_BUFFER_TOO_LARGE`, which
|
|
99
|
+
* becomes the archive's own error.
|
|
100
|
+
*/
|
|
101
|
+
function inflateBounded(inflate, maxOutputLength) {
|
|
102
|
+
let out;
|
|
103
|
+
try {
|
|
104
|
+
out = inflate();
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
if (maxOutputLength !== undefined &&
|
|
108
|
+
err.code === "ERR_BUFFER_TOO_LARGE") {
|
|
109
|
+
throw new ArchiveLimitError("maxOutputLength", maxOutputLength, { cause: err });
|
|
110
|
+
}
|
|
111
|
+
throw err;
|
|
112
|
+
}
|
|
113
|
+
if (maxOutputLength !== undefined && out.byteLength > maxOutputLength) {
|
|
114
|
+
throw new ArchiveLimitError("maxOutputLength", maxOutputLength);
|
|
115
|
+
}
|
|
116
|
+
return bufferToUint8Array(out);
|
|
117
|
+
}
|
|
118
|
+
/** {@link inflateBounded} for a run settled on the thread pool. */
|
|
119
|
+
async function inflateBoundedAsync(pending, maxOutputLength) {
|
|
120
|
+
const settled = await pending.then(out => () => out, (err) => () => {
|
|
121
|
+
throw err;
|
|
122
|
+
});
|
|
123
|
+
return inflateBounded(settled, maxOutputLength);
|
|
124
|
+
}
|
|
82
125
|
/**
|
|
83
126
|
* Decompress data using Node.js native zlib
|
|
84
127
|
*
|
|
85
128
|
* @param data - Compressed data (deflate-raw format)
|
|
129
|
+
* @param options - `maxOutputLength` bounds the output; inflation stops early
|
|
130
|
+
* with an `ArchiveLimitError` when it is exceeded
|
|
86
131
|
* @returns Decompressed data
|
|
87
132
|
*/
|
|
88
133
|
export async function decompress(data, options = {}) {
|
|
89
|
-
const thresholdBytes = resolveCompressThresholdBytes(options);
|
|
90
134
|
const input = uint8ArrayToBuffer(data);
|
|
135
|
+
const { maxOutputLength } = options;
|
|
136
|
+
const zlibOptions = boundOptions(maxOutputLength);
|
|
91
137
|
// Small-input fast path: avoid threadpool overhead.
|
|
92
|
-
if (data.byteLength <=
|
|
93
|
-
return
|
|
138
|
+
if (data.byteLength <= resolveCompressThresholdBytes(options)) {
|
|
139
|
+
return inflateBounded(() => nodeZlib.inflateRawSync(input, zlibOptions), maxOutputLength);
|
|
94
140
|
}
|
|
95
|
-
return
|
|
141
|
+
return inflateBoundedAsync(inflateRawAsync(input, zlibOptions), maxOutputLength);
|
|
96
142
|
}
|
|
97
143
|
/**
|
|
98
144
|
* Decompress data synchronously using Node.js zlib
|
|
99
145
|
*
|
|
100
146
|
* @param data - Compressed data (deflate-raw format)
|
|
147
|
+
* @param options - `maxOutputLength` bounds the output (see {@link decompress})
|
|
101
148
|
* @returns Decompressed data
|
|
102
149
|
*/
|
|
103
|
-
export function decompressSync(data) {
|
|
150
|
+
export function decompressSync(data, options = {}) {
|
|
104
151
|
const input = uint8ArrayToBuffer(data);
|
|
105
|
-
|
|
152
|
+
const { maxOutputLength } = options;
|
|
153
|
+
return inflateBounded(() => nodeZlib.inflateRawSync(input, boundOptions(maxOutputLength)), maxOutputLength);
|
|
106
154
|
}
|
|
107
155
|
// =============================================================================
|
|
108
156
|
// GZIP API
|
|
@@ -129,11 +177,13 @@ export async function gzip(data, options = {}) {
|
|
|
129
177
|
export async function gunzip(data, options = {}) {
|
|
130
178
|
const thresholdBytes = resolveCompressThresholdBytes(options);
|
|
131
179
|
const input = uint8ArrayToBuffer(data);
|
|
180
|
+
const { maxOutputLength } = options;
|
|
181
|
+
const zlibOptions = boundOptions(maxOutputLength);
|
|
132
182
|
// Small-input fast path
|
|
133
183
|
if (data.byteLength <= thresholdBytes) {
|
|
134
|
-
return
|
|
184
|
+
return inflateBounded(() => nodeZlib.gunzipSync(input, zlibOptions), maxOutputLength);
|
|
135
185
|
}
|
|
136
|
-
return
|
|
186
|
+
return inflateBoundedAsync(gunzipAsync(input, zlibOptions), maxOutputLength);
|
|
137
187
|
}
|
|
138
188
|
/**
|
|
139
189
|
* Compress data with gzip (sync)
|
|
@@ -147,9 +197,10 @@ export function gzipSync(data, options = {}) {
|
|
|
147
197
|
/**
|
|
148
198
|
* Decompress gzip data (sync)
|
|
149
199
|
*/
|
|
150
|
-
export function gunzipSync(data) {
|
|
200
|
+
export function gunzipSync(data, options = {}) {
|
|
151
201
|
const input = uint8ArrayToBuffer(data);
|
|
152
|
-
|
|
202
|
+
const { maxOutputLength } = options;
|
|
203
|
+
return inflateBounded(() => nodeZlib.gunzipSync(input, boundOptions(maxOutputLength)), maxOutputLength);
|
|
153
204
|
}
|
|
154
205
|
// =============================================================================
|
|
155
206
|
// ZLIB API (RFC 1950: DEFLATE with zlib header/trailer + Adler-32)
|
|
@@ -179,11 +230,13 @@ export async function zlib(data, options = {}) {
|
|
|
179
230
|
export async function unzlib(data, options = {}) {
|
|
180
231
|
const thresholdBytes = resolveCompressThresholdBytes(options);
|
|
181
232
|
const input = uint8ArrayToBuffer(data);
|
|
233
|
+
const { maxOutputLength } = options;
|
|
234
|
+
const zlibOptions = boundOptions(maxOutputLength);
|
|
182
235
|
// Small-input fast path
|
|
183
236
|
if (data.byteLength <= thresholdBytes) {
|
|
184
|
-
return
|
|
237
|
+
return inflateBounded(() => nodeZlib.inflateSync(input, zlibOptions), maxOutputLength);
|
|
185
238
|
}
|
|
186
|
-
return
|
|
239
|
+
return inflateBoundedAsync(unzlibAsync(input, zlibOptions), maxOutputLength);
|
|
187
240
|
}
|
|
188
241
|
/**
|
|
189
242
|
* Compress data with Zlib wrapper (sync)
|
|
@@ -196,10 +249,13 @@ export function zlibSync(data, options = {}) {
|
|
|
196
249
|
}
|
|
197
250
|
/**
|
|
198
251
|
* Decompress Zlib data (sync)
|
|
252
|
+
*
|
|
253
|
+
* @param options - `maxOutputLength` bounds the output (see {@link decompress})
|
|
199
254
|
*/
|
|
200
|
-
export function unzlibSync(data) {
|
|
255
|
+
export function unzlibSync(data, options = {}) {
|
|
201
256
|
const input = uint8ArrayToBuffer(data);
|
|
202
|
-
|
|
257
|
+
const { maxOutputLength } = options;
|
|
258
|
+
return inflateBounded(() => nodeZlib.inflateSync(input, boundOptions(maxOutputLength)), maxOutputLength);
|
|
203
259
|
}
|
|
204
260
|
// =============================================================================
|
|
205
261
|
// AUTO-DETECT DECOMPRESSION
|
|
@@ -232,14 +288,14 @@ export async function decompressAuto(data, options = {}) {
|
|
|
232
288
|
/**
|
|
233
289
|
* Decompress data synchronously, automatically detecting the format
|
|
234
290
|
*/
|
|
235
|
-
export function decompressAutoSync(data) {
|
|
291
|
+
export function decompressAutoSync(data, options = {}) {
|
|
236
292
|
const format = detectCompressionFormat(data);
|
|
237
293
|
switch (format) {
|
|
238
294
|
case "gzip":
|
|
239
|
-
return gunzipSync(data);
|
|
295
|
+
return gunzipSync(data, options);
|
|
240
296
|
case "zlib":
|
|
241
|
-
return unzlibSync(data);
|
|
297
|
+
return unzlibSync(data, options);
|
|
242
298
|
case "deflate-raw":
|
|
243
|
-
return decompressSync(data);
|
|
299
|
+
return decompressSync(data, options);
|
|
244
300
|
}
|
|
245
301
|
}
|
|
@@ -10,8 +10,9 @@
|
|
|
10
10
|
* - Safari < 16.4
|
|
11
11
|
* - Chrome < 103
|
|
12
12
|
*/
|
|
13
|
-
import { ArchiveError } from "../core/errors.js";
|
|
13
|
+
import { ArchiveError, ArchiveLimitError } from "../core/errors.js";
|
|
14
14
|
import { concatUint8Arrays } from "../../../utils/binary.js";
|
|
15
|
+
import { assertLimitOption } from "../../../utils/limits.js";
|
|
15
16
|
// ============================================================================
|
|
16
17
|
// DEFLATE Decompression (Full implementation)
|
|
17
18
|
// ============================================================================
|
|
@@ -199,19 +200,28 @@ class BitReader {
|
|
|
199
200
|
* Decompress DEFLATE data (raw format, no zlib header)
|
|
200
201
|
*
|
|
201
202
|
* @param data - Compressed data in deflate-raw format
|
|
203
|
+
* @param maxOutputLength - Optional output bound; decoding stops with a
|
|
204
|
+
* `ArchiveLimitError` before the output buffer grows past it
|
|
202
205
|
* @returns Decompressed data
|
|
203
206
|
*/
|
|
204
|
-
export function inflateRaw(data) {
|
|
207
|
+
export function inflateRaw(data, maxOutputLength) {
|
|
205
208
|
const reader = new BitReader(data);
|
|
206
209
|
// Output accumulator. DEFLATE has no length prefix, so we grow a typed array
|
|
207
210
|
// geometrically instead of pushing into a `number[]` (which boxes every byte
|
|
208
211
|
// at ~8x the memory and forces a final full copy). Seed with a heuristic
|
|
209
212
|
// based on the compressed size; deflate ratios on OOXML/text are commonly
|
|
210
213
|
// 3-5x, so 4x is a reasonable starting capacity that avoids most regrowths.
|
|
211
|
-
|
|
214
|
+
assertLimitOption("maxOutputLength", maxOutputLength);
|
|
215
|
+
const limit = maxOutputLength ?? Infinity;
|
|
216
|
+
// Never larger than the bound; with a positive bound never empty, so the
|
|
217
|
+
// doubling below always makes progress (a zero bound throws before growing).
|
|
218
|
+
let output = new Uint8Array(Math.min(Math.max(64, data.length * 4), limit));
|
|
212
219
|
let outLen = 0;
|
|
213
220
|
const ensureCapacity = (additional) => {
|
|
214
221
|
const required = outLen + additional;
|
|
222
|
+
if (required > limit) {
|
|
223
|
+
throw new ArchiveLimitError("maxOutputLength", limit);
|
|
224
|
+
}
|
|
215
225
|
if (required <= output.length) {
|
|
216
226
|
return;
|
|
217
227
|
}
|
|
@@ -219,6 +229,7 @@ export function inflateRaw(data) {
|
|
|
219
229
|
while (capacity < required) {
|
|
220
230
|
capacity *= 2;
|
|
221
231
|
}
|
|
232
|
+
capacity = Math.min(capacity, limit);
|
|
222
233
|
const grown = new Uint8Array(capacity);
|
|
223
234
|
grown.set(output.subarray(0, outLen));
|
|
224
235
|
output = grown;
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { resolvePoolOptions, getPriorityValue, hasWorkerSupport, createAbortError } from "./pool.base.js";
|
|
16
16
|
import { getWorkerBlobUrl, releaseWorkerBlobUrl } from "./worker-script.js";
|
|
17
|
-
import { ArchiveError } from "../../core/errors.js";
|
|
17
|
+
import { ArchiveError, ArchiveLimitError } from "../../core/errors.js";
|
|
18
18
|
export { hasWorkerSupport };
|
|
19
19
|
const EMPTY_CHUNK = new Uint8Array(0);
|
|
20
20
|
const DEFAULT_MAX_INFLIGHT_STREAM_CHUNKS = 8;
|
|
@@ -153,6 +153,7 @@ export class WorkerPool {
|
|
|
153
153
|
taskType,
|
|
154
154
|
data,
|
|
155
155
|
level: options?.level,
|
|
156
|
+
maxOutputLength: options?.maxOutputLength,
|
|
156
157
|
priority,
|
|
157
158
|
priorityValue,
|
|
158
159
|
resolve,
|
|
@@ -362,7 +363,8 @@ export class WorkerPool {
|
|
|
362
363
|
taskId: task.taskId,
|
|
363
364
|
taskType: task.taskType,
|
|
364
365
|
data,
|
|
365
|
-
level: task.level
|
|
366
|
+
level: task.level,
|
|
367
|
+
maxOutputLength: task.maxOutputLength
|
|
366
368
|
};
|
|
367
369
|
// Use transferables for zero-copy
|
|
368
370
|
if (shouldTransfer) {
|
|
@@ -485,7 +487,11 @@ export class WorkerPool {
|
|
|
485
487
|
}
|
|
486
488
|
else {
|
|
487
489
|
this._failedTasks++;
|
|
488
|
-
|
|
490
|
+
// An Error does not survive postMessage with its class, so a limit
|
|
491
|
+
// hit travels as the bound and is rebuilt as the archive's own error.
|
|
492
|
+
task.reject(message.limit !== undefined
|
|
493
|
+
? new ArchiveLimitError("maxOutputLength", message.limit)
|
|
494
|
+
: new Error(message.error ?? "Unknown worker error"));
|
|
489
495
|
}
|
|
490
496
|
this._workerBecameIdle(poolWorker);
|
|
491
497
|
return;
|
|
@@ -32,16 +32,25 @@ const hasDeflateRaw = (() => {
|
|
|
32
32
|
|
|
33
33
|
const EMPTY_UINT8ARRAY = new Uint8Array(0);
|
|
34
34
|
|
|
35
|
+
/** Output exceeded the task's maxOutputLength; reported to the pool as \`limit\`. */
|
|
36
|
+
class LimitError extends Error {
|
|
37
|
+
constructor(limit) {
|
|
38
|
+
super('Decompressed output exceeds maxOutputLength (' + limit + ' bytes)');
|
|
39
|
+
this.limit = limit;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
35
43
|
/**
|
|
36
44
|
* Process data through a TransformStream (compress or decompress)
|
|
37
45
|
*/
|
|
38
|
-
async function processWithStream(stream, data) {
|
|
46
|
+
async function processWithStream(stream, data, maxOutputLength) {
|
|
39
47
|
const writer = stream.writable.getWriter();
|
|
40
48
|
const reader = stream.readable.getReader();
|
|
41
49
|
|
|
42
50
|
// Start reading output
|
|
43
51
|
let firstChunk = null;
|
|
44
52
|
let chunks = null;
|
|
53
|
+
let produced = 0;
|
|
45
54
|
const readPromise = (async () => {
|
|
46
55
|
while (true) {
|
|
47
56
|
const { done, value } = await reader.read();
|
|
@@ -49,6 +58,13 @@ async function processWithStream(stream, data) {
|
|
|
49
58
|
if (!value) {
|
|
50
59
|
continue;
|
|
51
60
|
}
|
|
61
|
+
produced += value.length;
|
|
62
|
+
if (maxOutputLength !== undefined && produced > maxOutputLength) {
|
|
63
|
+
// Stop pulling so nothing past the bound is produced or buffered.
|
|
64
|
+
const limitError = new LimitError(maxOutputLength);
|
|
65
|
+
reader.cancel(limitError).catch(() => {});
|
|
66
|
+
throw limitError;
|
|
67
|
+
}
|
|
52
68
|
if (firstChunk === null) {
|
|
53
69
|
firstChunk = value;
|
|
54
70
|
} else if (chunks === null) {
|
|
@@ -59,12 +75,19 @@ async function processWithStream(stream, data) {
|
|
|
59
75
|
}
|
|
60
76
|
})();
|
|
61
77
|
|
|
62
|
-
// Write input and close
|
|
63
|
-
|
|
64
|
-
|
|
78
|
+
// Write input and close. Once the reader has failed the writes reject
|
|
79
|
+
// too; the read's verdict is the one to report.
|
|
80
|
+
const read = readPromise.then(() => null, err => err);
|
|
81
|
+
try {
|
|
82
|
+
await writer.write(data);
|
|
83
|
+
await writer.close();
|
|
84
|
+
} catch (err) {
|
|
85
|
+
throw (await read) ?? err;
|
|
86
|
+
}
|
|
65
87
|
|
|
66
88
|
// Wait for all output
|
|
67
|
-
await
|
|
89
|
+
const readError = await read;
|
|
90
|
+
if (readError) throw readError;
|
|
68
91
|
|
|
69
92
|
// Fast path for common cases
|
|
70
93
|
if (firstChunk === null) return EMPTY_UINT8ARRAY;
|
|
@@ -121,6 +144,7 @@ function postError(taskId, err, startTime) {
|
|
|
121
144
|
type: 'error',
|
|
122
145
|
taskId,
|
|
123
146
|
error,
|
|
147
|
+
limit: err instanceof LimitError ? err.limit : undefined,
|
|
124
148
|
duration
|
|
125
149
|
});
|
|
126
150
|
}
|
|
@@ -274,7 +298,7 @@ self.onmessage = async function(event) {
|
|
|
274
298
|
|
|
275
299
|
// Handle task request
|
|
276
300
|
if (msg.type === 'task') {
|
|
277
|
-
const { taskId, taskType, data } = msg;
|
|
301
|
+
const { taskId, taskType, data, maxOutputLength } = msg;
|
|
278
302
|
const startTime = performance.now();
|
|
279
303
|
|
|
280
304
|
try {
|
|
@@ -294,7 +318,11 @@ self.onmessage = async function(event) {
|
|
|
294
318
|
throw new Error('Unknown task type: ' + taskType);
|
|
295
319
|
}
|
|
296
320
|
|
|
297
|
-
const result = await processWithStream(
|
|
321
|
+
const result = await processWithStream(
|
|
322
|
+
stream,
|
|
323
|
+
data,
|
|
324
|
+
taskType === 'inflate' ? maxOutputLength : undefined
|
|
325
|
+
);
|
|
298
326
|
|
|
299
327
|
// Transfer the result buffer for zero-copy
|
|
300
328
|
postResult(taskId, result, startTime);
|