convert-buddy-js 0.10.18 → 0.11.1
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 +49 -4
- package/dist/browser-stream-controller.d.ts +107 -0
- package/dist/browser-stream-controller.js +226 -0
- package/dist/browser-stream-controller.js.map +1 -0
- package/dist/browser.d.ts +16 -195
- package/dist/browser.js +78 -339
- package/dist/browser.js.map +1 -1
- package/dist/index-BpUN6Tdz.d.ts +440 -0
- package/dist/index.d.ts +1 -271
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -1
- package/dist/node-stream-controller.d.ts +133 -0
- package/dist/node-stream-controller.js +274 -0
- package/dist/node-stream-controller.js.map +1 -0
- package/dist/node.d.ts +3 -2
- package/dist/node.js +2 -0
- package/dist/node.js.map +1 -1
- package/dist/stream-controller.d.ts +1 -0
- package/dist/stream-controller.js +277 -0
- package/dist/stream-controller.js.map +1 -0
- package/dist/streaming-worker.js +1 -1
- package/dist/streaming-worker.js.map +1 -1
- package/dist/tests/stream-controller.test.js +237 -0
- package/dist/tests/stream-controller.test.js.map +1 -0
- package/dist/wasm/nodejs/convert_buddy.d.ts +6 -0
- package/dist/wasm/nodejs/convert_buddy.js +58 -28
- package/dist/wasm/nodejs/convert_buddy_bg.wasm +0 -0
- package/dist/wasm/nodejs/convert_buddy_bg.wasm.d.ts +4 -3
- package/dist/wasm/web/convert_buddy.d.ts +10 -3
- package/dist/wasm/web/convert_buddy.js +55 -27
- package/dist/wasm/web/convert_buddy_bg.wasm +0 -0
- package/dist/wasm/web/convert_buddy_bg.wasm.d.ts +4 -3
- package/package.json +3 -5
- package/dist/browser-core.d.ts +0 -196
- package/dist/browser-core.js +0 -787
- package/dist/browser-core.js.map +0 -1
- package/dist/wasm/nodejs/convert_buddy.cjs +0 -712
package/dist/browser.js
CHANGED
|
@@ -1,100 +1,87 @@
|
|
|
1
|
-
export * from "./
|
|
1
|
+
export * from "./index.js";
|
|
2
|
+
export * from "./stream-controller.js";
|
|
3
|
+
export * from "./browser-stream-controller.js";
|
|
2
4
|
import {
|
|
5
|
+
convertToString as coreConvertToString,
|
|
6
|
+
convert as coreConvert,
|
|
3
7
|
ConvertBuddy,
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
convertAnyToString as convertAnyToStringCore
|
|
8
|
-
} from "./browser-core";
|
|
9
|
-
async function convert(input, opts) {
|
|
10
|
-
return convertAnyCore(input, opts);
|
|
11
|
-
}
|
|
8
|
+
getMimeType,
|
|
9
|
+
getExtension
|
|
10
|
+
} from "./index.js";
|
|
12
11
|
async function convertToString(input, opts) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
if (detected.xmlConfig) {
|
|
34
|
-
actualOpts.xmlConfig = opts.xmlConfig ? { ...detected.xmlConfig, ...opts.xmlConfig } : detected.xmlConfig;
|
|
35
|
-
}
|
|
36
|
-
if (opts.debug) {
|
|
37
|
-
console.log("[convert-buddy] Auto-detected format:", detected.format);
|
|
12
|
+
if (typeof input === "string" || input instanceof Uint8Array) {
|
|
13
|
+
return coreConvertToString(input, opts);
|
|
14
|
+
}
|
|
15
|
+
if (typeof File !== "undefined" && input instanceof File) {
|
|
16
|
+
const arrayBuffer = await input.arrayBuffer();
|
|
17
|
+
return coreConvertToString(new Uint8Array(arrayBuffer), opts);
|
|
18
|
+
}
|
|
19
|
+
if (typeof Blob !== "undefined" && input instanceof Blob) {
|
|
20
|
+
const arrayBuffer = await input.arrayBuffer();
|
|
21
|
+
return coreConvertToString(new Uint8Array(arrayBuffer), opts);
|
|
22
|
+
}
|
|
23
|
+
if (typeof ReadableStream !== "undefined" && input instanceof ReadableStream) {
|
|
24
|
+
const chunks = [];
|
|
25
|
+
const reader = input.getReader();
|
|
26
|
+
try {
|
|
27
|
+
while (true) {
|
|
28
|
+
const { done, value } = await reader.read();
|
|
29
|
+
if (done) break;
|
|
30
|
+
chunks.push(value);
|
|
38
31
|
}
|
|
39
|
-
}
|
|
40
|
-
|
|
32
|
+
} finally {
|
|
33
|
+
reader.releaseLock();
|
|
41
34
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
Math.min(
|
|
49
|
-
1 * 1024 * 1024,
|
|
50
|
-
// maximum: 1MB (conservative for memory)
|
|
51
|
-
Math.floor(fileSize / 16)
|
|
52
|
-
// 1/16 of file size
|
|
53
|
-
)
|
|
54
|
-
);
|
|
55
|
-
if (opts.debug) {
|
|
56
|
-
console.log(`[convert-buddy] Adaptive chunk sizing: ${fileSize} bytes \u2192 ${actualOpts.chunkTargetBytes} byte chunks`);
|
|
35
|
+
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
36
|
+
const combined = new Uint8Array(totalLength);
|
|
37
|
+
let offset = 0;
|
|
38
|
+
for (const chunk of chunks) {
|
|
39
|
+
combined.set(chunk, offset);
|
|
40
|
+
offset += chunk.length;
|
|
57
41
|
}
|
|
42
|
+
return coreConvertToString(combined, opts);
|
|
58
43
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
44
|
+
throw new Error("Unsupported input type for browser environment");
|
|
45
|
+
}
|
|
46
|
+
async function convert(input, opts) {
|
|
47
|
+
if (typeof input === "string" || input instanceof Uint8Array) {
|
|
48
|
+
return coreConvert(input, opts);
|
|
49
|
+
}
|
|
50
|
+
if (typeof File !== "undefined" && input instanceof File) {
|
|
51
|
+
const arrayBuffer = await input.arrayBuffer();
|
|
52
|
+
return coreConvert(new Uint8Array(arrayBuffer), opts);
|
|
53
|
+
}
|
|
54
|
+
if (typeof Blob !== "undefined" && input instanceof Blob) {
|
|
55
|
+
const arrayBuffer = await input.arrayBuffer();
|
|
56
|
+
return coreConvert(new Uint8Array(arrayBuffer), opts);
|
|
57
|
+
}
|
|
58
|
+
if (typeof ReadableStream !== "undefined" && input instanceof ReadableStream) {
|
|
59
|
+
const chunks = [];
|
|
60
|
+
const reader = input.getReader();
|
|
61
|
+
try {
|
|
62
|
+
while (true) {
|
|
63
|
+
const { done, value } = await reader.read();
|
|
64
|
+
if (done) break;
|
|
65
|
+
chunks.push(value);
|
|
73
66
|
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (final.length > 0) {
|
|
77
|
-
chunks.push(final);
|
|
67
|
+
} finally {
|
|
68
|
+
reader.releaseLock();
|
|
78
69
|
}
|
|
79
70
|
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
80
|
-
const
|
|
71
|
+
const combined = new Uint8Array(totalLength);
|
|
81
72
|
let offset = 0;
|
|
82
73
|
for (const chunk of chunks) {
|
|
83
|
-
|
|
74
|
+
combined.set(chunk, offset);
|
|
84
75
|
offset += chunk.length;
|
|
85
76
|
}
|
|
86
|
-
|
|
87
|
-
console.log("[convert-buddy] Performance Stats:", buddy.stats());
|
|
88
|
-
}
|
|
89
|
-
return result;
|
|
90
|
-
} catch (error) {
|
|
91
|
-
reader.releaseLock();
|
|
92
|
-
throw error;
|
|
77
|
+
return coreConvert(combined, opts);
|
|
93
78
|
}
|
|
79
|
+
throw new Error("Unsupported input type for browser environment");
|
|
94
80
|
}
|
|
95
|
-
async function convertFileToFile(inputFile, outputFilename, opts
|
|
96
|
-
const result = await
|
|
97
|
-
const
|
|
81
|
+
async function convertFileToFile(inputFile, outputFilename, opts) {
|
|
82
|
+
const result = await convert(inputFile, opts);
|
|
83
|
+
const mimeType = getMimeType(opts.outputFormat);
|
|
84
|
+
const blob = new Blob([result.buffer], { type: mimeType });
|
|
98
85
|
const url = URL.createObjectURL(blob);
|
|
99
86
|
const link = document.createElement("a");
|
|
100
87
|
link.href = url;
|
|
@@ -107,269 +94,21 @@ async function convertFileToFile(inputFile, outputFilename, opts = {}) {
|
|
|
107
94
|
URL.revokeObjectURL(url);
|
|
108
95
|
}, 100);
|
|
109
96
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const detected = await autoDetectConfig(sample, { debug: opts.debug });
|
|
118
|
-
if (detected.format !== "unknown") {
|
|
119
|
-
actualOpts.inputFormat = detected.format;
|
|
120
|
-
if (detected.csvConfig) {
|
|
121
|
-
actualOpts.csvConfig = opts.csvConfig ? { ...detected.csvConfig, ...opts.csvConfig } : detected.csvConfig;
|
|
122
|
-
}
|
|
123
|
-
if (detected.xmlConfig) {
|
|
124
|
-
actualOpts.xmlConfig = opts.xmlConfig ? { ...detected.xmlConfig, ...opts.xmlConfig } : detected.xmlConfig;
|
|
125
|
-
}
|
|
126
|
-
} else {
|
|
127
|
-
throw new Error("Could not auto-detect input format.");
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
const buddy = await ConvertBuddy.create(actualOpts);
|
|
131
|
-
const inputStream = file.stream();
|
|
132
|
-
return new ReadableStream({
|
|
133
|
-
async start(controller) {
|
|
134
|
-
const reader = inputStream.getReader();
|
|
135
|
-
try {
|
|
136
|
-
while (true) {
|
|
137
|
-
const { done, value } = await reader.read();
|
|
138
|
-
if (done) {
|
|
139
|
-
const final = buddy.finish();
|
|
140
|
-
if (final.length > 0) {
|
|
141
|
-
controller.enqueue(final);
|
|
142
|
-
}
|
|
143
|
-
controller.close();
|
|
144
|
-
break;
|
|
145
|
-
}
|
|
146
|
-
if (buddy.isAborted()) {
|
|
147
|
-
controller.error(new Error("Conversion aborted"));
|
|
148
|
-
break;
|
|
149
|
-
}
|
|
150
|
-
const output = buddy.push(value);
|
|
151
|
-
if (output.length > 0) {
|
|
152
|
-
controller.enqueue(output);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
} catch (error) {
|
|
156
|
-
controller.error(error);
|
|
157
|
-
} finally {
|
|
158
|
-
reader.releaseLock();
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
async function autoConvertStream(file, opts) {
|
|
164
|
-
return convertFileStream(file, {
|
|
165
|
-
...opts,
|
|
166
|
-
inputFormat: "auto"
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
async function convertStreamToWritable(file, writable, opts = {}) {
|
|
170
|
-
const outputStream = await convertFileStream(file, opts);
|
|
171
|
-
await outputStream.pipeTo(writable);
|
|
172
|
-
}
|
|
173
|
-
function isFileSystemAccessSupported() {
|
|
174
|
-
return typeof window !== "undefined" && "showSaveFilePicker" in window && "showOpenFilePicker" in window;
|
|
175
|
-
}
|
|
176
|
-
async function convertAndSave(file, opts = {}) {
|
|
177
|
-
if (!isFileSystemAccessSupported()) {
|
|
178
|
-
const filename = opts.suggestedName || "converted";
|
|
179
|
-
await convertFileToFile(file, filename, opts);
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
const outputFormat = opts.outputFormat || "json";
|
|
183
|
-
const suggestedName = opts.suggestedName || `converted.${outputFormat}`;
|
|
184
|
-
const types = getFileTypeConfig(outputFormat);
|
|
185
|
-
try {
|
|
186
|
-
const fileHandle = await window.showSaveFilePicker({
|
|
187
|
-
suggestedName,
|
|
188
|
-
types
|
|
189
|
-
});
|
|
190
|
-
const writable = await fileHandle.createWritable();
|
|
191
|
-
await convertStreamToWritable(file, writable, opts);
|
|
192
|
-
} catch (error) {
|
|
193
|
-
if (error?.name === "AbortError") {
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
throw error;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
async function streamProcessFileInWorker(file, opts = {}, onProgress) {
|
|
200
|
-
if (typeof Worker === "undefined") {
|
|
201
|
-
console.warn("[convert-buddy] Web Workers not available, falling back to main thread processing");
|
|
202
|
-
return convertFile(file, opts);
|
|
203
|
-
}
|
|
204
|
-
return new Promise((resolve, reject) => {
|
|
205
|
-
try {
|
|
206
|
-
const workerCode = `
|
|
207
|
-
let buddy = null;
|
|
208
|
-
let totalBytesRead = 0;
|
|
209
|
-
let totalBytesWritten = 0;
|
|
210
|
-
let recordsProcessed = 0;
|
|
211
|
-
let fileSize = 0;
|
|
212
|
-
let chunkSize = 1024 * 1024;
|
|
213
|
-
let lastProgressPost = 0;
|
|
214
|
-
const PROGRESS_THROTTLE_MS = 150;
|
|
215
|
-
const utf8Decoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
|
|
216
|
-
|
|
217
|
-
self.onmessage = async (event) => {
|
|
218
|
-
const { type, file, opts } = event.data;
|
|
219
|
-
|
|
220
|
-
if (type === 'start') {
|
|
221
|
-
try {
|
|
222
|
-
// For inline workers, we need to use the browser-core directly
|
|
223
|
-
// This is loaded via importScripts or dynamic import
|
|
224
|
-
const { ConvertBuddy } = await import('convert-buddy-js/browser');
|
|
225
|
-
buddy = await ConvertBuddy.create(opts);
|
|
226
|
-
fileSize = file.size;
|
|
227
|
-
totalBytesRead = 0;
|
|
228
|
-
totalBytesWritten = 0;
|
|
229
|
-
recordsProcessed = 0;
|
|
230
|
-
chunkSize = opts.chunkTargetBytes || chunkSize;
|
|
231
|
-
|
|
232
|
-
let offset = 0;
|
|
233
|
-
while (offset < fileSize) {
|
|
234
|
-
const chunkEnd = Math.min(offset + chunkSize, fileSize);
|
|
235
|
-
const chunk = file.slice(offset, chunkEnd);
|
|
236
|
-
const chunkData = await chunk.arrayBuffer();
|
|
237
|
-
const uint8Array = new Uint8Array(chunkData);
|
|
238
|
-
totalBytesRead += uint8Array.length;
|
|
239
|
-
|
|
240
|
-
const output = buddy.push(uint8Array);
|
|
241
|
-
if (output && output.length > 0) {
|
|
242
|
-
totalBytesWritten += output.length;
|
|
243
|
-
const ab = output.buffer.slice(output.byteOffset, output.byteOffset + output.byteLength);
|
|
244
|
-
self.postMessage({ type: 'data', chunk: ab }, [ab]);
|
|
245
|
-
|
|
246
|
-
try {
|
|
247
|
-
const chunkText = utf8Decoder.decode(output);
|
|
248
|
-
recordsProcessed += chunkText.split('\\n').length - 1;
|
|
249
|
-
} catch (e) {}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
const now = Date.now();
|
|
253
|
-
if (now - lastProgressPost > PROGRESS_THROTTLE_MS) {
|
|
254
|
-
lastProgressPost = now;
|
|
255
|
-
self.postMessage({
|
|
256
|
-
type: 'progress',
|
|
257
|
-
bytesRead: totalBytesRead,
|
|
258
|
-
bytesWritten: totalBytesWritten,
|
|
259
|
-
percentComplete: (totalBytesRead / fileSize) * 100,
|
|
260
|
-
recordsProcessed,
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
offset = chunkEnd;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
const final = buddy.finish();
|
|
268
|
-
totalBytesWritten += final.length;
|
|
269
|
-
try {
|
|
270
|
-
const finalText = utf8Decoder.decode(final);
|
|
271
|
-
recordsProcessed += finalText.split('\\n').length - 1;
|
|
272
|
-
} catch (e) {}
|
|
273
|
-
|
|
274
|
-
self.postMessage({
|
|
275
|
-
type: 'complete',
|
|
276
|
-
bytesRead: totalBytesRead,
|
|
277
|
-
bytesWritten: totalBytesWritten,
|
|
278
|
-
recordsProcessed,
|
|
279
|
-
result: final,
|
|
280
|
-
});
|
|
281
|
-
} catch (error) {
|
|
282
|
-
self.postMessage({ type: 'error', error: error.message });
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
};
|
|
286
|
-
`;
|
|
287
|
-
const blob = new Blob([workerCode], { type: "application/javascript" });
|
|
288
|
-
const workerUrl = URL.createObjectURL(blob);
|
|
289
|
-
const worker = new Worker(workerUrl, { type: "module" });
|
|
290
|
-
worker.onmessage = (event) => {
|
|
291
|
-
const { type, ...data } = event.data;
|
|
292
|
-
if (type === "progress" && onProgress) {
|
|
293
|
-
onProgress(data);
|
|
294
|
-
} else if (type === "complete") {
|
|
295
|
-
worker.terminate();
|
|
296
|
-
URL.revokeObjectURL(workerUrl);
|
|
297
|
-
resolve(new Uint8Array(data.result));
|
|
298
|
-
} else if (type === "error") {
|
|
299
|
-
worker.terminate();
|
|
300
|
-
URL.revokeObjectURL(workerUrl);
|
|
301
|
-
reject(new Error(data.error));
|
|
302
|
-
}
|
|
303
|
-
};
|
|
304
|
-
worker.onerror = (error) => {
|
|
305
|
-
worker.terminate();
|
|
306
|
-
URL.revokeObjectURL(workerUrl);
|
|
307
|
-
console.warn("[convert-buddy] Worker failed, falling back to main thread:", error);
|
|
308
|
-
convertFile(file, opts).then(resolve).catch(reject);
|
|
309
|
-
};
|
|
310
|
-
worker.postMessage({ type: "start", file, opts });
|
|
311
|
-
} catch (error) {
|
|
312
|
-
console.warn("[convert-buddy] Worker creation failed, falling back to main thread:", error);
|
|
313
|
-
convertFile(file, opts).then(resolve).catch(reject);
|
|
97
|
+
function getFileTypeConfig(format) {
|
|
98
|
+
const mimeType = getMimeType(format);
|
|
99
|
+
const extension = `.${getExtension(format)}`;
|
|
100
|
+
return [
|
|
101
|
+
{
|
|
102
|
+
description: `${format.toUpperCase()} Files`,
|
|
103
|
+
accept: { [mimeType]: [extension] }
|
|
314
104
|
}
|
|
315
|
-
|
|
316
|
-
}
|
|
317
|
-
async function streamProcessFileInWorkerToWritable(file, writable, opts = {}, onProgress) {
|
|
318
|
-
const stream = await convertFileStream(file, opts);
|
|
319
|
-
const reader = stream.getReader();
|
|
320
|
-
let bytesRead = 0;
|
|
321
|
-
let bytesWritten = 0;
|
|
322
|
-
let lastProgressTime = 0;
|
|
323
|
-
try {
|
|
324
|
-
while (true) {
|
|
325
|
-
const { done, value } = await reader.read();
|
|
326
|
-
if (done) break;
|
|
327
|
-
if (value) {
|
|
328
|
-
bytesWritten += value.length;
|
|
329
|
-
if (writable.getWriter) {
|
|
330
|
-
const writer = writable.getWriter();
|
|
331
|
-
await writer.write(value);
|
|
332
|
-
writer.releaseLock();
|
|
333
|
-
} else if (writable.write) {
|
|
334
|
-
await writable.write(value);
|
|
335
|
-
}
|
|
336
|
-
const now = Date.now();
|
|
337
|
-
if (onProgress && now - lastProgressTime > 150) {
|
|
338
|
-
lastProgressTime = now;
|
|
339
|
-
onProgress({
|
|
340
|
-
bytesRead,
|
|
341
|
-
bytesWritten,
|
|
342
|
-
percentComplete: bytesWritten / file.size * 100,
|
|
343
|
-
recordsProcessed: 0
|
|
344
|
-
// Approximate
|
|
345
|
-
});
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
if (onProgress) {
|
|
350
|
-
onProgress({
|
|
351
|
-
bytesRead: file.size,
|
|
352
|
-
bytesWritten,
|
|
353
|
-
percentComplete: 100,
|
|
354
|
-
recordsProcessed: 0
|
|
355
|
-
});
|
|
356
|
-
}
|
|
357
|
-
} finally {
|
|
358
|
-
reader.releaseLock();
|
|
359
|
-
}
|
|
105
|
+
];
|
|
360
106
|
}
|
|
361
107
|
export {
|
|
362
|
-
|
|
108
|
+
ConvertBuddy as Converter,
|
|
363
109
|
convert,
|
|
364
|
-
convertAndSave,
|
|
365
|
-
convertFile,
|
|
366
|
-
convertFileStream,
|
|
367
110
|
convertFileToFile,
|
|
368
|
-
convertFileToString,
|
|
369
|
-
convertStreamToWritable,
|
|
370
111
|
convertToString,
|
|
371
|
-
|
|
372
|
-
streamProcessFileInWorker,
|
|
373
|
-
streamProcessFileInWorkerToWritable
|
|
112
|
+
getFileTypeConfig
|
|
374
113
|
};
|
|
375
114
|
//# sourceMappingURL=browser.js.map
|
package/dist/browser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/browser.ts"],"sourcesContent":["/**\r\n * Browser-only entry point for convert-buddy-js\r\n * This module is designed to work in any browser environment, including StackBlitz\r\n * WITHOUT requiring WebContainers or special worker thread support.\r\n * \r\n * Key differences from the main entry point:\r\n * - No Node.js code paths (no worker_threads, no fs, no path)\r\n * - Browser-optimized WASM loading\r\n * - Web Worker functionality is optional and gracefully degrades\r\n */\r\n\r\n// Re-export everything from browser-core (which has NO Node.js dependencies)\r\nexport * from \"./browser-core\";\r\n\r\n// Import specific things we need for browser-specific implementations\r\nimport {\r\n ConvertBuddy,\r\n type ConvertBuddyOptions,\r\n type ConvertOptions,\r\n type Format,\r\n autoDetectConfig,\r\n getFileTypeConfig,\r\n convertAny as convertAnyCore,\r\n convertAnyToString as convertAnyToStringCore,\r\n} from \"./browser-core\";\r\n\r\nexport type BrowserConvertOptions = ConvertBuddyOptions & {\r\n // Additional browser-specific options can go here\r\n};\r\n\r\n/**\r\n * Ultra-simple convert function for browser.\r\n * Auto-detects input type (File, URL, string, etc.) and format.\r\n * \r\n * @example\r\n * // From File\r\n * const file = fileInput.files[0];\r\n * const result = await convert(file, { outputFormat: \"json\" });\r\n * \r\n * @example\r\n * // From URL\r\n * const result = await convert(\"https://example.com/data.csv\", { outputFormat: \"json\" });\r\n * \r\n * @example\r\n * // From string\r\n * const result = await convert(csvString, { outputFormat: \"json\" });\r\n */\r\nexport async function convert(\r\n input: string | Uint8Array | File | Blob | ReadableStream<Uint8Array>,\r\n opts: ConvertOptions\r\n): Promise<Uint8Array> {\r\n return convertAnyCore(input, opts);\r\n}\r\n\r\n/**\r\n * Ultra-simple convert function that returns a string.\r\n * \r\n * @example\r\n * const json = await convertToString(file, { outputFormat: \"json\" });\r\n * console.log(JSON.parse(json));\r\n */\r\nexport async function convertToString(\r\n input: string | Uint8Array | File | Blob | ReadableStream<Uint8Array>,\r\n opts: ConvertOptions\r\n): Promise<string> {\r\n return convertAnyToStringCore(input, opts);\r\n}\r\n\r\n/**\r\n * Convert a browser File or Blob object to a string.\r\n * Handles streaming internally using FileReader and web streams.\r\n * \r\n * @example\r\n * // From file input\r\n * const fileInput = document.querySelector('input[type=\"file\"]');\r\n * const file = fileInput.files[0];\r\n * const result = await convertFileToString(file, {\r\n * inputFormat: \"csv\",\r\n * outputFormat: \"json\"\r\n * });\r\n * \r\n * @example\r\n * // With auto-detection\r\n * const result = await convertFileToString(file, {\r\n * inputFormat: \"auto\",\r\n * outputFormat: \"ndjson\"\r\n * });\r\n */\r\nexport async function convertFileToString(\r\n file: File | Blob,\r\n opts: BrowserConvertOptions = {}\r\n): Promise<string> {\r\n const bytes = await convertFile(file, opts);\r\n const decoder = new TextDecoder(\"utf-8\", { fatal: true, ignoreBOM: true });\r\n return decoder.decode(bytes);\r\n}\r\n\r\n/**\r\n * Convert a browser File or Blob object to a Uint8Array.\r\n * Handles streaming internally using FileReader and web streams.\r\n * \r\n * @example\r\n * const file = fileInput.files[0];\r\n * const result = await convertFile(file, {\r\n * inputFormat: \"csv\",\r\n * outputFormat: \"json\",\r\n * onProgress: (stats) => {\r\n * console.log(`Progress: ${stats.bytesIn} bytes processed`);\r\n * }\r\n * });\r\n */\r\nexport async function convertFile(\r\n file: File | Blob,\r\n opts: BrowserConvertOptions = {}\r\n): Promise<Uint8Array> {\r\n // Handle auto-detection\r\n let actualOpts = { ...opts };\r\n \r\n if (opts.inputFormat === \"auto\") {\r\n // Read a sample for auto-detection\r\n const sampleSize = 256 * 1024; // 256KB\r\n const sampleBlob = file.slice(0, sampleSize);\r\n const sampleBuffer = await sampleBlob.arrayBuffer();\r\n const sample = new Uint8Array(sampleBuffer as ArrayBuffer);\r\n \r\n const detected = await autoDetectConfig(sample, { debug: opts.debug });\r\n \r\n if (detected.format !== \"unknown\") {\r\n actualOpts.inputFormat = detected.format as Format;\r\n \r\n if (detected.csvConfig) {\r\n actualOpts.csvConfig = opts.csvConfig ? { ...detected.csvConfig, ...opts.csvConfig } : detected.csvConfig;\r\n }\r\n \r\n if (detected.xmlConfig) {\r\n actualOpts.xmlConfig = opts.xmlConfig ? { ...detected.xmlConfig, ...opts.xmlConfig } : detected.xmlConfig;\r\n }\r\n \r\n if (opts.debug) {\r\n console.log(\"[convert-buddy] Auto-detected format:\", detected.format);\r\n }\r\n } else {\r\n throw new Error(\"Could not auto-detect input format. Please specify inputFormat explicitly.\");\r\n }\r\n }\r\n \r\n // Adaptive chunk sizing based on file size\r\n if (!actualOpts.chunkTargetBytes) {\r\n const fileSize = file.size;\r\n actualOpts.chunkTargetBytes = Math.max(\r\n 512 * 1024, // minimum: 512KB\r\n Math.min(\r\n 1 * 1024 * 1024, // maximum: 1MB (conservative for memory)\r\n Math.floor(fileSize / 16) // 1/16 of file size\r\n )\r\n );\r\n if (opts.debug) {\r\n console.log(`[convert-buddy] Adaptive chunk sizing: ${fileSize} bytes → ${actualOpts.chunkTargetBytes} byte chunks`);\r\n }\r\n }\r\n \r\n const buddy = await ConvertBuddy.create(actualOpts);\r\n \r\n // Use streams API for efficient processing\r\n const stream = file.stream();\r\n const reader = stream.getReader();\r\n \r\n const chunks: Uint8Array[] = [];\r\n \r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n \r\n if (done) break;\r\n \r\n if (buddy.isAborted()) {\r\n throw new Error(\"Conversion aborted\");\r\n }\r\n \r\n const output = buddy.push(value);\r\n if (output.length > 0) {\r\n chunks.push(output);\r\n }\r\n }\r\n \r\n const final = buddy.finish();\r\n if (final.length > 0) {\r\n chunks.push(final);\r\n }\r\n \r\n // Combine all chunks\r\n const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);\r\n const result = new Uint8Array(totalLength);\r\n let offset = 0;\r\n for (const chunk of chunks) {\r\n result.set(chunk, offset);\r\n offset += chunk.length;\r\n }\r\n \r\n if (opts.profile) {\r\n console.log(\"[convert-buddy] Performance Stats:\", buddy.stats());\r\n }\r\n \r\n return result;\r\n } catch (error) {\r\n reader.releaseLock();\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Convert a browser File or Blob and download the result as a file.\r\n * \r\n * @example\r\n * const fileInput = document.querySelector('input[type=\"file\"]');\r\n * const file = fileInput.files[0];\r\n * await convertFileToFile(file, \"output.json\", {\r\n * inputFormat: \"csv\",\r\n * outputFormat: \"json\"\r\n * });\r\n */\r\nexport async function convertFileToFile(\r\n inputFile: File | Blob,\r\n outputFilename: string,\r\n opts: BrowserConvertOptions = {}\r\n): Promise<void> {\r\n const result = await convertFile(inputFile, opts);\r\n \r\n // Create a download link\r\n const blob = new Blob([new Uint8Array(result)], { type: \"application/octet-stream\" });\r\n const url = URL.createObjectURL(blob);\r\n \r\n const link = document.createElement(\"a\");\r\n link.href = url;\r\n link.download = outputFilename;\r\n link.style.display = \"none\";\r\n \r\n document.body.appendChild(link);\r\n link.click();\r\n \r\n // Cleanup\r\n setTimeout(() => {\r\n document.body.removeChild(link);\r\n URL.revokeObjectURL(url);\r\n }, 100);\r\n}\r\n\r\n/**\r\n * Create a ReadableStream that converts data on-the-fly from a File or Blob.\r\n * Useful for piping through other stream processors.\r\n * \r\n * @example\r\n * const file = fileInput.files[0];\r\n * const stream = convertFileStream(file, {\r\n * inputFormat: \"csv\",\r\n * outputFormat: \"ndjson\"\r\n * });\r\n * \r\n * const reader = stream.getReader();\r\n * while (true) {\r\n * const { done, value } = await reader.read();\r\n * if (done) break;\r\n * // Process each chunk as it's converted\r\n * console.log(new TextDecoder().decode(value));\r\n * }\r\n */\r\nexport async function convertFileStream(\r\n file: File | Blob,\r\n opts: BrowserConvertOptions = {}\r\n): Promise<ReadableStream<Uint8Array>> {\r\n // Handle auto-detection\r\n let actualOpts = { ...opts };\r\n \r\n if (opts.inputFormat === \"auto\") {\r\n const sampleSize = 256 * 1024;\r\n const sampleBlob = file.slice(0, sampleSize);\r\n const sampleBuffer = await sampleBlob.arrayBuffer();\r\n const sample = new Uint8Array(sampleBuffer);\r\n \r\n const detected = await autoDetectConfig(sample, { debug: opts.debug });\r\n \r\n if (detected.format !== \"unknown\") {\r\n actualOpts.inputFormat = detected.format as Format;\r\n if (detected.csvConfig) {\r\n actualOpts.csvConfig = opts.csvConfig ? { ...detected.csvConfig, ...opts.csvConfig } : detected.csvConfig;\r\n }\r\n if (detected.xmlConfig) {\r\n actualOpts.xmlConfig = opts.xmlConfig ? { ...detected.xmlConfig, ...opts.xmlConfig } : detected.xmlConfig;\r\n }\r\n } else {\r\n throw new Error(\"Could not auto-detect input format.\");\r\n }\r\n }\r\n \r\n const buddy = await ConvertBuddy.create(actualOpts);\r\n const inputStream = file.stream();\r\n \r\n return new ReadableStream<Uint8Array>({\r\n async start(controller) {\r\n const reader = inputStream.getReader();\r\n \r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n \r\n if (done) {\r\n const final = buddy.finish();\r\n if (final.length > 0) {\r\n controller.enqueue(final);\r\n }\r\n controller.close();\r\n break;\r\n }\r\n \r\n if (buddy.isAborted()) {\r\n controller.error(new Error(\"Conversion aborted\"));\r\n break;\r\n }\r\n \r\n const output = buddy.push(value);\r\n if (output.length > 0) {\r\n controller.enqueue(output);\r\n }\r\n }\r\n } catch (error) {\r\n controller.error(error);\r\n } finally {\r\n reader.releaseLock();\r\n }\r\n },\r\n });\r\n}\r\n\r\n/**\r\n * Auto-detect format and create a ReadableStream for conversion.\r\n * This is a convenience helper that combines format detection with streaming conversion.\r\n * \r\n * @example\r\n * const file = fileInput.files[0];\r\n * const stream = await autoConvertStream(file, { outputFormat: \"json\" });\r\n * \r\n * // Pipe to response\r\n * return new Response(stream);\r\n */\r\nexport async function autoConvertStream(\r\n file: File | Blob,\r\n opts: Omit<BrowserConvertOptions, \"inputFormat\"> & { outputFormat: Format }\r\n): Promise<ReadableStream<Uint8Array>> {\r\n return convertFileStream(file, {\r\n ...opts,\r\n inputFormat: \"auto\",\r\n });\r\n}\r\n\r\n/**\r\n * Stream a file conversion directly to a writable destination.\r\n * This is useful for streaming large conversions to disk using File System Access API\r\n * or to other writable streams.\r\n * \r\n * @example\r\n * // Using File System Access API\r\n * const fileInput = document.querySelector('input[type=\"file\"]');\r\n * const file = fileInput.files[0];\r\n * \r\n * const fileHandle = await window.showSaveFilePicker({\r\n * suggestedName: \"output.json\",\r\n * types: [{ description: \"JSON\", accept: { \"application/json\": [\".json\"] } }]\r\n * });\r\n * const writable = await fileHandle.createWritable();\r\n * \r\n * await convertStreamToWritable(file, writable, {\r\n * inputFormat: \"csv\",\r\n * outputFormat: \"json\",\r\n * onProgress: (stats) => console.log(`${stats.bytesIn} bytes processed`)\r\n * });\r\n */\r\nexport async function convertStreamToWritable(\r\n file: File | Blob,\r\n writable: WritableStream<Uint8Array> | FileSystemWritableFileStream,\r\n opts: BrowserConvertOptions = {}\r\n): Promise<void> {\r\n const outputStream = await convertFileStream(file, opts);\r\n await outputStream.pipeTo(writable);\r\n}\r\n\r\n/**\r\n * Check if File System Access API is supported in the current browser.\r\n * Use this to determine if you can use File System Access API features.\r\n * \r\n * @example\r\n * if (isFileSystemAccessSupported()) {\r\n * // Use File System Access API\r\n * const handle = await window.showSaveFilePicker();\r\n * } else {\r\n * // Fall back to download link\r\n * await convertFileToFile(file, \"output.json\", opts);\r\n * }\r\n */\r\nexport function isFileSystemAccessSupported(): boolean {\r\n return (\r\n typeof window !== \"undefined\" &&\r\n \"showSaveFilePicker\" in window &&\r\n \"showOpenFilePicker\" in window\r\n );\r\n}\r\n\r\n/**\r\n * Convert a file and save it using File System Access API with a user-selected location.\r\n * This provides a better UX than automatic downloads by letting users choose where to save.\r\n * Falls back to regular download if File System Access API is not supported.\r\n * \r\n * @example\r\n * const file = fileInput.files[0];\r\n * await convertAndSave(file, {\r\n * inputFormat: \"csv\",\r\n * outputFormat: \"json\",\r\n * suggestedName: \"output.json\"\r\n * });\r\n */\r\nexport async function convertAndSave(\r\n file: File | Blob,\r\n opts: BrowserConvertOptions & {\r\n suggestedName?: string;\r\n } = {}\r\n): Promise<void> {\r\n if (!isFileSystemAccessSupported()) {\r\n // Fall back to regular download\r\n const filename = opts.suggestedName || \"converted\";\r\n await convertFileToFile(file, filename, opts);\r\n return;\r\n }\r\n\r\n const outputFormat = opts.outputFormat || \"json\";\r\n const suggestedName = opts.suggestedName || `converted.${outputFormat}`;\r\n const types = getFileTypeConfig(outputFormat);\r\n\r\n try {\r\n const fileHandle = await (window as any).showSaveFilePicker({\r\n suggestedName,\r\n types,\r\n });\r\n\r\n const writable = await fileHandle.createWritable();\r\n await convertStreamToWritable(file, writable, opts);\r\n } catch (error: any) {\r\n // User cancelled or error occurred\r\n if (error?.name === \"AbortError\") {\r\n // User cancelled - this is fine, just return\r\n return;\r\n }\r\n // Re-throw other errors\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Stream a File/Blob conversion in a Web Worker with progress updates.\r\n * \r\n * NOTE: This function requires Web Worker support and may not work in all environments\r\n * (e.g., StackBlitz without WebContainers). For maximum compatibility, use the\r\n * non-worker versions: convertFile(), convertFileStream(), etc.\r\n *\r\n * @param file File or Blob to convert\r\n * @param opts Convert options (inputFormat, outputFormat, etc)\r\n * @param onProgress Callback for progress updates\r\n * @returns Promise<Uint8Array> with the converted result\r\n */\r\nexport async function streamProcessFileInWorker(\r\n file: File | Blob,\r\n opts: BrowserConvertOptions = {},\r\n onProgress?: (progress: { bytesRead: number; bytesWritten: number; percentComplete: number; recordsProcessed: number }) => void\r\n): Promise<Uint8Array> {\r\n // Check if Web Workers are available\r\n if (typeof Worker === \"undefined\") {\r\n console.warn(\"[convert-buddy] Web Workers not available, falling back to main thread processing\");\r\n return convertFile(file, opts);\r\n }\r\n\r\n return new Promise((resolve, reject) => {\r\n try {\r\n // Create an inline worker using Blob to avoid import.meta.url issues\r\n const workerCode = `\r\n let buddy = null;\r\n let totalBytesRead = 0;\r\n let totalBytesWritten = 0;\r\n let recordsProcessed = 0;\r\n let fileSize = 0;\r\n let chunkSize = 1024 * 1024;\r\n let lastProgressPost = 0;\r\n const PROGRESS_THROTTLE_MS = 150;\r\n const utf8Decoder = new TextDecoder(\"utf-8\", { fatal: true, ignoreBOM: true });\r\n\r\n self.onmessage = async (event) => {\r\n const { type, file, opts } = event.data;\r\n\r\n if (type === 'start') {\r\n try {\r\n // For inline workers, we need to use the browser-core directly\r\n // This is loaded via importScripts or dynamic import\r\n const { ConvertBuddy } = await import('convert-buddy-js/browser');\r\n buddy = await ConvertBuddy.create(opts);\r\n fileSize = file.size;\r\n totalBytesRead = 0;\r\n totalBytesWritten = 0;\r\n recordsProcessed = 0;\r\n chunkSize = opts.chunkTargetBytes || chunkSize;\r\n\r\n let offset = 0;\r\n while (offset < fileSize) {\r\n const chunkEnd = Math.min(offset + chunkSize, fileSize);\r\n const chunk = file.slice(offset, chunkEnd);\r\n const chunkData = await chunk.arrayBuffer();\r\n const uint8Array = new Uint8Array(chunkData);\r\n totalBytesRead += uint8Array.length;\r\n\r\n const output = buddy.push(uint8Array);\r\n if (output && output.length > 0) {\r\n totalBytesWritten += output.length;\r\n const ab = output.buffer.slice(output.byteOffset, output.byteOffset + output.byteLength);\r\n self.postMessage({ type: 'data', chunk: ab }, [ab]);\r\n\r\n try {\r\n const chunkText = utf8Decoder.decode(output);\r\n recordsProcessed += chunkText.split('\\\\n').length - 1;\r\n } catch (e) {}\r\n }\r\n\r\n const now = Date.now();\r\n if (now - lastProgressPost > PROGRESS_THROTTLE_MS) {\r\n lastProgressPost = now;\r\n self.postMessage({\r\n type: 'progress',\r\n bytesRead: totalBytesRead,\r\n bytesWritten: totalBytesWritten,\r\n percentComplete: (totalBytesRead / fileSize) * 100,\r\n recordsProcessed,\r\n });\r\n }\r\n\r\n offset = chunkEnd;\r\n }\r\n \r\n const final = buddy.finish();\r\n totalBytesWritten += final.length;\r\n try {\r\n const finalText = utf8Decoder.decode(final);\r\n recordsProcessed += finalText.split('\\\\n').length - 1;\r\n } catch (e) {}\r\n \r\n self.postMessage({\r\n type: 'complete',\r\n bytesRead: totalBytesRead,\r\n bytesWritten: totalBytesWritten,\r\n recordsProcessed,\r\n result: final,\r\n });\r\n } catch (error) {\r\n self.postMessage({ type: 'error', error: error.message });\r\n }\r\n }\r\n };\r\n `;\r\n\r\n const blob = new Blob([workerCode], { type: \"application/javascript\" });\r\n const workerUrl = URL.createObjectURL(blob);\r\n const worker = new Worker(workerUrl, { type: \"module\" });\r\n\r\n worker.onmessage = (event) => {\r\n const { type, ...data } = event.data;\r\n if (type === \"progress\" && onProgress) {\r\n onProgress(data);\r\n } else if (type === \"complete\") {\r\n worker.terminate();\r\n URL.revokeObjectURL(workerUrl);\r\n resolve(new Uint8Array(data.result));\r\n } else if (type === \"error\") {\r\n worker.terminate();\r\n URL.revokeObjectURL(workerUrl);\r\n reject(new Error(data.error));\r\n }\r\n };\r\n\r\n worker.onerror = (error) => {\r\n worker.terminate();\r\n URL.revokeObjectURL(workerUrl);\r\n // Fall back to main thread processing\r\n console.warn(\"[convert-buddy] Worker failed, falling back to main thread:\", error);\r\n convertFile(file, opts).then(resolve).catch(reject);\r\n };\r\n\r\n // Send file and options to worker\r\n worker.postMessage({ type: \"start\", file, opts });\r\n } catch (error) {\r\n // Fall back to main thread processing if worker creation fails\r\n console.warn(\"[convert-buddy] Worker creation failed, falling back to main thread:\", error);\r\n convertFile(file, opts).then(resolve).catch(reject);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Stream a File/Blob conversion in a Web Worker and pipe output to a Writable.\r\n * This is useful for saving directly to disk using File System Access API.\r\n * \r\n * NOTE: This function requires Web Worker support and may not work in all environments.\r\n * For maximum compatibility, use convertStreamToWritable() instead.\r\n */\r\nexport async function streamProcessFileInWorkerToWritable(\r\n file: File | Blob,\r\n writable: WritableStream<Uint8Array> | FileSystemWritableFileStream,\r\n opts: BrowserConvertOptions = {},\r\n onProgress?: (progress: { bytesRead: number; bytesWritten: number; percentComplete: number; recordsProcessed: number }) => void\r\n): Promise<void> {\r\n // For simplicity and compatibility, use the non-worker streaming approach\r\n const stream = await convertFileStream(file, opts);\r\n const reader = stream.getReader();\r\n \r\n let bytesRead = 0;\r\n let bytesWritten = 0;\r\n let lastProgressTime = 0;\r\n \r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n \r\n if (done) break;\r\n \r\n if (value) {\r\n bytesWritten += value.length;\r\n \r\n if ((writable as any).getWriter) {\r\n const writer = (writable as WritableStream<Uint8Array>).getWriter();\r\n await writer.write(value);\r\n writer.releaseLock();\r\n } else if ((writable as any).write) {\r\n await (writable as any).write(value);\r\n }\r\n \r\n // Throttled progress updates\r\n const now = Date.now();\r\n if (onProgress && now - lastProgressTime > 150) {\r\n lastProgressTime = now;\r\n onProgress({\r\n bytesRead,\r\n bytesWritten,\r\n percentComplete: (bytesWritten / file.size) * 100,\r\n recordsProcessed: 0, // Approximate\r\n });\r\n }\r\n }\r\n }\r\n \r\n // Final progress update\r\n if (onProgress) {\r\n onProgress({\r\n bytesRead: file.size,\r\n bytesWritten,\r\n percentComplete: 100,\r\n recordsProcessed: 0,\r\n });\r\n }\r\n } finally {\r\n reader.releaseLock();\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/browser.ts"],"sourcesContent":["/**\r\n * Browser entry point for convert-buddy-js\r\n * Re-exports the main API but optimized for browser environments\r\n */\r\n\r\n// Re-export all the main functionality from index\r\nexport * from \"./index.js\";\r\n\r\n// Export browser-specific streaming controllers\r\nexport * from \"./stream-controller.js\";\r\nexport * from \"./browser-stream-controller.js\";\r\n\r\n// Export browser-specific utilities\r\nimport {\r\n type Format,\r\n type ConvertOptions,\r\n type ConvertBuddyOptions,\r\n convertToString as coreConvertToString,\r\n convert as coreConvert,\r\n ConvertBuddy,\r\n getMimeType,\r\n getExtension,\r\n getSuggestedFilename,\r\n} from \"./index.js\";\r\n\r\n/**\r\n * Browser-optimized convert function for strings\r\n */\r\nexport async function convertToString(\r\n input: string | Uint8Array | File | Blob | ReadableStream<Uint8Array>,\r\n opts: ConvertOptions\r\n): Promise<string> {\r\n if (typeof input === \"string\" || input instanceof Uint8Array) {\r\n return coreConvertToString(input, opts);\r\n }\r\n \r\n if (typeof File !== \"undefined\" && input instanceof File) {\r\n const arrayBuffer = await input.arrayBuffer();\r\n return coreConvertToString(new Uint8Array(arrayBuffer), opts);\r\n }\r\n \r\n if (typeof Blob !== \"undefined\" && input instanceof Blob) {\r\n const arrayBuffer = await input.arrayBuffer();\r\n return coreConvertToString(new Uint8Array(arrayBuffer), opts);\r\n }\r\n \r\n if (typeof ReadableStream !== \"undefined\" && input instanceof ReadableStream) {\r\n const chunks: Uint8Array[] = [];\r\n const reader = input.getReader();\r\n \r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n chunks.push(value);\r\n }\r\n } finally {\r\n reader.releaseLock();\r\n }\r\n \r\n // Combine chunks\r\n const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);\r\n const combined = new Uint8Array(totalLength);\r\n let offset = 0;\r\n for (const chunk of chunks) {\r\n combined.set(chunk, offset);\r\n offset += chunk.length;\r\n }\r\n \r\n return coreConvertToString(combined, opts);\r\n }\r\n \r\n throw new Error(\"Unsupported input type for browser environment\");\r\n}\r\n\r\n/**\r\n * Browser-optimized convert function for bytes\r\n */\r\nexport async function convert(\r\n input: string | Uint8Array | File | Blob | ReadableStream<Uint8Array>,\r\n opts: ConvertOptions\r\n): Promise<Uint8Array> {\r\n if (typeof input === \"string\" || input instanceof Uint8Array) {\r\n return coreConvert(input, opts);\r\n }\r\n \r\n if (typeof File !== \"undefined\" && input instanceof File) {\r\n const arrayBuffer = await input.arrayBuffer();\r\n return coreConvert(new Uint8Array(arrayBuffer), opts);\r\n }\r\n \r\n if (typeof Blob !== \"undefined\" && input instanceof Blob) {\r\n const arrayBuffer = await input.arrayBuffer();\r\n return coreConvert(new Uint8Array(arrayBuffer), opts);\r\n }\r\n \r\n if (typeof ReadableStream !== \"undefined\" && input instanceof ReadableStream) {\r\n const chunks: Uint8Array[] = [];\r\n const reader = input.getReader();\r\n \r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n chunks.push(value);\r\n }\r\n } finally {\r\n reader.releaseLock();\r\n }\r\n \r\n // Combine chunks\r\n const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);\r\n const combined = new Uint8Array(totalLength);\r\n let offset = 0;\r\n for (const chunk of chunks) {\r\n combined.set(chunk, offset);\r\n offset += chunk.length;\r\n }\r\n \r\n return coreConvert(combined, opts);\r\n }\r\n \r\n throw new Error(\"Unsupported input type for browser environment\");\r\n}\r\n\r\n/**\r\n * Convert a browser File or Blob and trigger download of the result\r\n */\r\nexport async function convertFileToFile(\r\n inputFile: File | Blob,\r\n outputFilename: string,\r\n opts: ConvertOptions\r\n): Promise<void> {\r\n const result = await convert(inputFile, opts);\r\n \r\n // Create download\r\n const mimeType = getMimeType(opts.outputFormat);\r\n const blob = new Blob([result.buffer as ArrayBuffer], { type: mimeType });\r\n const url = URL.createObjectURL(blob);\r\n \r\n const link = document.createElement(\"a\");\r\n link.href = url;\r\n link.download = outputFilename;\r\n link.style.display = \"none\";\r\n \r\n document.body.appendChild(link);\r\n link.click();\r\n \r\n // Cleanup\r\n setTimeout(() => {\r\n document.body.removeChild(link);\r\n URL.revokeObjectURL(url);\r\n }, 100);\r\n}\r\n\r\n/**\r\n * Get file type configuration for browser file pickers\r\n */\r\nexport function getFileTypeConfig(format: Format): Array<{\r\n description: string;\r\n accept: Record<string, string[]>;\r\n}> {\r\n const mimeType = getMimeType(format);\r\n const extension = `.${getExtension(format)}`;\r\n\r\n return [\r\n {\r\n description: `${format.toUpperCase()} Files`,\r\n accept: { [mimeType]: [extension] },\r\n },\r\n ];\r\n}\r\n\r\n// Legacy exports for backward compatibility\r\nexport { ConvertBuddy as Converter };"],"mappings":"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","names":[]}
|