convert-buddy-js 0.10.7 → 0.10.9

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/dist/browser.js CHANGED
@@ -1,40 +1,8 @@
1
- var __defProp = Object.defineProperty;
2
- var __defProps = Object.defineProperties;
3
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
- var __spreadValues = (a, b) => {
9
- for (var prop in b || (b = {}))
10
- if (__hasOwnProp.call(b, prop))
11
- __defNormalProp(a, prop, b[prop]);
12
- if (__getOwnPropSymbols)
13
- for (var prop of __getOwnPropSymbols(b)) {
14
- if (__propIsEnum.call(b, prop))
15
- __defNormalProp(a, prop, b[prop]);
16
- }
17
- return a;
18
- };
19
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
- var __objRest = (source, exclude) => {
21
- var target = {};
22
- for (var prop in source)
23
- if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
24
- target[prop] = source[prop];
25
- if (source != null && __getOwnPropSymbols)
26
- for (var prop of __getOwnPropSymbols(source)) {
27
- if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
28
- target[prop] = source[prop];
29
- }
30
- return target;
31
- };
32
- const import_meta = {};
33
1
  async function streamProcessFileInWorker(file, opts = {}, onProgress) {
34
2
  return new Promise((resolve, reject) => {
35
- const worker = new Worker(new URL("./streaming-worker.js", import_meta.url), { type: "module" });
3
+ const worker = new Worker(new URL("./streaming-worker.js", import.meta.url), { type: "module" });
36
4
  worker.onmessage = (event) => {
37
- const _a = event.data, { type } = _a, data = __objRest(_a, ["type"]);
5
+ const { type, ...data } = event.data;
38
6
  if (type === "progress" && onProgress) {
39
7
  onProgress(data);
40
8
  } else if (type === "complete") {
@@ -62,7 +30,7 @@ async function convertFileToString(file, opts = {}) {
62
30
  return decoder.decode(bytes);
63
31
  }
64
32
  async function convertFile(file, opts = {}) {
65
- let actualOpts = __spreadValues({}, opts);
33
+ let actualOpts = { ...opts };
66
34
  if (opts.inputFormat === "auto") {
67
35
  const sampleSize = 256 * 1024;
68
36
  const sampleBlob = file.slice(0, sampleSize);
@@ -72,10 +40,10 @@ async function convertFile(file, opts = {}) {
72
40
  if (detected.format !== "unknown") {
73
41
  actualOpts.inputFormat = detected.format;
74
42
  if (detected.csvConfig) {
75
- actualOpts.csvConfig = opts.csvConfig ? __spreadValues(__spreadValues({}, detected.csvConfig), opts.csvConfig) : detected.csvConfig;
43
+ actualOpts.csvConfig = opts.csvConfig ? { ...detected.csvConfig, ...opts.csvConfig } : detected.csvConfig;
76
44
  }
77
45
  if (detected.xmlConfig) {
78
- actualOpts.xmlConfig = opts.xmlConfig ? __spreadValues(__spreadValues({}, detected.xmlConfig), opts.xmlConfig) : detected.xmlConfig;
46
+ actualOpts.xmlConfig = opts.xmlConfig ? { ...detected.xmlConfig, ...opts.xmlConfig } : detected.xmlConfig;
79
47
  }
80
48
  if (opts.debug) {
81
49
  console.log("[convert-buddy] Auto-detected format:", detected.format);
@@ -152,7 +120,7 @@ async function convertFileToFile(inputFile, outputFilename, opts = {}) {
152
120
  }, 100);
153
121
  }
154
122
  async function convertFileStream(file, opts = {}) {
155
- let actualOpts = __spreadValues({}, opts);
123
+ let actualOpts = { ...opts };
156
124
  if (opts.inputFormat === "auto") {
157
125
  const sampleSize = 256 * 1024;
158
126
  const sampleBlob = file.slice(0, sampleSize);
@@ -162,10 +130,10 @@ async function convertFileStream(file, opts = {}) {
162
130
  if (detected.format !== "unknown") {
163
131
  actualOpts.inputFormat = detected.format;
164
132
  if (detected.csvConfig) {
165
- actualOpts.csvConfig = opts.csvConfig ? __spreadValues(__spreadValues({}, detected.csvConfig), opts.csvConfig) : detected.csvConfig;
133
+ actualOpts.csvConfig = opts.csvConfig ? { ...detected.csvConfig, ...opts.csvConfig } : detected.csvConfig;
166
134
  }
167
135
  if (detected.xmlConfig) {
168
- actualOpts.xmlConfig = opts.xmlConfig ? __spreadValues(__spreadValues({}, detected.xmlConfig), opts.xmlConfig) : detected.xmlConfig;
136
+ actualOpts.xmlConfig = opts.xmlConfig ? { ...detected.xmlConfig, ...opts.xmlConfig } : detected.xmlConfig;
169
137
  }
170
138
  } else {
171
139
  throw new Error("Could not auto-detect input format.");
@@ -205,9 +173,10 @@ async function convertFileStream(file, opts = {}) {
205
173
  });
206
174
  }
207
175
  async function autoConvertStream(file, opts) {
208
- return convertFileStream(file, __spreadProps(__spreadValues({}, opts), {
176
+ return convertFileStream(file, {
177
+ ...opts,
209
178
  inputFormat: "auto"
210
- }));
179
+ });
211
180
  }
212
181
  async function convertStreamToWritable(file, writable, opts = {}) {
213
182
  const outputStream = await convertFileStream(file, opts);
@@ -233,7 +202,7 @@ async function convertAndSave(file, opts = {}) {
233
202
  const writable = await fileHandle.createWritable();
234
203
  await convertStreamToWritable(file, writable, opts);
235
204
  } catch (error) {
236
- if ((error == null ? void 0 : error.name) === "AbortError") {
205
+ if (error?.name === "AbortError") {
237
206
  return;
238
207
  }
239
208
  throw error;
@@ -241,7 +210,7 @@ async function convertAndSave(file, opts = {}) {
241
210
  }
242
211
  async function streamProcessFileInWorkerToWritable(file, writable, opts = {}, onProgress) {
243
212
  return new Promise((resolve, reject) => {
244
- const worker = new Worker(new URL("./streaming-worker.js", import_meta.url), { type: "module" });
213
+ const worker = new Worker(new URL("./streaming-worker.js", import.meta.url), { type: "module" });
245
214
  let writer = null;
246
215
  (async () => {
247
216
  try {
@@ -261,7 +230,7 @@ async function streamProcessFileInWorkerToWritable(file, writable, opts = {}, on
261
230
  await writable.write(chunk);
262
231
  }
263
232
  } else if (type === "progress") {
264
- onProgress == null ? void 0 : onProgress(event.data);
233
+ onProgress?.(event.data);
265
234
  } else if (type === "complete") {
266
235
  if (event.data.result) {
267
236
  const finalChunk = new Uint8Array(event.data.result);
@@ -286,7 +255,7 @@ async function streamProcessFileInWorkerToWritable(file, writable, opts = {}, on
286
255
  if (writer) {
287
256
  try {
288
257
  await writer.abort(err);
289
- } catch (e) {
258
+ } catch {
290
259
  }
291
260
  }
292
261
  worker.terminate();
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/browser.ts"],"sourcesContent":["/**\r\n * Stream a File/Blob conversion in a Web Worker with progress updates.\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 return new Promise((resolve, reject) => {\r\n // Create worker\r\n const worker = new Worker(new URL('./streaming-worker.js', import.meta.url), { 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 resolve(new Uint8Array(data.result));\r\n } else if (type === 'error') {\r\n worker.terminate();\r\n reject(new Error(data.error));\r\n }\r\n };\r\n\r\n // Send file and options to worker\r\n worker.postMessage({ type: 'start', file, opts });\r\n });\r\n}\r\nimport { ConvertBuddy, type ConvertBuddyOptions, type ConvertOptions, type Format, autoDetectConfig, detectFormat, getMimeType, getFileTypeConfig, convertAny as convertAnyCore, convertAnyToString as convertAnyToStringCore } from \"./index\";\r\n\r\nexport * from \"./index\";\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 // Tuned to balance WASM boundary crossing reduction with memory efficiency\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 * 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\n * @example\r\n * // With auto-detection\r\n * await convertStreamToWritable(file, writable, {\r\n * inputFormat: \"auto\",\r\n * outputFormat: \"ndjson\"\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 and pipe output to a Writable.\r\n * This is useful for saving directly to disk using File System Access API.\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 return new Promise((resolve, reject) => {\r\n const worker = new Worker(new URL('./streaming-worker.js', import.meta.url), { type: 'module' });\r\n let writer: WritableStreamDefaultWriter<Uint8Array> | null = null;\r\n\r\n (async () => {\r\n try {\r\n if ((writable as any).getWriter) {\r\n writer = (writable as WritableStream<Uint8Array>).getWriter();\r\n } else {\r\n // FileSystemWritableFileStream supports write(Uint8Array)\r\n writer = null;\r\n }\r\n\r\n worker.onmessage = async (event) => {\r\n const { type } = event.data;\r\n if (type === 'data') {\r\n const ab: ArrayBuffer = event.data.chunk;\r\n const chunk = new Uint8Array(ab);\r\n if (writer) {\r\n await writer.write(chunk);\r\n } else if ((writable as any).write) {\r\n await (writable as any).write(chunk);\r\n }\r\n } else if (type === 'progress') {\r\n onProgress?.(event.data);\r\n } else if (type === 'complete') {\r\n // write final chunk if present\r\n if (event.data.result) {\r\n const finalChunk = new Uint8Array(event.data.result);\r\n if (writer) await writer.write(finalChunk);\r\n else if ((writable as any).write) await (writable as any).write(finalChunk);\r\n }\r\n\r\n try {\r\n // Only close if we have a writer (WritableStream with getWriter)\r\n // FileSystemWritableFileStream should NOT be closed by us - caller owns it\r\n if (writer) {\r\n await writer.close();\r\n }\r\n } catch (e) {\r\n // ignore close errors\r\n }\r\n worker.terminate();\r\n resolve();\r\n } else if (type === 'error') {\r\n worker.terminate();\r\n reject(new Error(event.data.error));\r\n }\r\n };\r\n\r\n // Start worker\r\n worker.postMessage({ type: 'start', file, opts });\r\n } catch (err) {\r\n if (writer) {\r\n try { await writer.abort(err); } catch {}\r\n }\r\n worker.terminate();\r\n reject(err);\r\n }\r\n })();\r\n });\r\n}\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/browser.ts"],"sourcesContent":["/**\r\n * Stream a File/Blob conversion in a Web Worker with progress updates.\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 return new Promise((resolve, reject) => {\r\n // Create worker\r\n const worker = new Worker(new URL('./streaming-worker.js', import.meta.url), { 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 resolve(new Uint8Array(data.result));\r\n } else if (type === 'error') {\r\n worker.terminate();\r\n reject(new Error(data.error));\r\n }\r\n };\r\n\r\n // Send file and options to worker\r\n worker.postMessage({ type: 'start', file, opts });\r\n });\r\n}\r\nimport { ConvertBuddy, type ConvertBuddyOptions, type ConvertOptions, type Format, autoDetectConfig, detectFormat, getMimeType, getFileTypeConfig, convertAny as convertAnyCore, convertAnyToString as convertAnyToStringCore } from \"./index\";\r\n\r\nexport * from \"./index\";\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 // Tuned to balance WASM boundary crossing reduction with memory efficiency\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 * 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\n * @example\r\n * // With auto-detection\r\n * await convertStreamToWritable(file, writable, {\r\n * inputFormat: \"auto\",\r\n * outputFormat: \"ndjson\"\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 and pipe output to a Writable.\r\n * This is useful for saving directly to disk using File System Access API.\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 return new Promise((resolve, reject) => {\r\n const worker = new Worker(new URL('./streaming-worker.js', import.meta.url), { type: 'module' });\r\n let writer: WritableStreamDefaultWriter<Uint8Array> | null = null;\r\n\r\n (async () => {\r\n try {\r\n if ((writable as any).getWriter) {\r\n writer = (writable as WritableStream<Uint8Array>).getWriter();\r\n } else {\r\n // FileSystemWritableFileStream supports write(Uint8Array)\r\n writer = null;\r\n }\r\n\r\n worker.onmessage = async (event) => {\r\n const { type } = event.data;\r\n if (type === 'data') {\r\n const ab: ArrayBuffer = event.data.chunk;\r\n const chunk = new Uint8Array(ab);\r\n if (writer) {\r\n await writer.write(chunk);\r\n } else if ((writable as any).write) {\r\n await (writable as any).write(chunk);\r\n }\r\n } else if (type === 'progress') {\r\n onProgress?.(event.data);\r\n } else if (type === 'complete') {\r\n // write final chunk if present\r\n if (event.data.result) {\r\n const finalChunk = new Uint8Array(event.data.result);\r\n if (writer) await writer.write(finalChunk);\r\n else if ((writable as any).write) await (writable as any).write(finalChunk);\r\n }\r\n\r\n try {\r\n // Only close if we have a writer (WritableStream with getWriter)\r\n // FileSystemWritableFileStream should NOT be closed by us - caller owns it\r\n if (writer) {\r\n await writer.close();\r\n }\r\n } catch (e) {\r\n // ignore close errors\r\n }\r\n worker.terminate();\r\n resolve();\r\n } else if (type === 'error') {\r\n worker.terminate();\r\n reject(new Error(event.data.error));\r\n }\r\n };\r\n\r\n // Start worker\r\n worker.postMessage({ type: 'start', file, opts });\r\n } catch (err) {\r\n if (writer) {\r\n try { await writer.abort(err); } catch {}\r\n }\r\n worker.terminate();\r\n reject(err);\r\n }\r\n })();\r\n });\r\n}\r\n"],"mappings":"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","names":[]}
package/dist/index.js CHANGED
@@ -39,7 +39,7 @@ async function loadWasmModule() {
39
39
  const mod2 = require2("../wasm-node.cjs");
40
40
  return mod2;
41
41
  }
42
- const mod = await import("../wasm/web/convert_buddy.js");
42
+ const mod = await import("./wasm/web/convert_buddy.js");
43
43
  if (wasmThreadingSupported && mod.initThreadPool) {
44
44
  try {
45
45
  const numThreads = Math.min(navigator.hardwareConcurrency || 4, 8);
@@ -278,7 +278,7 @@ class ConvertBuddy {
278
278
  const { WasmThreadPool } = await import("./thread-pool");
279
279
  threadPool = new WasmThreadPool({
280
280
  maxWorkers: actualThreads,
281
- wasmPath: "../wasm/web/convert_buddy.js"
281
+ wasmPath: "./wasm/web/convert_buddy.js"
282
282
  });
283
283
  await threadPool.initialize();
284
284
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export type Format = \"csv\" | \"ndjson\" | \"json\" | \"xml\";\r\nexport type DetectInput =\r\n | Uint8Array\r\n | ArrayBuffer\r\n | string\r\n | ReadableStream<Uint8Array>\r\n | AsyncIterable<Uint8Array>;\r\n\r\nexport type CsvDetection = {\r\n delimiter: string;\r\n fields: string[];\r\n};\r\n\r\nexport type XmlDetection = {\r\n elements: string[];\r\n recordElement?: string;\r\n};\r\n\r\nexport type JsonDetection = {\r\n fields: string[];\r\n};\r\n\r\nexport type NdjsonDetection = {\r\n fields: string[];\r\n};\r\n\r\nexport type StructureDetection = {\r\n format: Format;\r\n fields: string[];\r\n delimiter?: string; // For CSV\r\n recordElement?: string; // For XML\r\n};\r\n\r\nexport type DetectOptions = {\r\n maxBytes?: number;\r\n debug?: boolean;\r\n};\r\n\r\nexport type ProgressCallback = (stats: Stats) => void;\r\n\r\nexport type ConvertBuddyOptions = {\r\n debug?: boolean;\r\n profile?: boolean;\r\n inputFormat?: Format | \"auto\";\r\n outputFormat?: Format;\r\n chunkTargetBytes?: number;\r\n parallelism?: number; // Node only - number of worker threads\r\n maxMemoryMB?: number; // Memory limit for conversions (future use)\r\n csvConfig?: CsvConfig;\r\n xmlConfig?: XmlConfig;\r\n transform?: TransformConfig;\r\n onProgress?: ProgressCallback;\r\n progressIntervalBytes?: number; // Trigger progress callback every N bytes (default: 1MB)\r\n};\r\n\r\nexport type ConvertOptions = {\r\n inputFormat?: Format | \"auto\";\r\n outputFormat: Format;\r\n csvConfig?: CsvConfig;\r\n xmlConfig?: XmlConfig;\r\n transform?: TransformConfig;\r\n onProgress?: ProgressCallback;\r\n};\r\n\r\nexport type CsvConfig = {\r\n delimiter?: string;\r\n quote?: string;\r\n hasHeaders?: boolean;\r\n trimWhitespace?: boolean;\r\n};\r\n\r\nexport type XmlConfig = {\r\n recordElement?: string;\r\n trimText?: boolean;\r\n includeAttributes?: boolean;\r\n expandEntities?: boolean;\r\n};\r\n\r\nexport type TransformMode = \"replace\" | \"augment\";\r\n\r\nexport type Coerce =\r\n | { type: \"string\" }\r\n | { type: \"i64\" }\r\n | { type: \"f64\" }\r\n | { type: \"bool\" }\r\n | { type: \"timestamp_ms\"; format?: \"iso8601\" | \"unix_ms\" | \"unix_s\" };\r\n\r\nexport type FieldMap = {\r\n targetFieldName: string;\r\n originFieldName?: string;\r\n required?: boolean;\r\n defaultValue?: string | number | boolean | null;\r\n coerce?: Coerce;\r\n compute?: string;\r\n};\r\n\r\nexport type TransformConfig = {\r\n mode?: TransformMode;\r\n fields: FieldMap[];\r\n onMissingField?: \"error\" | \"null\" | \"drop\";\r\n onMissingRequired?: \"error\" | \"abort\";\r\n onCoerceError?: \"error\" | \"null\" | \"dropRecord\";\r\n};\r\n\r\nexport type Stats = {\r\n bytesIn: number;\r\n bytesOut: number;\r\n chunksIn: number;\r\n recordsProcessed: number;\r\n parseTimeMs: number;\r\n transformTimeMs: number;\r\n writeTimeMs: number;\r\n maxBufferSize: number;\r\n currentPartialSize: number;\r\n throughputMbPerSec: number;\r\n};\r\n\r\ntype WasmModule = {\r\n default?: unknown;\r\n init: (debugEnabled: boolean) => void;\r\n Converter: new (debug: boolean) => {\r\n push: (chunk: Uint8Array) => Uint8Array;\r\n finish: () => Uint8Array;\r\n getStats: () => Stats;\r\n };\r\n detectFormat?: (sample: Uint8Array) => string | null | undefined;\r\n detectCsvFields?: (sample: Uint8Array) => CsvDetection | null | undefined;\r\n detectXmlElements?: (sample: Uint8Array) => XmlDetection | null | undefined;\r\n detectJsonFields?: (sample: Uint8Array) => JsonDetection | null | undefined;\r\n detectNdjsonFields?: (sample: Uint8Array) => NdjsonDetection | null | undefined;\r\n detectStructure?: (sample: Uint8Array, formatHint?: string) => StructureDetection | null | undefined;\r\n getSimdEnabled?: () => boolean;\r\n __wbg_set_wasm?: (wasm: unknown) => void;\r\n};\r\n\r\nlet wasmModuleInstance: WasmModule | null = null;\r\nlet wasmModuleLoadPromise: Promise<WasmModule> | null = null;\r\nlet wasmThreadingSupported = false;\r\nlet threadPool: any = null; // Custom WASM thread pool (browser)\r\nlet nodejsThreadPool: any = null; // Node.js specific thread pool\r\nconst utf8Decoder = new TextDecoder(\"utf-8\", { fatal: true, ignoreBOM: true });\r\n\r\nfunction decodeUtf8(bytes: Uint8Array): string {\r\n return utf8Decoder.decode(bytes);\r\n}\r\n\r\n// Detect SharedArrayBuffer support for WASM threading\r\nfunction detectWasmThreadingSupport(): boolean {\r\n if (typeof SharedArrayBuffer === 'undefined') {\r\n return false;\r\n }\r\n \r\n // Test if we can actually create a SharedArrayBuffer\r\n try {\r\n new SharedArrayBuffer(1);\r\n return true;\r\n } catch (e) {\r\n return false;\r\n }\r\n}\r\n\r\nasync function loadWasmModule(): Promise<WasmModule> {\r\n // Return cached instance if already loaded\r\n if (wasmModuleInstance) {\r\n return wasmModuleInstance;\r\n }\r\n\r\n // If load is in progress, wait for it\r\n if (wasmModuleLoadPromise) {\r\n return wasmModuleLoadPromise;\r\n }\r\n\r\n // Start loading\r\n wasmModuleLoadPromise = (async () => {\r\n const isNode =\r\n typeof process !== \"undefined\" &&\r\n !!(process as any).versions?.node;\r\n\r\n // Detect threading support\r\n wasmThreadingSupported = detectWasmThreadingSupport();\r\n \r\n if (isNode) {\r\n const nodeModule: any = await import(/* webpackIgnore: true */ \"node:module\");\r\n const createRequire = nodeModule.createRequire as any;\r\n const requireFn = createRequire ? createRequire(import.meta.url) : (module as any).createRequire?.(import.meta.url);\r\n const require = requireFn ?? (globalThis as any).require;\r\n const mod = require(\"../wasm-node.cjs\");\r\n return mod as WasmModule;\r\n }\r\n\r\n const mod = (await import(\"../wasm/web/convert_buddy.js\")) as unknown as WasmModule;\r\n \r\n // Initialize threading if supported\r\n if (wasmThreadingSupported && (mod as any).initThreadPool) {\r\n try {\r\n const numThreads = Math.min(navigator.hardwareConcurrency || 4, 8);\r\n await (mod as any).initThreadPool(numThreads);\r\n console.log(`[convert-buddy] WASM threading initialized with ${numThreads} threads`);\r\n } catch (e) {\r\n console.warn('[convert-buddy] WASM threading initialization failed, using single-thread:', e);\r\n wasmThreadingSupported = false;\r\n }\r\n }\r\n \r\n return mod;\r\n })();\r\n\r\n try {\r\n wasmModuleInstance = await wasmModuleLoadPromise;\r\n return wasmModuleInstance;\r\n } finally {\r\n wasmModuleLoadPromise = null;\r\n }\r\n}\r\n\r\nlet wasmInitialized = false;\r\nlet wasmInitPromise: Promise<void> | null = null;\r\n\r\nasync function initWasm(debug: boolean): Promise<void> {\r\n // If already initialized, return immediately\r\n if (wasmInitialized) {\r\n return;\r\n }\r\n\r\n // If initialization is in progress, wait for it\r\n if (wasmInitPromise) {\r\n return wasmInitPromise;\r\n }\r\n\r\n // Start initialization\r\n wasmInitPromise = (async () => {\r\n const wasmModule = await loadWasmModule();\r\n\r\n if (typeof wasmModule.default === \"function\") {\r\n await (wasmModule.default as () => Promise<void>)();\r\n }\r\n\r\n wasmModule.init(debug);\r\n \r\n // Note: Node.js enhanced threading is handled at the JavaScript level\r\n // No WASM thread pool initialization needed\r\n \r\n wasmInitialized = true;\r\n })();\r\n\r\n try {\r\n await wasmInitPromise;\r\n } finally {\r\n wasmInitPromise = null;\r\n }\r\n}\r\n\r\n/**\r\n * Warn if using non-streaming approach with large files\r\n */\r\nfunction warnIfLargeFile(sizeBytes: number, methodName: string = \"convert\"): void {\r\n const SIZE_THRESHOLD = 10 * 1024 * 1024; // 10MB\r\n \r\n if (sizeBytes >= SIZE_THRESHOLD) {\r\n const sizeMB = (sizeBytes / 1024 / 1024).toFixed(1);\r\n console.warn(\r\n `[convert-buddy-js] WARNING: Using ${methodName}() with a large file (${sizeMB}MB). ` +\r\n `This method is intended for small files and may cause memory issues with large files. ` +\r\n `For better performance and memory management with files of any size, use the streaming API: ` +\r\n `ConvertBuddy.create() with push()/finish() methods.`\r\n );\r\n }\r\n}\r\n\r\nexport class ConvertBuddy {\r\n private converter: any;\r\n private debug: boolean;\r\n private profile: boolean;\r\n private aborted: boolean = false;\r\n private paused: boolean = false;\r\n private onProgress?: ProgressCallback;\r\n private progressIntervalBytes: number;\r\n private lastProgressBytes: number = 0;\r\n private globalConfig: ConvertBuddyOptions;\r\n private initialized: boolean = false;\r\n public simd: boolean;\r\n\r\n /**\r\n * Create a new ConvertBuddy instance with global configuration.\r\n * This is useful when you want to set memory limits, debug mode, or other global settings.\r\n * \r\n * @example\r\n * const buddy = new ConvertBuddy({ maxMemoryMB: 512, debug: true });\r\n * const result = await buddy.convert(input, { outputFormat: \"json\" });\r\n */\r\n constructor(opts: ConvertBuddyOptions = {}) {\r\n // Initialize basic properties\r\n this.debug = !!opts.debug;\r\n this.profile = !!opts.profile;\r\n this.simd = false; // Will be set on first convert\r\n this.globalConfig = opts;\r\n this.progressIntervalBytes = opts.progressIntervalBytes || 1024 * 1024;\r\n this.onProgress = opts.onProgress;\r\n this.converter = null; // Will be initialized lazily\r\n this.initialized = false;\r\n }\r\n\r\n /**\r\n * Convert input (string, Buffer, File, URL, etc.) to the desired output format.\r\n * This is the main method for the new simplified API.\r\n * \r\n * @example\r\n * // Auto-detect everything\r\n * const buddy = new ConvertBuddy();\r\n * const result = await buddy.convert(\"https://example.com/data.csv\", { outputFormat: \"json\" });\r\n * \r\n * @example\r\n * // With configuration\r\n * const buddy = new ConvertBuddy({ maxMemoryMB: 512 });\r\n * const result = await buddy.convert(file, { inputFormat: \"csv\", outputFormat: \"json\" });\r\n */\r\n async convert(\r\n input: string | Uint8Array | File | Blob | ReadableStream<Uint8Array>,\r\n opts: ConvertOptions\r\n ): Promise<Uint8Array> {\r\n // Merge global and local options\r\n const mergedOpts: ConvertBuddyOptions = {\r\n ...this.globalConfig,\r\n ...opts,\r\n inputFormat: opts.inputFormat || this.globalConfig.inputFormat || \"auto\",\r\n };\r\n\r\n // Detect input type and convert accordingly\r\n if (typeof input === \"string\") {\r\n // Could be URL or raw data\r\n if (input.startsWith(\"http://\") || input.startsWith(\"https://\")) {\r\n // Fetch from URL\r\n return this.convertFromUrl(input, mergedOpts);\r\n } else {\r\n // Treat as raw data\r\n return this.convertFromString(input, mergedOpts);\r\n }\r\n } else if (input instanceof Uint8Array) {\r\n return this.convertFromBuffer(input, mergedOpts);\r\n } else if (typeof File !== \"undefined\" && input instanceof File) {\r\n return this.convertFromFile(input as File, mergedOpts);\r\n } else if (typeof Blob !== \"undefined\" && input instanceof Blob) {\r\n return this.convertFromBlob(input as Blob, mergedOpts);\r\n } else if (typeof ReadableStream !== \"undefined\" && input instanceof ReadableStream) {\r\n return this.convertFromStream(input, mergedOpts);\r\n } else {\r\n throw new Error(\"Unsupported input type\");\r\n }\r\n }\r\n\r\n private async convertFromUrl(url: string, opts: ConvertBuddyOptions): Promise<Uint8Array> {\r\n const response = await fetch(url);\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch ${url}: ${response.statusText}`);\r\n }\r\n \r\n const stream = response.body;\r\n if (!stream) {\r\n throw new Error(\"Response body is null\");\r\n }\r\n\r\n return this.convertFromStream(stream, opts);\r\n }\r\n\r\n private async convertFromString(input: string, opts: ConvertBuddyOptions): Promise<Uint8Array> {\r\n const inputBytes = new TextEncoder().encode(input);\r\n // Don't warn here - will warn in convertFromBuffer\r\n return this.convertFromBuffer(inputBytes, opts);\r\n }\r\n\r\n private async convertFromBuffer(input: Uint8Array, opts: ConvertBuddyOptions, skipWarning = false): Promise<Uint8Array> {\r\n if (!skipWarning) {\r\n warnIfLargeFile(input.length, \"convert\");\r\n }\r\n \r\n // Use WASM threading for large inputs when available\r\n const useWasmThreading = wasmThreadingSupported && input.length > 256 * 1024; // 256KB threshold\r\n \r\n if (useWasmThreading && opts.debug) {\r\n console.log('[convert-buddy] Using WASM threading for parallel processing');\r\n }\r\n \r\n // Check if we should use JavaScript-level parallelism as fallback\r\n if (!useWasmThreading && opts.parallelism && opts.parallelism > 1 && input.length > 512 * 1024) {\r\n if (opts.debug) {\r\n console.log('[convert-buddy] WASM threading not available, using JavaScript parallelism');\r\n }\r\n return this.convertFromBufferParallel(input, opts);\r\n }\r\n\r\n // Handle auto-detection\r\n let actualOpts = { ...opts };\r\n \r\n if (opts.inputFormat === \"auto\") {\r\n const detected = await autoDetectConfig(input, { 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 const buddy = await ConvertBuddy.create(actualOpts);\r\n const output = buddy.push(input);\r\n const final = buddy.finish();\r\n\r\n // Combine outputs\r\n const result = new Uint8Array(output.length + final.length);\r\n result.set(output, 0);\r\n result.set(final, output.length);\r\n\r\n if (opts.profile) {\r\n const stats = buddy.stats();\r\n console.log(\"[convert-buddy] Performance Stats:\", stats);\r\n }\r\n\r\n return result;\r\n }\r\n\r\n private async convertFromBufferParallel(input: Uint8Array, opts: ConvertBuddyOptions): Promise<Uint8Array> {\r\n // Only use parallel processing for large inputs and supported conversions\r\n const parallelThreshold = 512 * 1024; // 512KB (lowered threshold for better parallelism)\r\n const maxConcurrency = Math.min(\r\n typeof navigator !== \"undefined\" && navigator.hardwareConcurrency\r\n ? navigator.hardwareConcurrency\r\n : 4,\r\n 8\r\n );\r\n \r\n if (input.length < parallelThreshold || !opts.parallelism || opts.parallelism < 2) {\r\n return this.convertFromBuffer(input, { ...opts, parallelism: 1 }, true); // Skip warning on recursive call\r\n }\r\n\r\n // Extended support for parallel processing\r\n const supportedConversions = [\r\n { input: \"csv\", output: \"ndjson\" },\r\n { input: \"csv\", output: \"json\" },\r\n { input: \"ndjson\", output: \"json\" },\r\n { input: \"ndjson\", output: \"csv\" },\r\n { input: \"ndjson\", output: \"ndjson\" }, // passthrough optimization\r\n { input: \"json\", output: \"ndjson\" },\r\n { input: \"json\", output: \"csv\" },\r\n ];\r\n\r\n const isSupported = supportedConversions.some(\r\n conv => conv.input === opts.inputFormat && conv.output === opts.outputFormat\r\n );\r\n\r\n if (!isSupported) {\r\n if (opts.debug) {\r\n console.log(`[convert-buddy] Parallel processing not supported for ${opts.inputFormat} → ${opts.outputFormat}, using sequential`);\r\n }\r\n return this.convertFromBuffer(input, { ...opts, parallelism: 1 });\r\n }\r\n\r\n try {\r\n const actualThreads = Math.min(maxConcurrency, opts.parallelism || maxConcurrency);\r\n const isNodejs = typeof window === \"undefined\" && typeof process !== \"undefined\";\r\n \r\n if (opts.debug) {\r\n const threadingType = isNodejs ? 'Node.js WASM threading' : 'Browser custom threading';\r\n console.log(`[convert-buddy] Using ${threadingType} with ${actualThreads} threads`);\r\n }\r\n\r\n if (isNodejs) {\r\n // Try enhanced Node.js threading first\r\n if (!nodejsThreadPool) {\r\n try {\r\n const { NodejsThreadPool } = await import('./nodejs-thread-pool');\r\n nodejsThreadPool = new NodejsThreadPool({\r\n maxWorkers: actualThreads,\r\n wasmPath: '../wasm-node.cjs'\r\n });\r\n await nodejsThreadPool.initialize();\r\n } catch (error) {\r\n if (opts.debug) {\r\n console.log('[convert-buddy] Node.js thread pool creation failed, using JS parallelism:', error);\r\n }\r\n }\r\n }\r\n\r\n if (nodejsThreadPool) {\r\n return this.convertUsingNodejsThreadPool(input, opts, actualThreads);\r\n } else {\r\n return this.convertUsingJsParallelism(input, opts, actualThreads);\r\n }\r\n } else {\r\n // Browser: Create custom thread pool for WASM-level parallelism\r\n if (!threadPool) {\r\n const { WasmThreadPool } = await import('./thread-pool');\r\n threadPool = new WasmThreadPool({\r\n maxWorkers: actualThreads,\r\n wasmPath: '../wasm/web/convert_buddy.js'\r\n });\r\n await threadPool.initialize();\r\n }\r\n\r\n return this.convertUsingWasmThreadPool(input, opts, actualThreads);\r\n }\r\n \r\n } catch (error) {\r\n if (opts.debug) {\r\n console.warn(`[convert-buddy] Parallel processing failed, falling back to sequential:`, error);\r\n }\r\n return this.convertFromBuffer(input, { ...opts, parallelism: 1 });\r\n }\r\n }\r\n\r\n private async convertUsingNodejsThreadPool(input: Uint8Array, opts: ConvertBuddyOptions, numThreads: number): Promise<Uint8Array> {\r\n const { chunkDataNodejs, mergeResultsNodejs } = await import('./nodejs-thread-pool');\r\n \r\n if (opts.debug) {\r\n console.log(`[convert-buddy] Processing with enhanced Node.js threading (${numThreads} workers)`);\r\n }\r\n\r\n // Use optimized chunking for Node.js\r\n const chunks = chunkDataNodejs(input, numThreads);\r\n \r\n // Process chunks using Node.js worker threads\r\n const results = await nodejsThreadPool!.processChunks('convert', chunks, {\r\n outputFormat: opts.outputFormat,\r\n inputFormat: opts.inputFormat,\r\n csvConfig: opts.csvConfig,\r\n xmlConfig: opts.xmlConfig,\r\n debug: false // Disable debug in workers to reduce noise\r\n });\r\n\r\n // Merge results intelligently based on output format\r\n const merged = mergeResultsNodejs(results, opts.outputFormat!);\r\n \r\n if (opts.debug) {\r\n console.log(`[convert-buddy] Node.js threading completed: ${chunks.length} chunks, ${merged.length} bytes`);\r\n }\r\n\r\n return merged;\r\n }\r\n\r\n private async convertUsingWasmThreadPool(input: Uint8Array, opts: ConvertBuddyOptions, numThreads: number): Promise<Uint8Array> {\r\n const inputStr = decodeUtf8(input);\r\n \r\n // Import chunking utilities\r\n const { chunkData, mergeResults } = await import('./thread-pool');\r\n const chunks = chunkData(inputStr, numThreads);\r\n \r\n if (opts.debug) {\r\n console.log(`[convert-buddy] Processing ${chunks.length} chunks with WASM thread pool`);\r\n }\r\n\r\n // Determine method based on conversion type\r\n let method: string;\r\n const conversion = `${opts.inputFormat}_to_${opts.outputFormat}`;\r\n switch (conversion) {\r\n case 'csv_to_ndjson':\r\n case 'csv_to_json':\r\n method = 'parseCSV';\r\n break;\r\n case 'ndjson_to_csv':\r\n case 'ndjson_to_json':\r\n method = 'parseNDJSON';\r\n break;\r\n case 'json_to_csv':\r\n case 'json_to_ndjson':\r\n method = 'parseJSON';\r\n break;\r\n default:\r\n throw new Error(`Unsupported conversion: ${conversion}`);\r\n }\r\n\r\n // Process chunks in parallel using thread pool\r\n const results = await threadPool!.processChunks(method, chunks, {\r\n outputFormat: opts.outputFormat,\r\n csvConfig: opts.csvConfig,\r\n xmlConfig: opts.xmlConfig,\r\n debug: opts.debug\r\n });\r\n\r\n // Merge results intelligently based on output format\r\n const merged = mergeResults(results, opts.outputFormat!);\r\n return new TextEncoder().encode(merged);\r\n }\r\n\r\n private async convertUsingJsParallelism(input: Uint8Array, opts: ConvertBuddyOptions, numThreads: number): Promise<Uint8Array> {\r\n // Split input into chunks based on line boundaries for CSV/NDJSON\r\n const chunks = this.splitIntoChunks(input, Math.max(1, Math.floor(input.length / numThreads)));\r\n \r\n if (opts.debug) {\r\n console.log(`[convert-buddy] Processing ${chunks.length} chunks with JS-level parallelism`);\r\n }\r\n \r\n // Process chunks in parallel with improved coordination\r\n const chunkPromises = chunks.map(async (chunk, index) => {\r\n const chunkOpts = { ...opts, parallelism: 1 }; // Disable recursion\r\n \r\n // For CSV with headers, only the first chunk should process headers\r\n if (opts.inputFormat === \"csv\" && index > 0) {\r\n chunkOpts.csvConfig = { ...chunkOpts.csvConfig, hasHeaders: false };\r\n }\r\n \r\n const chunkBuddy = await ConvertBuddy.create(chunkOpts);\r\n const output = chunkBuddy.push(chunk);\r\n const final = chunkBuddy.finish();\r\n \r\n // Combine chunk output\r\n const result = new Uint8Array(output.length + final.length);\r\n result.set(output, 0);\r\n result.set(final, output.length);\r\n \r\n return result;\r\n });\r\n\r\n const chunkResults = await Promise.all(chunkPromises);\r\n\r\n // Combine results more efficiently\r\n const totalLength = chunkResults.reduce((sum, chunk) => sum + chunk.length, 0);\r\n const result = new Uint8Array(totalLength);\r\n \r\n let offset = 0;\r\n for (const chunk of chunkResults) {\r\n result.set(chunk, offset);\r\n offset += chunk.length;\r\n }\r\n\r\n if (opts.debug) {\r\n console.log(`[convert-buddy] JS parallel processing completed: ${chunks.length} chunks, ${totalLength} bytes`);\r\n }\r\n\r\n return result;\r\n }\r\n\r\n private splitIntoChunks(input: Uint8Array, targetChunkSize: number): Uint8Array[] {\r\n if (input.length <= targetChunkSize) {\r\n return [input];\r\n }\r\n\r\n const chunks: Uint8Array[] = [];\r\n let start = 0;\r\n\r\n while (start < input.length) {\r\n let end = Math.min(start + targetChunkSize, input.length);\r\n \r\n // Try to find a line boundary within a reasonable range\r\n if (end < input.length) {\r\n const searchStart = Math.max(start + targetChunkSize - 1024, start);\r\n const searchEnd = Math.min(end + 1024, input.length);\r\n \r\n // Look for newline\r\n for (let i = searchEnd - 1; i >= searchStart; i--) {\r\n if (input[i] === 0x0A) { // '\\n'\r\n end = i + 1;\r\n break;\r\n }\r\n }\r\n }\r\n \r\n chunks.push(input.slice(start, end));\r\n start = end;\r\n }\r\n\r\n return chunks;\r\n }\r\n\r\n private async convertFromFile(file: File, opts: ConvertBuddyOptions): Promise<Uint8Array> {\r\n return this.convertFromBlob(file, opts);\r\n }\r\n\r\n private async convertFromBlob(blob: Blob, opts: ConvertBuddyOptions): Promise<Uint8Array> {\r\n warnIfLargeFile(blob.size, \"convert\");\r\n \r\n // Handle auto-detection\r\n let actualOpts = { ...opts };\r\n \r\n if (opts.inputFormat === \"auto\") {\r\n const sampleSize = 256 * 1024; // 256KB\r\n const sampleBlob = blob.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 const buddy = await ConvertBuddy.create(actualOpts);\r\n \r\n // Read blob as stream and process\r\n const stream = blob.stream();\r\n const reader = stream.getReader();\r\n \r\n const outputs: Uint8Array[] = [];\r\n \r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n \r\n const output = buddy.push(value);\r\n if (output.length > 0) {\r\n outputs.push(output);\r\n }\r\n }\r\n \r\n const final = buddy.finish();\r\n if (final.length > 0) {\r\n outputs.push(final);\r\n }\r\n \r\n // Combine all outputs\r\n const totalLength = outputs.reduce((sum, arr) => sum + arr.length, 0);\r\n const result = new Uint8Array(totalLength);\r\n let offset = 0;\r\n for (const output of outputs) {\r\n result.set(output, offset);\r\n offset += output.length;\r\n }\r\n \r\n if (opts.profile) {\r\n const stats = buddy.stats();\r\n console.log(\"[convert-buddy] Performance Stats:\", stats);\r\n }\r\n \r\n return result;\r\n } finally {\r\n reader.releaseLock();\r\n }\r\n }\r\n\r\n private async convertFromStream(stream: ReadableStream<Uint8Array>, opts: ConvertBuddyOptions): Promise<Uint8Array> {\r\n // Handle auto-detection by reading a sample first\r\n let actualOpts = { ...opts };\r\n let firstChunks: Uint8Array[] = [];\r\n let totalSampleBytes = 0;\r\n const maxSampleSize = 256 * 1024; // 256KB\r\n \r\n if (opts.inputFormat === \"auto\") {\r\n const reader = stream.getReader();\r\n \r\n try {\r\n while (totalSampleBytes < maxSampleSize) {\r\n const { done, value } = await reader.read();\r\n if (done || !value) break;\r\n \r\n firstChunks.push(value);\r\n totalSampleBytes += value.length;\r\n }\r\n \r\n // Concatenate sample\r\n const sample = new Uint8Array(totalSampleBytes);\r\n let offset = 0;\r\n for (const chunk of firstChunks) {\r\n sample.set(chunk, offset);\r\n offset += chunk.length;\r\n }\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 } finally {\r\n reader.releaseLock();\r\n }\r\n }\r\n\r\n const buddy = await ConvertBuddy.create(actualOpts);\r\n \r\n // Process buffered chunks from auto-detection\r\n const outputs: Uint8Array[] = [];\r\n for (const chunk of firstChunks) {\r\n const output = buddy.push(chunk);\r\n if (output.length > 0) {\r\n outputs.push(output);\r\n }\r\n }\r\n \r\n // Continue with the rest of the stream\r\n const reader = stream.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 \r\n const output = buddy.push(value);\r\n if (output.length > 0) {\r\n outputs.push(output);\r\n }\r\n }\r\n \r\n const final = buddy.finish();\r\n if (final.length > 0) {\r\n outputs.push(final);\r\n }\r\n \r\n // Combine all outputs\r\n const totalLength = outputs.reduce((sum, arr) => sum + arr.length, 0);\r\n const result = new Uint8Array(totalLength);\r\n let offset = 0;\r\n for (const output of outputs) {\r\n result.set(output, offset);\r\n offset += output.length;\r\n }\r\n \r\n if (opts.profile) {\r\n const stats = buddy.stats();\r\n console.log(\"[convert-buddy] Performance Stats:\", stats);\r\n }\r\n \r\n return result;\r\n } finally {\r\n reader.releaseLock();\r\n }\r\n }\r\n\r\n /**\r\n * Legacy create method for backward compatibility.\r\n * Prefer using the constructor: new ConvertBuddy(opts)\r\n */\r\n static async create(opts: ConvertBuddyOptions = {}): Promise<ConvertBuddy> {\r\n const debug = !!opts.debug;\r\n const profile = !!opts.profile;\r\n\r\n // Initialize WASM once (singleton)\r\n await initWasm(debug);\r\n\r\n const wasmModule = await loadWasmModule();\r\n\r\n // Handle auto-detection\r\n let inputFormat = opts.inputFormat;\r\n let csvConfig = opts.csvConfig;\r\n\r\n // We can't auto-detect without data, so we'll defer this to push()\r\n // For now, just validate the format if it's not \"auto\"\r\n if (inputFormat === \"auto\") {\r\n // Auto-detection will be handled on first push()\r\n inputFormat = undefined;\r\n }\r\n\r\n // Optimize chunk size for better WASM performance\r\n // Larger chunks reduce boundary crossing overhead\r\n // Default: 512KB (was 1MB), but can be customized\r\n const chunkTargetBytes = opts.chunkTargetBytes || (512 * 1024);\r\n\r\n let converter;\r\n if (inputFormat && opts.outputFormat) {\r\n // Use withConfig for custom formats\r\n const Converter = (wasmModule as any).Converter;\r\n converter = Converter.withConfig(\r\n debug,\r\n inputFormat,\r\n opts.outputFormat,\r\n chunkTargetBytes,\r\n profile, // Enable stats tracking when profile is enabled\r\n csvConfig || null,\r\n opts.xmlConfig || null,\r\n opts.transform || null\r\n );\r\n } else {\r\n converter = new wasmModule.Converter(debug);\r\n }\r\n\r\n // Check if SIMD is enabled\r\n const simdEnabled = (wasmModule as any).getSimdEnabled?.() ?? false;\r\n\r\n if (debug) console.log(\"[convert-buddy-js] initialized with chunkTargetBytes:\", chunkTargetBytes, \"simd:\", simdEnabled, opts);\r\n \r\n // Create instance using constructor and set internal properties\r\n const instance = new ConvertBuddy(opts);\r\n instance.converter = converter;\r\n instance.simd = simdEnabled;\r\n instance.initialized = true;\r\n \r\n return instance;\r\n }\r\n\r\n push(chunk: Uint8Array): Uint8Array {\r\n if (this.aborted) {\r\n throw new Error(\"Conversion has been aborted\");\r\n }\r\n\r\n if (this.paused) {\r\n throw new Error(\"Conversion is paused. Call resume() before pushing more data.\");\r\n }\r\n\r\n if (this.debug) console.log(\"[convert-buddy-js] push\", chunk.byteLength);\r\n const output = this.converter.push(chunk);\r\n\r\n // Check if we should trigger progress callback\r\n if (this.onProgress) {\r\n const stats = this.stats();\r\n if (stats.bytesIn - this.lastProgressBytes >= this.progressIntervalBytes) {\r\n this.onProgress(stats);\r\n this.lastProgressBytes = stats.bytesIn;\r\n }\r\n }\r\n\r\n return output;\r\n }\r\n\r\n finish(): Uint8Array {\r\n if (this.aborted) {\r\n throw new Error(\"Conversion has been aborted\");\r\n }\r\n\r\n if (this.debug) console.log(\"[convert-buddy-js] finish\");\r\n const output = this.converter.finish();\r\n\r\n // Final progress callback\r\n if (this.onProgress) {\r\n this.onProgress(this.stats());\r\n }\r\n\r\n return output;\r\n }\r\n\r\n stats(): Stats {\r\n if (!this.converter || typeof this.converter.getStats !== 'function') {\r\n // Converter not initialized yet\r\n return {\r\n bytesIn: 0,\r\n bytesOut: 0,\r\n chunksIn: 0,\r\n recordsProcessed: 0,\r\n parseTimeMs: 0,\r\n transformTimeMs: 0,\r\n writeTimeMs: 0,\r\n maxBufferSize: 0,\r\n currentPartialSize: 0,\r\n throughputMbPerSec: 0,\r\n };\r\n }\r\n\r\n try {\r\n const wasmStats = this.converter.getStats();\r\n \r\n // WASM object properties are snake_case (Rust convention)\r\n // Access them directly as they're exposed via wasm_bindgen getters\r\n const stats = {\r\n bytesIn: wasmStats.bytes_in,\r\n bytesOut: wasmStats.bytes_out,\r\n chunksIn: wasmStats.chunks_in,\r\n recordsProcessed: wasmStats.records_processed,\r\n parseTimeMs: wasmStats.parse_time_ms,\r\n transformTimeMs: wasmStats.transform_time_ms,\r\n writeTimeMs: wasmStats.write_time_ms,\r\n maxBufferSize: wasmStats.max_buffer_size,\r\n currentPartialSize: wasmStats.current_partial_size,\r\n throughputMbPerSec: wasmStats.throughput_mb_per_sec,\r\n };\r\n\r\n // Warn if stats tracking is not enabled (profile: false)\r\n if (!this.profile && stats.bytesIn === 0 && stats.chunksIn === 0) {\r\n console.warn(\r\n \"[convert-buddy-js] WARNING: stats() called but profiling is disabled. \" +\r\n \"Enable profiling by setting { profile: true } in ConvertBuddy.create() options to get accurate statistics.\"\r\n );\r\n }\r\n\r\n return stats;\r\n } catch (e) {\r\n if (this.debug) console.error(\"[convert-buddy-js] Error getting stats:\", e);\r\n return {\r\n bytesIn: 0,\r\n bytesOut: 0,\r\n chunksIn: 0,\r\n recordsProcessed: 0,\r\n parseTimeMs: 0,\r\n transformTimeMs: 0,\r\n writeTimeMs: 0,\r\n maxBufferSize: 0,\r\n currentPartialSize: 0,\r\n throughputMbPerSec: 0,\r\n };\r\n }\r\n }\r\n\r\n abort(): void {\r\n this.aborted = true;\r\n if (this.debug) console.log(\"[convert-buddy-js] aborted\");\r\n }\r\n\r\n pause(): void {\r\n this.paused = true;\r\n if (this.debug) console.log(\"[convert-buddy-js] paused\");\r\n }\r\n\r\n resume(): void {\r\n this.paused = false;\r\n if (this.debug) console.log(\"[convert-buddy-js] resumed\");\r\n }\r\n\r\n isAborted(): boolean {\r\n return this.aborted;\r\n }\r\n\r\n isPaused(): boolean {\r\n return this.paused;\r\n }\r\n}\r\n\r\nasync function readSample(\r\n input: DetectInput,\r\n maxBytes = 256 * 1024\r\n): Promise<Uint8Array> {\r\n if (typeof input === \"string\") {\r\n const encoded = new TextEncoder().encode(input);\r\n return encoded.length > maxBytes ? encoded.slice(0, maxBytes) : encoded;\r\n }\r\n\r\n if (input instanceof Uint8Array) {\r\n return input.length > maxBytes ? input.slice(0, maxBytes) : input;\r\n }\r\n\r\n if (input instanceof ArrayBuffer) {\r\n const bytes = new Uint8Array(input as ArrayBuffer);\r\n return bytes.length > maxBytes ? bytes.slice(0, maxBytes) : bytes;\r\n }\r\n\r\n if (isReadableStream(input)) {\r\n const reader = input.getReader();\r\n const chunks: Uint8Array[] = [];\r\n let total = 0;\r\n\r\n while (total < maxBytes) {\r\n const { value, done } = await reader.read();\r\n if (done || !value) break;\r\n const slice = total + value.length > maxBytes\r\n ? value.slice(0, maxBytes - total)\r\n : value;\r\n chunks.push(slice);\r\n total += slice.length;\r\n }\r\n\r\n if (total >= maxBytes) {\r\n await reader.cancel();\r\n }\r\n\r\n return concatChunks(chunks, total);\r\n }\r\n\r\n const chunks: Uint8Array[] = [];\r\n let total = 0;\r\n\r\n for await (const chunk of input as AsyncIterable<Uint8Array>) {\r\n if (total >= maxBytes) {\r\n break;\r\n }\r\n const data = chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk);\r\n const slice = total + data.length > maxBytes\r\n ? data.slice(0, maxBytes - total)\r\n : data;\r\n chunks.push(slice);\r\n total += slice.length;\r\n }\r\n\r\n return concatChunks(chunks, total);\r\n}\r\n\r\nfunction concatChunks(chunks: Uint8Array[], total: number): Uint8Array {\r\n const result = new Uint8Array(total);\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 return result;\r\n}\r\n\r\nfunction isReadableStream(\r\n input: DetectInput\r\n): input is ReadableStream<Uint8Array> {\r\n return typeof (input as ReadableStream<Uint8Array>)?.getReader === \"function\";\r\n}\r\n\r\nasync function loadDetectionWasm(debug: boolean): Promise<WasmModule> {\r\n const wasmModule = await loadWasmModule();\r\n if (typeof wasmModule.default === \"function\") {\r\n await (wasmModule.default as () => Promise<void>)();\r\n }\r\n wasmModule.init(debug);\r\n return wasmModule;\r\n}\r\n\r\nexport async function detectFormat(\r\n input: DetectInput,\r\n opts: DetectOptions = {}\r\n): Promise<Format | \"unknown\"> {\r\n const wasmModule = await loadDetectionWasm(!!opts.debug);\r\n const sample = await readSample(input, opts.maxBytes);\r\n const format = wasmModule.detectFormat?.(sample);\r\n return (format as Format) ?? \"unknown\";\r\n}\r\n\r\nexport async function detectStructure(\r\n input: DetectInput,\r\n formatHint?: Format,\r\n opts: DetectOptions = {}\r\n): Promise<StructureDetection | null> {\r\n const wasmModule = await loadDetectionWasm(!!opts.debug);\r\n const sample = await readSample(input, opts.maxBytes);\r\n const result = wasmModule.detectStructure?.(sample, formatHint);\r\n return result ?? null;\r\n}\r\n\r\n// Backward compatibility functions - these now use the unified detectStructure internally\r\nexport async function detectCsvFieldsAndDelimiter(\r\n input: DetectInput,\r\n opts: DetectOptions = {}\r\n): Promise<CsvDetection | null> {\r\n const structure = await detectStructure(input, \"csv\", opts);\r\n if (structure && structure.format === \"csv\" && structure.delimiter) {\r\n return {\r\n delimiter: structure.delimiter,\r\n fields: structure.fields,\r\n };\r\n }\r\n return null;\r\n}\r\n\r\nexport async function detectXmlElements(\r\n input: DetectInput,\r\n opts: DetectOptions = {}\r\n): Promise<XmlDetection | null> {\r\n const structure = await detectStructure(input, \"xml\", opts);\r\n if (structure && structure.format === \"xml\") {\r\n return {\r\n elements: structure.fields,\r\n recordElement: structure.recordElement,\r\n };\r\n }\r\n return null;\r\n}\r\n\r\n// Helper to auto-detect format and CSV/XML configuration from sample data\r\nexport async function autoDetectConfig(\r\n input: DetectInput,\r\n opts: DetectOptions = {}\r\n): Promise<{ \r\n format: Format | \"unknown\"; \r\n csvConfig?: CsvConfig;\r\n xmlConfig?: XmlConfig;\r\n}> {\r\n const wasmModule = await loadDetectionWasm(!!opts.debug);\r\n const sample = await readSample(input, opts.maxBytes);\r\n \r\n const format = (wasmModule.detectFormat?.(sample) as Format) ?? \"unknown\";\r\n \r\n const result: { format: Format | \"unknown\"; csvConfig?: CsvConfig; xmlConfig?: XmlConfig } = { format };\r\n \r\n if (format === \"csv\") {\r\n const csvDetection = wasmModule.detectCsvFields?.(sample);\r\n if (csvDetection) {\r\n result.csvConfig = {\r\n delimiter: csvDetection.delimiter,\r\n hasHeaders: csvDetection.fields.length > 0,\r\n };\r\n }\r\n } else if (format === \"xml\") {\r\n const xmlDetection = wasmModule.detectXmlElements?.(sample);\r\n if (xmlDetection?.recordElement) {\r\n result.xmlConfig = {\r\n recordElement: xmlDetection.recordElement,\r\n };\r\n }\r\n }\r\n \r\n return result;\r\n}\r\n\r\n// Web Streams TransformStream adapter\r\nexport class ConvertBuddyTransformStream extends TransformStream<Uint8Array, Uint8Array> {\r\n constructor(opts: ConvertBuddyOptions = {}) {\r\n let buddy: ConvertBuddy | null = null;\r\n\r\n super({\r\n async start(controller) {\r\n buddy = await ConvertBuddy.create(opts);\r\n },\r\n\r\n transform(chunk, controller) {\r\n if (!buddy) {\r\n throw new Error(\"ConvertBuddy not initialized\");\r\n }\r\n\r\n const output = buddy.push(chunk);\r\n if (output.length > 0) {\r\n controller.enqueue(output);\r\n }\r\n },\r\n\r\n flush(controller) {\r\n if (!buddy) {\r\n return;\r\n }\r\n\r\n const output = buddy.finish();\r\n if (output.length > 0) {\r\n controller.enqueue(output);\r\n }\r\n\r\n if (opts.profile) {\r\n const stats = buddy.stats();\r\n console.log(\"[convert-buddy] Performance Stats:\", stats);\r\n }\r\n },\r\n });\r\n }\r\n}\r\n\r\n// Utility: Convert entire buffer/string\r\nexport async function convert(\r\n input: Uint8Array | string,\r\n opts: ConvertBuddyOptions = {}\r\n): Promise<Uint8Array> {\r\n try {\r\n const inputBytes = typeof input === \"string\" \r\n ? new TextEncoder().encode(input)\r\n : input;\r\n\r\n // If inputFormat is not specified or is \"auto\", perform auto-detection\r\n let actualOpts = opts;\r\n if (!opts.inputFormat || opts.inputFormat === \"auto\") {\r\n const sample = inputBytes.length > 256 * 1024 \r\n ? inputBytes.slice(0, 256 * 1024) \r\n : inputBytes;\r\n \r\n const detected = await autoDetectConfig(sample, { debug: opts.debug });\r\n \r\n if (detected.format !== \"unknown\") {\r\n actualOpts = { ...opts, inputFormat: detected.format as Format };\r\n \r\n if (detected.csvConfig && !opts.csvConfig) {\r\n actualOpts.csvConfig = detected.csvConfig;\r\n }\r\n \r\n if (detected.xmlConfig && !opts.xmlConfig) {\r\n actualOpts.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 const buddy = await ConvertBuddy.create(actualOpts);\r\n\r\n const output = buddy.push(inputBytes);\r\n const final = buddy.finish();\r\n\r\n // Combine outputs\r\n const result = new Uint8Array(output.length + final.length);\r\n result.set(output, 0);\r\n result.set(final, output.length);\r\n\r\n if (opts.profile) {\r\n const stats = buddy.stats();\r\n console.log(\"[convert-buddy] Performance Stats:\", stats);\r\n }\r\n\r\n return result;\r\n } catch (err: any) {\r\n // Normalize non-Error throws (e.g., wasm JsValue) into Error with message\r\n if (err instanceof Error) throw err;\r\n try {\r\n // Try to stringify common structures\r\n const msg = typeof err === 'string' ? err : (err && err.message) ? err.message : JSON.stringify(err);\r\n throw new Error(String(msg));\r\n } catch (_) {\r\n throw new Error(String(err));\r\n }\r\n }\r\n}\r\n\r\n// Utility: Convert and return as string\r\nexport async function convertToString(\r\n input: Uint8Array | string,\r\n opts: ConvertBuddyOptions = {}\r\n): Promise<string> {\r\n const result = await convert(input, opts);\r\n return decodeUtf8(result);\r\n}\r\n\r\n/**\r\n * Ultra-simple standalone convert function with auto-detection.\r\n * Accepts any input type (URL, File, Buffer, string, stream) and automatically detects format.\r\n * \r\n * @example\r\n * // From URL\r\n * import { convertAny } from \"convert-buddy-js\";\r\n * const result = await convertAny(\"https://example.com/data.csv\", { outputFormat: \"json\" });\r\n * \r\n * @example\r\n * // From File (browser)\r\n * const file = fileInput.files[0];\r\n * const result = await convertAny(file, { outputFormat: \"ndjson\" });\r\n * \r\n * @example\r\n * // From string data\r\n * const result = await convertAny('{\"name\":\"Ada\"}', { outputFormat: \"csv\" });\r\n */\r\nexport async function convertAny(\r\n input: string | Uint8Array | File | Blob | ReadableStream<Uint8Array>,\r\n opts: ConvertOptions\r\n): Promise<Uint8Array> {\r\n const buddy = new ConvertBuddy();\r\n return buddy.convert(input, opts);\r\n}\r\n\r\n/**\r\n * Ultra-simple standalone convert function that returns a string.\r\n * Same as convertAny but decodes the output to a string.\r\n * \r\n * @example\r\n * import { convertAnyToString } from \"convert-buddy-js\";\r\n * const json = await convertAnyToString(\"https://example.com/data.csv\", { outputFormat: \"json\" });\r\n * console.log(JSON.parse(json));\r\n */\r\nexport async function convertAnyToString(\r\n input: string | Uint8Array | File | Blob | ReadableStream<Uint8Array>,\r\n opts: ConvertOptions\r\n): Promise<string> {\r\n const result = await convertAny(input, opts);\r\n return decodeUtf8(result);\r\n}\r\n\r\n// ===== Helper Functions =====\r\n// File format utilities for common use cases\r\n\r\n/**\r\n * Get MIME type for a given format\r\n * \r\n * @example\r\n * const mimeType = getMimeType(\"json\"); // \"application/json\"\r\n */\r\nexport function getMimeType(format: Format): string {\r\n switch (format) {\r\n case \"json\":\r\n return \"application/json\";\r\n case \"ndjson\":\r\n return \"application/x-ndjson\";\r\n case \"csv\":\r\n return \"text/csv\";\r\n case \"xml\":\r\n return \"application/xml\";\r\n }\r\n}\r\n\r\n/**\r\n * Get file extension for a given format (without the dot)\r\n * \r\n * @example\r\n * const ext = getExtension(\"json\"); // \"json\"\r\n */\r\nexport function getExtension(format: Format): string {\r\n return format;\r\n}\r\n\r\n/**\r\n * Get suggested filename for a converted file\r\n * \r\n * @param originalName - Original filename\r\n * @param outputFormat - Target format\r\n * @param includeTimestamp - Whether to include a timestamp (default: false)\r\n * \r\n * @example\r\n * const name = getSuggestedFilename(\"data.csv\", \"json\"); // \"data.json\"\r\n * const name = getSuggestedFilename(\"data.csv\", \"json\", true); // \"data_converted_1234567890.json\"\r\n */\r\nexport function getSuggestedFilename(\r\n originalName: string,\r\n outputFormat: Format,\r\n includeTimestamp = false\r\n): string {\r\n const baseName = originalName.replace(/\\.[^/.]+$/, \"\");\r\n const extension = getExtension(outputFormat);\r\n \r\n if (includeTimestamp) {\r\n return `${baseName}_converted_${Date.now()}.${extension}`;\r\n }\r\n \r\n return `${baseName}.${extension}`;\r\n}\r\n\r\n/**\r\n * Get File System Access API file type configuration for showSaveFilePicker\r\n * \r\n * @example\r\n * const types = getFileTypeConfig(\"json\");\r\n * const handle = await showSaveFilePicker({ types });\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// WASM Threading Capabilities API\r\n/**\r\n * Check if WASM threading is supported in the current environment\r\n * @returns true if SharedArrayBuffer and Atomics are available (required for WASM threads)\r\n */\r\nexport function isWasmThreadingSupported(): boolean {\r\n return detectWasmThreadingSupport();\r\n}\r\n\r\n/**\r\n * Get the optimal number of worker threads based on CPU cores and WASM capabilities\r\n * @returns Recommended thread count for optimal performance\r\n */\r\nexport function getOptimalThreadCount(): number {\r\n const cores = typeof navigator !== 'undefined' \r\n ? (navigator.hardwareConcurrency || 4)\r\n : (process?.env?.UV_THREADPOOL_SIZE ? parseInt(process.env.UV_THREADPOOL_SIZE) : \r\n typeof require !== 'undefined' ? require('os').cpus().length : 4);\r\n \r\n // For current JavaScript-level parallelism, limit to 4 parallel instances\r\n // When true WASM threading is enabled, this can be increased\r\n return Math.min(cores, 4);\r\n}\r\n\r\n/**\r\n * Get current threading capabilities and configuration\r\n * @returns Object with threading information\r\n */\r\nexport function getThreadingInfo(): {\r\n wasmThreadingSupported: boolean;\r\n customThreadPoolAvailable: boolean;\r\n nodejsWasmThreading: boolean;\r\n recommendedThreads: number;\r\n currentThreads: number;\r\n approach: string;\r\n} {\r\n const isNodejs = typeof process !== 'undefined';\r\n \r\n return {\r\n wasmThreadingSupported: detectWasmThreadingSupport(),\r\n customThreadPoolAvailable: typeof window !== 'undefined',\r\n nodejsWasmThreading: isNodejs && !!nodejsThreadPool,\r\n recommendedThreads: getOptimalThreadCount(),\r\n currentThreads: isNodejs ? \r\n (nodejsThreadPool ? nodejsThreadPool.workers?.length || 0 : 0) :\r\n (threadPool ? threadPool.workers?.length || 0 : 0),\r\n approach: isNodejs ? 'nodejs_enhanced_threading' : 'browser_custom_threading'\r\n };\r\n}\r\n\r\n/**\r\n * Backward compatibility alias for ConvertBuddy\r\n * @deprecated Use ConvertBuddy instead\r\n */\r\nexport const Converter = ConvertBuddy;\r\n"],"mappings":"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","names":["require","mod","result","reader","Converter","chunks","total"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export type Format = \"csv\" | \"ndjson\" | \"json\" | \"xml\";\r\nexport type DetectInput =\r\n | Uint8Array\r\n | ArrayBuffer\r\n | string\r\n | ReadableStream<Uint8Array>\r\n | AsyncIterable<Uint8Array>;\r\n\r\nexport type CsvDetection = {\r\n delimiter: string;\r\n fields: string[];\r\n};\r\n\r\nexport type XmlDetection = {\r\n elements: string[];\r\n recordElement?: string;\r\n};\r\n\r\nexport type JsonDetection = {\r\n fields: string[];\r\n};\r\n\r\nexport type NdjsonDetection = {\r\n fields: string[];\r\n};\r\n\r\nexport type StructureDetection = {\r\n format: Format;\r\n fields: string[];\r\n delimiter?: string; // For CSV\r\n recordElement?: string; // For XML\r\n};\r\n\r\nexport type DetectOptions = {\r\n maxBytes?: number;\r\n debug?: boolean;\r\n};\r\n\r\nexport type ProgressCallback = (stats: Stats) => void;\r\n\r\nexport type ConvertBuddyOptions = {\r\n debug?: boolean;\r\n profile?: boolean;\r\n inputFormat?: Format | \"auto\";\r\n outputFormat?: Format;\r\n chunkTargetBytes?: number;\r\n parallelism?: number; // Node only - number of worker threads\r\n maxMemoryMB?: number; // Memory limit for conversions (future use)\r\n csvConfig?: CsvConfig;\r\n xmlConfig?: XmlConfig;\r\n transform?: TransformConfig;\r\n onProgress?: ProgressCallback;\r\n progressIntervalBytes?: number; // Trigger progress callback every N bytes (default: 1MB)\r\n};\r\n\r\nexport type ConvertOptions = {\r\n inputFormat?: Format | \"auto\";\r\n outputFormat: Format;\r\n csvConfig?: CsvConfig;\r\n xmlConfig?: XmlConfig;\r\n transform?: TransformConfig;\r\n onProgress?: ProgressCallback;\r\n};\r\n\r\nexport type CsvConfig = {\r\n delimiter?: string;\r\n quote?: string;\r\n hasHeaders?: boolean;\r\n trimWhitespace?: boolean;\r\n};\r\n\r\nexport type XmlConfig = {\r\n recordElement?: string;\r\n trimText?: boolean;\r\n includeAttributes?: boolean;\r\n expandEntities?: boolean;\r\n};\r\n\r\nexport type TransformMode = \"replace\" | \"augment\";\r\n\r\nexport type Coerce =\r\n | { type: \"string\" }\r\n | { type: \"i64\" }\r\n | { type: \"f64\" }\r\n | { type: \"bool\" }\r\n | { type: \"timestamp_ms\"; format?: \"iso8601\" | \"unix_ms\" | \"unix_s\" };\r\n\r\nexport type FieldMap = {\r\n targetFieldName: string;\r\n originFieldName?: string;\r\n required?: boolean;\r\n defaultValue?: string | number | boolean | null;\r\n coerce?: Coerce;\r\n compute?: string;\r\n};\r\n\r\nexport type TransformConfig = {\r\n mode?: TransformMode;\r\n fields: FieldMap[];\r\n onMissingField?: \"error\" | \"null\" | \"drop\";\r\n onMissingRequired?: \"error\" | \"abort\";\r\n onCoerceError?: \"error\" | \"null\" | \"dropRecord\";\r\n};\r\n\r\nexport type Stats = {\r\n bytesIn: number;\r\n bytesOut: number;\r\n chunksIn: number;\r\n recordsProcessed: number;\r\n parseTimeMs: number;\r\n transformTimeMs: number;\r\n writeTimeMs: number;\r\n maxBufferSize: number;\r\n currentPartialSize: number;\r\n throughputMbPerSec: number;\r\n};\r\n\r\ntype WasmModule = {\r\n default?: unknown;\r\n init: (debugEnabled: boolean) => void;\r\n Converter: new (debug: boolean) => {\r\n push: (chunk: Uint8Array) => Uint8Array;\r\n finish: () => Uint8Array;\r\n getStats: () => Stats;\r\n };\r\n detectFormat?: (sample: Uint8Array) => string | null | undefined;\r\n detectCsvFields?: (sample: Uint8Array) => CsvDetection | null | undefined;\r\n detectXmlElements?: (sample: Uint8Array) => XmlDetection | null | undefined;\r\n detectJsonFields?: (sample: Uint8Array) => JsonDetection | null | undefined;\r\n detectNdjsonFields?: (sample: Uint8Array) => NdjsonDetection | null | undefined;\r\n detectStructure?: (sample: Uint8Array, formatHint?: string) => StructureDetection | null | undefined;\r\n getSimdEnabled?: () => boolean;\r\n __wbg_set_wasm?: (wasm: unknown) => void;\r\n};\r\n\r\nlet wasmModuleInstance: WasmModule | null = null;\r\nlet wasmModuleLoadPromise: Promise<WasmModule> | null = null;\r\nlet wasmThreadingSupported = false;\r\nlet threadPool: any = null; // Custom WASM thread pool (browser)\r\nlet nodejsThreadPool: any = null; // Node.js specific thread pool\r\nconst utf8Decoder = new TextDecoder(\"utf-8\", { fatal: true, ignoreBOM: true });\r\n\r\nfunction decodeUtf8(bytes: Uint8Array): string {\r\n return utf8Decoder.decode(bytes);\r\n}\r\n\r\n// Detect SharedArrayBuffer support for WASM threading\r\nfunction detectWasmThreadingSupport(): boolean {\r\n if (typeof SharedArrayBuffer === 'undefined') {\r\n return false;\r\n }\r\n \r\n // Test if we can actually create a SharedArrayBuffer\r\n try {\r\n new SharedArrayBuffer(1);\r\n return true;\r\n } catch (e) {\r\n return false;\r\n }\r\n}\r\n\r\nasync function loadWasmModule(): Promise<WasmModule> {\r\n // Return cached instance if already loaded\r\n if (wasmModuleInstance) {\r\n return wasmModuleInstance;\r\n }\r\n\r\n // If load is in progress, wait for it\r\n if (wasmModuleLoadPromise) {\r\n return wasmModuleLoadPromise;\r\n }\r\n\r\n // Start loading\r\n wasmModuleLoadPromise = (async () => {\r\n const isNode =\r\n typeof process !== \"undefined\" &&\r\n !!(process as any).versions?.node;\r\n\r\n // Detect threading support\r\n wasmThreadingSupported = detectWasmThreadingSupport();\r\n \r\n if (isNode) {\r\n const nodeModule: any = await import(/* webpackIgnore: true */ \"node:module\");\r\n const createRequire = nodeModule.createRequire as any;\r\n const requireFn = createRequire ? createRequire(import.meta.url) : (module as any).createRequire?.(import.meta.url);\r\n const require = requireFn ?? (globalThis as any).require;\r\n const mod = require(\"../wasm-node.cjs\");\r\n return mod as WasmModule;\r\n }\r\n\r\n // @ts-expect-error - WASM module will be available at runtime in dist/wasm/web/\r\n const mod = (await import(\"./wasm/web/convert_buddy.js\")) as unknown as WasmModule;\r\n \r\n // Initialize threading if supported\r\n if (wasmThreadingSupported && (mod as any).initThreadPool) {\r\n try {\r\n const numThreads = Math.min(navigator.hardwareConcurrency || 4, 8);\r\n await (mod as any).initThreadPool(numThreads);\r\n console.log(`[convert-buddy] WASM threading initialized with ${numThreads} threads`);\r\n } catch (e) {\r\n console.warn('[convert-buddy] WASM threading initialization failed, using single-thread:', e);\r\n wasmThreadingSupported = false;\r\n }\r\n }\r\n \r\n return mod;\r\n })();\r\n\r\n try {\r\n wasmModuleInstance = await wasmModuleLoadPromise;\r\n return wasmModuleInstance;\r\n } finally {\r\n wasmModuleLoadPromise = null;\r\n }\r\n}\r\n\r\nlet wasmInitialized = false;\r\nlet wasmInitPromise: Promise<void> | null = null;\r\n\r\nasync function initWasm(debug: boolean): Promise<void> {\r\n // If already initialized, return immediately\r\n if (wasmInitialized) {\r\n return;\r\n }\r\n\r\n // If initialization is in progress, wait for it\r\n if (wasmInitPromise) {\r\n return wasmInitPromise;\r\n }\r\n\r\n // Start initialization\r\n wasmInitPromise = (async () => {\r\n const wasmModule = await loadWasmModule();\r\n\r\n if (typeof wasmModule.default === \"function\") {\r\n await (wasmModule.default as () => Promise<void>)();\r\n }\r\n\r\n wasmModule.init(debug);\r\n \r\n // Note: Node.js enhanced threading is handled at the JavaScript level\r\n // No WASM thread pool initialization needed\r\n \r\n wasmInitialized = true;\r\n })();\r\n\r\n try {\r\n await wasmInitPromise;\r\n } finally {\r\n wasmInitPromise = null;\r\n }\r\n}\r\n\r\n/**\r\n * Warn if using non-streaming approach with large files\r\n */\r\nfunction warnIfLargeFile(sizeBytes: number, methodName: string = \"convert\"): void {\r\n const SIZE_THRESHOLD = 10 * 1024 * 1024; // 10MB\r\n \r\n if (sizeBytes >= SIZE_THRESHOLD) {\r\n const sizeMB = (sizeBytes / 1024 / 1024).toFixed(1);\r\n console.warn(\r\n `[convert-buddy-js] WARNING: Using ${methodName}() with a large file (${sizeMB}MB). ` +\r\n `This method is intended for small files and may cause memory issues with large files. ` +\r\n `For better performance and memory management with files of any size, use the streaming API: ` +\r\n `ConvertBuddy.create() with push()/finish() methods.`\r\n );\r\n }\r\n}\r\n\r\nexport class ConvertBuddy {\r\n private converter: any;\r\n private debug: boolean;\r\n private profile: boolean;\r\n private aborted: boolean = false;\r\n private paused: boolean = false;\r\n private onProgress?: ProgressCallback;\r\n private progressIntervalBytes: number;\r\n private lastProgressBytes: number = 0;\r\n private globalConfig: ConvertBuddyOptions;\r\n private initialized: boolean = false;\r\n public simd: boolean;\r\n\r\n /**\r\n * Create a new ConvertBuddy instance with global configuration.\r\n * This is useful when you want to set memory limits, debug mode, or other global settings.\r\n * \r\n * @example\r\n * const buddy = new ConvertBuddy({ maxMemoryMB: 512, debug: true });\r\n * const result = await buddy.convert(input, { outputFormat: \"json\" });\r\n */\r\n constructor(opts: ConvertBuddyOptions = {}) {\r\n // Initialize basic properties\r\n this.debug = !!opts.debug;\r\n this.profile = !!opts.profile;\r\n this.simd = false; // Will be set on first convert\r\n this.globalConfig = opts;\r\n this.progressIntervalBytes = opts.progressIntervalBytes || 1024 * 1024;\r\n this.onProgress = opts.onProgress;\r\n this.converter = null; // Will be initialized lazily\r\n this.initialized = false;\r\n }\r\n\r\n /**\r\n * Convert input (string, Buffer, File, URL, etc.) to the desired output format.\r\n * This is the main method for the new simplified API.\r\n * \r\n * @example\r\n * // Auto-detect everything\r\n * const buddy = new ConvertBuddy();\r\n * const result = await buddy.convert(\"https://example.com/data.csv\", { outputFormat: \"json\" });\r\n * \r\n * @example\r\n * // With configuration\r\n * const buddy = new ConvertBuddy({ maxMemoryMB: 512 });\r\n * const result = await buddy.convert(file, { inputFormat: \"csv\", outputFormat: \"json\" });\r\n */\r\n async convert(\r\n input: string | Uint8Array | File | Blob | ReadableStream<Uint8Array>,\r\n opts: ConvertOptions\r\n ): Promise<Uint8Array> {\r\n // Merge global and local options\r\n const mergedOpts: ConvertBuddyOptions = {\r\n ...this.globalConfig,\r\n ...opts,\r\n inputFormat: opts.inputFormat || this.globalConfig.inputFormat || \"auto\",\r\n };\r\n\r\n // Detect input type and convert accordingly\r\n if (typeof input === \"string\") {\r\n // Could be URL or raw data\r\n if (input.startsWith(\"http://\") || input.startsWith(\"https://\")) {\r\n // Fetch from URL\r\n return this.convertFromUrl(input, mergedOpts);\r\n } else {\r\n // Treat as raw data\r\n return this.convertFromString(input, mergedOpts);\r\n }\r\n } else if (input instanceof Uint8Array) {\r\n return this.convertFromBuffer(input, mergedOpts);\r\n } else if (typeof File !== \"undefined\" && input instanceof File) {\r\n return this.convertFromFile(input as File, mergedOpts);\r\n } else if (typeof Blob !== \"undefined\" && input instanceof Blob) {\r\n return this.convertFromBlob(input as Blob, mergedOpts);\r\n } else if (typeof ReadableStream !== \"undefined\" && input instanceof ReadableStream) {\r\n return this.convertFromStream(input, mergedOpts);\r\n } else {\r\n throw new Error(\"Unsupported input type\");\r\n }\r\n }\r\n\r\n private async convertFromUrl(url: string, opts: ConvertBuddyOptions): Promise<Uint8Array> {\r\n const response = await fetch(url);\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch ${url}: ${response.statusText}`);\r\n }\r\n \r\n const stream = response.body;\r\n if (!stream) {\r\n throw new Error(\"Response body is null\");\r\n }\r\n\r\n return this.convertFromStream(stream, opts);\r\n }\r\n\r\n private async convertFromString(input: string, opts: ConvertBuddyOptions): Promise<Uint8Array> {\r\n const inputBytes = new TextEncoder().encode(input);\r\n // Don't warn here - will warn in convertFromBuffer\r\n return this.convertFromBuffer(inputBytes, opts);\r\n }\r\n\r\n private async convertFromBuffer(input: Uint8Array, opts: ConvertBuddyOptions, skipWarning = false): Promise<Uint8Array> {\r\n if (!skipWarning) {\r\n warnIfLargeFile(input.length, \"convert\");\r\n }\r\n \r\n // Use WASM threading for large inputs when available\r\n const useWasmThreading = wasmThreadingSupported && input.length > 256 * 1024; // 256KB threshold\r\n \r\n if (useWasmThreading && opts.debug) {\r\n console.log('[convert-buddy] Using WASM threading for parallel processing');\r\n }\r\n \r\n // Check if we should use JavaScript-level parallelism as fallback\r\n if (!useWasmThreading && opts.parallelism && opts.parallelism > 1 && input.length > 512 * 1024) {\r\n if (opts.debug) {\r\n console.log('[convert-buddy] WASM threading not available, using JavaScript parallelism');\r\n }\r\n return this.convertFromBufferParallel(input, opts);\r\n }\r\n\r\n // Handle auto-detection\r\n let actualOpts = { ...opts };\r\n \r\n if (opts.inputFormat === \"auto\") {\r\n const detected = await autoDetectConfig(input, { 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 const buddy = await ConvertBuddy.create(actualOpts);\r\n const output = buddy.push(input);\r\n const final = buddy.finish();\r\n\r\n // Combine outputs\r\n const result = new Uint8Array(output.length + final.length);\r\n result.set(output, 0);\r\n result.set(final, output.length);\r\n\r\n if (opts.profile) {\r\n const stats = buddy.stats();\r\n console.log(\"[convert-buddy] Performance Stats:\", stats);\r\n }\r\n\r\n return result;\r\n }\r\n\r\n private async convertFromBufferParallel(input: Uint8Array, opts: ConvertBuddyOptions): Promise<Uint8Array> {\r\n // Only use parallel processing for large inputs and supported conversions\r\n const parallelThreshold = 512 * 1024; // 512KB (lowered threshold for better parallelism)\r\n const maxConcurrency = Math.min(\r\n typeof navigator !== \"undefined\" && navigator.hardwareConcurrency\r\n ? navigator.hardwareConcurrency\r\n : 4,\r\n 8\r\n );\r\n \r\n if (input.length < parallelThreshold || !opts.parallelism || opts.parallelism < 2) {\r\n return this.convertFromBuffer(input, { ...opts, parallelism: 1 }, true); // Skip warning on recursive call\r\n }\r\n\r\n // Extended support for parallel processing\r\n const supportedConversions = [\r\n { input: \"csv\", output: \"ndjson\" },\r\n { input: \"csv\", output: \"json\" },\r\n { input: \"ndjson\", output: \"json\" },\r\n { input: \"ndjson\", output: \"csv\" },\r\n { input: \"ndjson\", output: \"ndjson\" }, // passthrough optimization\r\n { input: \"json\", output: \"ndjson\" },\r\n { input: \"json\", output: \"csv\" },\r\n ];\r\n\r\n const isSupported = supportedConversions.some(\r\n conv => conv.input === opts.inputFormat && conv.output === opts.outputFormat\r\n );\r\n\r\n if (!isSupported) {\r\n if (opts.debug) {\r\n console.log(`[convert-buddy] Parallel processing not supported for ${opts.inputFormat} → ${opts.outputFormat}, using sequential`);\r\n }\r\n return this.convertFromBuffer(input, { ...opts, parallelism: 1 });\r\n }\r\n\r\n try {\r\n const actualThreads = Math.min(maxConcurrency, opts.parallelism || maxConcurrency);\r\n const isNodejs = typeof window === \"undefined\" && typeof process !== \"undefined\";\r\n \r\n if (opts.debug) {\r\n const threadingType = isNodejs ? 'Node.js WASM threading' : 'Browser custom threading';\r\n console.log(`[convert-buddy] Using ${threadingType} with ${actualThreads} threads`);\r\n }\r\n\r\n if (isNodejs) {\r\n // Try enhanced Node.js threading first\r\n if (!nodejsThreadPool) {\r\n try {\r\n const { NodejsThreadPool } = await import('./nodejs-thread-pool');\r\n nodejsThreadPool = new NodejsThreadPool({\r\n maxWorkers: actualThreads,\r\n wasmPath: '../wasm-node.cjs'\r\n });\r\n await nodejsThreadPool.initialize();\r\n } catch (error) {\r\n if (opts.debug) {\r\n console.log('[convert-buddy] Node.js thread pool creation failed, using JS parallelism:', error);\r\n }\r\n }\r\n }\r\n\r\n if (nodejsThreadPool) {\r\n return this.convertUsingNodejsThreadPool(input, opts, actualThreads);\r\n } else {\r\n return this.convertUsingJsParallelism(input, opts, actualThreads);\r\n }\r\n } else {\r\n // Browser: Create custom thread pool for WASM-level parallelism\r\n if (!threadPool) {\r\n const { WasmThreadPool } = await import('./thread-pool');\r\n threadPool = new WasmThreadPool({\r\n maxWorkers: actualThreads,\r\n wasmPath: './wasm/web/convert_buddy.js'\r\n });\r\n await threadPool.initialize();\r\n }\r\n\r\n return this.convertUsingWasmThreadPool(input, opts, actualThreads);\r\n }\r\n \r\n } catch (error) {\r\n if (opts.debug) {\r\n console.warn(`[convert-buddy] Parallel processing failed, falling back to sequential:`, error);\r\n }\r\n return this.convertFromBuffer(input, { ...opts, parallelism: 1 });\r\n }\r\n }\r\n\r\n private async convertUsingNodejsThreadPool(input: Uint8Array, opts: ConvertBuddyOptions, numThreads: number): Promise<Uint8Array> {\r\n const { chunkDataNodejs, mergeResultsNodejs } = await import('./nodejs-thread-pool');\r\n \r\n if (opts.debug) {\r\n console.log(`[convert-buddy] Processing with enhanced Node.js threading (${numThreads} workers)`);\r\n }\r\n\r\n // Use optimized chunking for Node.js\r\n const chunks = chunkDataNodejs(input, numThreads);\r\n \r\n // Process chunks using Node.js worker threads\r\n const results = await nodejsThreadPool!.processChunks('convert', chunks, {\r\n outputFormat: opts.outputFormat,\r\n inputFormat: opts.inputFormat,\r\n csvConfig: opts.csvConfig,\r\n xmlConfig: opts.xmlConfig,\r\n debug: false // Disable debug in workers to reduce noise\r\n });\r\n\r\n // Merge results intelligently based on output format\r\n const merged = mergeResultsNodejs(results, opts.outputFormat!);\r\n \r\n if (opts.debug) {\r\n console.log(`[convert-buddy] Node.js threading completed: ${chunks.length} chunks, ${merged.length} bytes`);\r\n }\r\n\r\n return merged;\r\n }\r\n\r\n private async convertUsingWasmThreadPool(input: Uint8Array, opts: ConvertBuddyOptions, numThreads: number): Promise<Uint8Array> {\r\n const inputStr = decodeUtf8(input);\r\n \r\n // Import chunking utilities\r\n const { chunkData, mergeResults } = await import('./thread-pool');\r\n const chunks = chunkData(inputStr, numThreads);\r\n \r\n if (opts.debug) {\r\n console.log(`[convert-buddy] Processing ${chunks.length} chunks with WASM thread pool`);\r\n }\r\n\r\n // Determine method based on conversion type\r\n let method: string;\r\n const conversion = `${opts.inputFormat}_to_${opts.outputFormat}`;\r\n switch (conversion) {\r\n case 'csv_to_ndjson':\r\n case 'csv_to_json':\r\n method = 'parseCSV';\r\n break;\r\n case 'ndjson_to_csv':\r\n case 'ndjson_to_json':\r\n method = 'parseNDJSON';\r\n break;\r\n case 'json_to_csv':\r\n case 'json_to_ndjson':\r\n method = 'parseJSON';\r\n break;\r\n default:\r\n throw new Error(`Unsupported conversion: ${conversion}`);\r\n }\r\n\r\n // Process chunks in parallel using thread pool\r\n const results = await threadPool!.processChunks(method, chunks, {\r\n outputFormat: opts.outputFormat,\r\n csvConfig: opts.csvConfig,\r\n xmlConfig: opts.xmlConfig,\r\n debug: opts.debug\r\n });\r\n\r\n // Merge results intelligently based on output format\r\n const merged = mergeResults(results, opts.outputFormat!);\r\n return new TextEncoder().encode(merged);\r\n }\r\n\r\n private async convertUsingJsParallelism(input: Uint8Array, opts: ConvertBuddyOptions, numThreads: number): Promise<Uint8Array> {\r\n // Split input into chunks based on line boundaries for CSV/NDJSON\r\n const chunks = this.splitIntoChunks(input, Math.max(1, Math.floor(input.length / numThreads)));\r\n \r\n if (opts.debug) {\r\n console.log(`[convert-buddy] Processing ${chunks.length} chunks with JS-level parallelism`);\r\n }\r\n \r\n // Process chunks in parallel with improved coordination\r\n const chunkPromises = chunks.map(async (chunk, index) => {\r\n const chunkOpts = { ...opts, parallelism: 1 }; // Disable recursion\r\n \r\n // For CSV with headers, only the first chunk should process headers\r\n if (opts.inputFormat === \"csv\" && index > 0) {\r\n chunkOpts.csvConfig = { ...chunkOpts.csvConfig, hasHeaders: false };\r\n }\r\n \r\n const chunkBuddy = await ConvertBuddy.create(chunkOpts);\r\n const output = chunkBuddy.push(chunk);\r\n const final = chunkBuddy.finish();\r\n \r\n // Combine chunk output\r\n const result = new Uint8Array(output.length + final.length);\r\n result.set(output, 0);\r\n result.set(final, output.length);\r\n \r\n return result;\r\n });\r\n\r\n const chunkResults = await Promise.all(chunkPromises);\r\n\r\n // Combine results more efficiently\r\n const totalLength = chunkResults.reduce((sum, chunk) => sum + chunk.length, 0);\r\n const result = new Uint8Array(totalLength);\r\n \r\n let offset = 0;\r\n for (const chunk of chunkResults) {\r\n result.set(chunk, offset);\r\n offset += chunk.length;\r\n }\r\n\r\n if (opts.debug) {\r\n console.log(`[convert-buddy] JS parallel processing completed: ${chunks.length} chunks, ${totalLength} bytes`);\r\n }\r\n\r\n return result;\r\n }\r\n\r\n private splitIntoChunks(input: Uint8Array, targetChunkSize: number): Uint8Array[] {\r\n if (input.length <= targetChunkSize) {\r\n return [input];\r\n }\r\n\r\n const chunks: Uint8Array[] = [];\r\n let start = 0;\r\n\r\n while (start < input.length) {\r\n let end = Math.min(start + targetChunkSize, input.length);\r\n \r\n // Try to find a line boundary within a reasonable range\r\n if (end < input.length) {\r\n const searchStart = Math.max(start + targetChunkSize - 1024, start);\r\n const searchEnd = Math.min(end + 1024, input.length);\r\n \r\n // Look for newline\r\n for (let i = searchEnd - 1; i >= searchStart; i--) {\r\n if (input[i] === 0x0A) { // '\\n'\r\n end = i + 1;\r\n break;\r\n }\r\n }\r\n }\r\n \r\n chunks.push(input.slice(start, end));\r\n start = end;\r\n }\r\n\r\n return chunks;\r\n }\r\n\r\n private async convertFromFile(file: File, opts: ConvertBuddyOptions): Promise<Uint8Array> {\r\n return this.convertFromBlob(file, opts);\r\n }\r\n\r\n private async convertFromBlob(blob: Blob, opts: ConvertBuddyOptions): Promise<Uint8Array> {\r\n warnIfLargeFile(blob.size, \"convert\");\r\n \r\n // Handle auto-detection\r\n let actualOpts = { ...opts };\r\n \r\n if (opts.inputFormat === \"auto\") {\r\n const sampleSize = 256 * 1024; // 256KB\r\n const sampleBlob = blob.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 const buddy = await ConvertBuddy.create(actualOpts);\r\n \r\n // Read blob as stream and process\r\n const stream = blob.stream();\r\n const reader = stream.getReader();\r\n \r\n const outputs: Uint8Array[] = [];\r\n \r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n \r\n const output = buddy.push(value);\r\n if (output.length > 0) {\r\n outputs.push(output);\r\n }\r\n }\r\n \r\n const final = buddy.finish();\r\n if (final.length > 0) {\r\n outputs.push(final);\r\n }\r\n \r\n // Combine all outputs\r\n const totalLength = outputs.reduce((sum, arr) => sum + arr.length, 0);\r\n const result = new Uint8Array(totalLength);\r\n let offset = 0;\r\n for (const output of outputs) {\r\n result.set(output, offset);\r\n offset += output.length;\r\n }\r\n \r\n if (opts.profile) {\r\n const stats = buddy.stats();\r\n console.log(\"[convert-buddy] Performance Stats:\", stats);\r\n }\r\n \r\n return result;\r\n } finally {\r\n reader.releaseLock();\r\n }\r\n }\r\n\r\n private async convertFromStream(stream: ReadableStream<Uint8Array>, opts: ConvertBuddyOptions): Promise<Uint8Array> {\r\n // Handle auto-detection by reading a sample first\r\n let actualOpts = { ...opts };\r\n let firstChunks: Uint8Array[] = [];\r\n let totalSampleBytes = 0;\r\n const maxSampleSize = 256 * 1024; // 256KB\r\n \r\n if (opts.inputFormat === \"auto\") {\r\n const reader = stream.getReader();\r\n \r\n try {\r\n while (totalSampleBytes < maxSampleSize) {\r\n const { done, value } = await reader.read();\r\n if (done || !value) break;\r\n \r\n firstChunks.push(value);\r\n totalSampleBytes += value.length;\r\n }\r\n \r\n // Concatenate sample\r\n const sample = new Uint8Array(totalSampleBytes);\r\n let offset = 0;\r\n for (const chunk of firstChunks) {\r\n sample.set(chunk, offset);\r\n offset += chunk.length;\r\n }\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 } finally {\r\n reader.releaseLock();\r\n }\r\n }\r\n\r\n const buddy = await ConvertBuddy.create(actualOpts);\r\n \r\n // Process buffered chunks from auto-detection\r\n const outputs: Uint8Array[] = [];\r\n for (const chunk of firstChunks) {\r\n const output = buddy.push(chunk);\r\n if (output.length > 0) {\r\n outputs.push(output);\r\n }\r\n }\r\n \r\n // Continue with the rest of the stream\r\n const reader = stream.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 \r\n const output = buddy.push(value);\r\n if (output.length > 0) {\r\n outputs.push(output);\r\n }\r\n }\r\n \r\n const final = buddy.finish();\r\n if (final.length > 0) {\r\n outputs.push(final);\r\n }\r\n \r\n // Combine all outputs\r\n const totalLength = outputs.reduce((sum, arr) => sum + arr.length, 0);\r\n const result = new Uint8Array(totalLength);\r\n let offset = 0;\r\n for (const output of outputs) {\r\n result.set(output, offset);\r\n offset += output.length;\r\n }\r\n \r\n if (opts.profile) {\r\n const stats = buddy.stats();\r\n console.log(\"[convert-buddy] Performance Stats:\", stats);\r\n }\r\n \r\n return result;\r\n } finally {\r\n reader.releaseLock();\r\n }\r\n }\r\n\r\n /**\r\n * Legacy create method for backward compatibility.\r\n * Prefer using the constructor: new ConvertBuddy(opts)\r\n */\r\n static async create(opts: ConvertBuddyOptions = {}): Promise<ConvertBuddy> {\r\n const debug = !!opts.debug;\r\n const profile = !!opts.profile;\r\n\r\n // Initialize WASM once (singleton)\r\n await initWasm(debug);\r\n\r\n const wasmModule = await loadWasmModule();\r\n\r\n // Handle auto-detection\r\n let inputFormat = opts.inputFormat;\r\n let csvConfig = opts.csvConfig;\r\n\r\n // We can't auto-detect without data, so we'll defer this to push()\r\n // For now, just validate the format if it's not \"auto\"\r\n if (inputFormat === \"auto\") {\r\n // Auto-detection will be handled on first push()\r\n inputFormat = undefined;\r\n }\r\n\r\n // Optimize chunk size for better WASM performance\r\n // Larger chunks reduce boundary crossing overhead\r\n // Default: 512KB (was 1MB), but can be customized\r\n const chunkTargetBytes = opts.chunkTargetBytes || (512 * 1024);\r\n\r\n let converter;\r\n if (inputFormat && opts.outputFormat) {\r\n // Use withConfig for custom formats\r\n const Converter = (wasmModule as any).Converter;\r\n converter = Converter.withConfig(\r\n debug,\r\n inputFormat,\r\n opts.outputFormat,\r\n chunkTargetBytes,\r\n profile, // Enable stats tracking when profile is enabled\r\n csvConfig || null,\r\n opts.xmlConfig || null,\r\n opts.transform || null\r\n );\r\n } else {\r\n converter = new wasmModule.Converter(debug);\r\n }\r\n\r\n // Check if SIMD is enabled\r\n const simdEnabled = (wasmModule as any).getSimdEnabled?.() ?? false;\r\n\r\n if (debug) console.log(\"[convert-buddy-js] initialized with chunkTargetBytes:\", chunkTargetBytes, \"simd:\", simdEnabled, opts);\r\n \r\n // Create instance using constructor and set internal properties\r\n const instance = new ConvertBuddy(opts);\r\n instance.converter = converter;\r\n instance.simd = simdEnabled;\r\n instance.initialized = true;\r\n \r\n return instance;\r\n }\r\n\r\n push(chunk: Uint8Array): Uint8Array {\r\n if (this.aborted) {\r\n throw new Error(\"Conversion has been aborted\");\r\n }\r\n\r\n if (this.paused) {\r\n throw new Error(\"Conversion is paused. Call resume() before pushing more data.\");\r\n }\r\n\r\n if (this.debug) console.log(\"[convert-buddy-js] push\", chunk.byteLength);\r\n const output = this.converter.push(chunk);\r\n\r\n // Check if we should trigger progress callback\r\n if (this.onProgress) {\r\n const stats = this.stats();\r\n if (stats.bytesIn - this.lastProgressBytes >= this.progressIntervalBytes) {\r\n this.onProgress(stats);\r\n this.lastProgressBytes = stats.bytesIn;\r\n }\r\n }\r\n\r\n return output;\r\n }\r\n\r\n finish(): Uint8Array {\r\n if (this.aborted) {\r\n throw new Error(\"Conversion has been aborted\");\r\n }\r\n\r\n if (this.debug) console.log(\"[convert-buddy-js] finish\");\r\n const output = this.converter.finish();\r\n\r\n // Final progress callback\r\n if (this.onProgress) {\r\n this.onProgress(this.stats());\r\n }\r\n\r\n return output;\r\n }\r\n\r\n stats(): Stats {\r\n if (!this.converter || typeof this.converter.getStats !== 'function') {\r\n // Converter not initialized yet\r\n return {\r\n bytesIn: 0,\r\n bytesOut: 0,\r\n chunksIn: 0,\r\n recordsProcessed: 0,\r\n parseTimeMs: 0,\r\n transformTimeMs: 0,\r\n writeTimeMs: 0,\r\n maxBufferSize: 0,\r\n currentPartialSize: 0,\r\n throughputMbPerSec: 0,\r\n };\r\n }\r\n\r\n try {\r\n const wasmStats = this.converter.getStats();\r\n \r\n // WASM object properties are snake_case (Rust convention)\r\n // Access them directly as they're exposed via wasm_bindgen getters\r\n const stats = {\r\n bytesIn: wasmStats.bytes_in,\r\n bytesOut: wasmStats.bytes_out,\r\n chunksIn: wasmStats.chunks_in,\r\n recordsProcessed: wasmStats.records_processed,\r\n parseTimeMs: wasmStats.parse_time_ms,\r\n transformTimeMs: wasmStats.transform_time_ms,\r\n writeTimeMs: wasmStats.write_time_ms,\r\n maxBufferSize: wasmStats.max_buffer_size,\r\n currentPartialSize: wasmStats.current_partial_size,\r\n throughputMbPerSec: wasmStats.throughput_mb_per_sec,\r\n };\r\n\r\n // Warn if stats tracking is not enabled (profile: false)\r\n if (!this.profile && stats.bytesIn === 0 && stats.chunksIn === 0) {\r\n console.warn(\r\n \"[convert-buddy-js] WARNING: stats() called but profiling is disabled. \" +\r\n \"Enable profiling by setting { profile: true } in ConvertBuddy.create() options to get accurate statistics.\"\r\n );\r\n }\r\n\r\n return stats;\r\n } catch (e) {\r\n if (this.debug) console.error(\"[convert-buddy-js] Error getting stats:\", e);\r\n return {\r\n bytesIn: 0,\r\n bytesOut: 0,\r\n chunksIn: 0,\r\n recordsProcessed: 0,\r\n parseTimeMs: 0,\r\n transformTimeMs: 0,\r\n writeTimeMs: 0,\r\n maxBufferSize: 0,\r\n currentPartialSize: 0,\r\n throughputMbPerSec: 0,\r\n };\r\n }\r\n }\r\n\r\n abort(): void {\r\n this.aborted = true;\r\n if (this.debug) console.log(\"[convert-buddy-js] aborted\");\r\n }\r\n\r\n pause(): void {\r\n this.paused = true;\r\n if (this.debug) console.log(\"[convert-buddy-js] paused\");\r\n }\r\n\r\n resume(): void {\r\n this.paused = false;\r\n if (this.debug) console.log(\"[convert-buddy-js] resumed\");\r\n }\r\n\r\n isAborted(): boolean {\r\n return this.aborted;\r\n }\r\n\r\n isPaused(): boolean {\r\n return this.paused;\r\n }\r\n}\r\n\r\nasync function readSample(\r\n input: DetectInput,\r\n maxBytes = 256 * 1024\r\n): Promise<Uint8Array> {\r\n if (typeof input === \"string\") {\r\n const encoded = new TextEncoder().encode(input);\r\n return encoded.length > maxBytes ? encoded.slice(0, maxBytes) : encoded;\r\n }\r\n\r\n if (input instanceof Uint8Array) {\r\n return input.length > maxBytes ? input.slice(0, maxBytes) : input;\r\n }\r\n\r\n if (input instanceof ArrayBuffer) {\r\n const bytes = new Uint8Array(input as ArrayBuffer);\r\n return bytes.length > maxBytes ? bytes.slice(0, maxBytes) : bytes;\r\n }\r\n\r\n if (isReadableStream(input)) {\r\n const reader = input.getReader();\r\n const chunks: Uint8Array[] = [];\r\n let total = 0;\r\n\r\n while (total < maxBytes) {\r\n const { value, done } = await reader.read();\r\n if (done || !value) break;\r\n const slice = total + value.length > maxBytes\r\n ? value.slice(0, maxBytes - total)\r\n : value;\r\n chunks.push(slice);\r\n total += slice.length;\r\n }\r\n\r\n if (total >= maxBytes) {\r\n await reader.cancel();\r\n }\r\n\r\n return concatChunks(chunks, total);\r\n }\r\n\r\n const chunks: Uint8Array[] = [];\r\n let total = 0;\r\n\r\n for await (const chunk of input as AsyncIterable<Uint8Array>) {\r\n if (total >= maxBytes) {\r\n break;\r\n }\r\n const data = chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk);\r\n const slice = total + data.length > maxBytes\r\n ? data.slice(0, maxBytes - total)\r\n : data;\r\n chunks.push(slice);\r\n total += slice.length;\r\n }\r\n\r\n return concatChunks(chunks, total);\r\n}\r\n\r\nfunction concatChunks(chunks: Uint8Array[], total: number): Uint8Array {\r\n const result = new Uint8Array(total);\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 return result;\r\n}\r\n\r\nfunction isReadableStream(\r\n input: DetectInput\r\n): input is ReadableStream<Uint8Array> {\r\n return typeof (input as ReadableStream<Uint8Array>)?.getReader === \"function\";\r\n}\r\n\r\nasync function loadDetectionWasm(debug: boolean): Promise<WasmModule> {\r\n const wasmModule = await loadWasmModule();\r\n if (typeof wasmModule.default === \"function\") {\r\n await (wasmModule.default as () => Promise<void>)();\r\n }\r\n wasmModule.init(debug);\r\n return wasmModule;\r\n}\r\n\r\nexport async function detectFormat(\r\n input: DetectInput,\r\n opts: DetectOptions = {}\r\n): Promise<Format | \"unknown\"> {\r\n const wasmModule = await loadDetectionWasm(!!opts.debug);\r\n const sample = await readSample(input, opts.maxBytes);\r\n const format = wasmModule.detectFormat?.(sample);\r\n return (format as Format) ?? \"unknown\";\r\n}\r\n\r\nexport async function detectStructure(\r\n input: DetectInput,\r\n formatHint?: Format,\r\n opts: DetectOptions = {}\r\n): Promise<StructureDetection | null> {\r\n const wasmModule = await loadDetectionWasm(!!opts.debug);\r\n const sample = await readSample(input, opts.maxBytes);\r\n const result = wasmModule.detectStructure?.(sample, formatHint);\r\n return result ?? null;\r\n}\r\n\r\n// Backward compatibility functions - these now use the unified detectStructure internally\r\nexport async function detectCsvFieldsAndDelimiter(\r\n input: DetectInput,\r\n opts: DetectOptions = {}\r\n): Promise<CsvDetection | null> {\r\n const structure = await detectStructure(input, \"csv\", opts);\r\n if (structure && structure.format === \"csv\" && structure.delimiter) {\r\n return {\r\n delimiter: structure.delimiter,\r\n fields: structure.fields,\r\n };\r\n }\r\n return null;\r\n}\r\n\r\nexport async function detectXmlElements(\r\n input: DetectInput,\r\n opts: DetectOptions = {}\r\n): Promise<XmlDetection | null> {\r\n const structure = await detectStructure(input, \"xml\", opts);\r\n if (structure && structure.format === \"xml\") {\r\n return {\r\n elements: structure.fields,\r\n recordElement: structure.recordElement,\r\n };\r\n }\r\n return null;\r\n}\r\n\r\n// Helper to auto-detect format and CSV/XML configuration from sample data\r\nexport async function autoDetectConfig(\r\n input: DetectInput,\r\n opts: DetectOptions = {}\r\n): Promise<{ \r\n format: Format | \"unknown\"; \r\n csvConfig?: CsvConfig;\r\n xmlConfig?: XmlConfig;\r\n}> {\r\n const wasmModule = await loadDetectionWasm(!!opts.debug);\r\n const sample = await readSample(input, opts.maxBytes);\r\n \r\n const format = (wasmModule.detectFormat?.(sample) as Format) ?? \"unknown\";\r\n \r\n const result: { format: Format | \"unknown\"; csvConfig?: CsvConfig; xmlConfig?: XmlConfig } = { format };\r\n \r\n if (format === \"csv\") {\r\n const csvDetection = wasmModule.detectCsvFields?.(sample);\r\n if (csvDetection) {\r\n result.csvConfig = {\r\n delimiter: csvDetection.delimiter,\r\n hasHeaders: csvDetection.fields.length > 0,\r\n };\r\n }\r\n } else if (format === \"xml\") {\r\n const xmlDetection = wasmModule.detectXmlElements?.(sample);\r\n if (xmlDetection?.recordElement) {\r\n result.xmlConfig = {\r\n recordElement: xmlDetection.recordElement,\r\n };\r\n }\r\n }\r\n \r\n return result;\r\n}\r\n\r\n// Web Streams TransformStream adapter\r\nexport class ConvertBuddyTransformStream extends TransformStream<Uint8Array, Uint8Array> {\r\n constructor(opts: ConvertBuddyOptions = {}) {\r\n let buddy: ConvertBuddy | null = null;\r\n\r\n super({\r\n async start(controller) {\r\n buddy = await ConvertBuddy.create(opts);\r\n },\r\n\r\n transform(chunk, controller) {\r\n if (!buddy) {\r\n throw new Error(\"ConvertBuddy not initialized\");\r\n }\r\n\r\n const output = buddy.push(chunk);\r\n if (output.length > 0) {\r\n controller.enqueue(output);\r\n }\r\n },\r\n\r\n flush(controller) {\r\n if (!buddy) {\r\n return;\r\n }\r\n\r\n const output = buddy.finish();\r\n if (output.length > 0) {\r\n controller.enqueue(output);\r\n }\r\n\r\n if (opts.profile) {\r\n const stats = buddy.stats();\r\n console.log(\"[convert-buddy] Performance Stats:\", stats);\r\n }\r\n },\r\n });\r\n }\r\n}\r\n\r\n// Utility: Convert entire buffer/string\r\nexport async function convert(\r\n input: Uint8Array | string,\r\n opts: ConvertBuddyOptions = {}\r\n): Promise<Uint8Array> {\r\n try {\r\n const inputBytes = typeof input === \"string\" \r\n ? new TextEncoder().encode(input)\r\n : input;\r\n\r\n // If inputFormat is not specified or is \"auto\", perform auto-detection\r\n let actualOpts = opts;\r\n if (!opts.inputFormat || opts.inputFormat === \"auto\") {\r\n const sample = inputBytes.length > 256 * 1024 \r\n ? inputBytes.slice(0, 256 * 1024) \r\n : inputBytes;\r\n \r\n const detected = await autoDetectConfig(sample, { debug: opts.debug });\r\n \r\n if (detected.format !== \"unknown\") {\r\n actualOpts = { ...opts, inputFormat: detected.format as Format };\r\n \r\n if (detected.csvConfig && !opts.csvConfig) {\r\n actualOpts.csvConfig = detected.csvConfig;\r\n }\r\n \r\n if (detected.xmlConfig && !opts.xmlConfig) {\r\n actualOpts.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 const buddy = await ConvertBuddy.create(actualOpts);\r\n\r\n const output = buddy.push(inputBytes);\r\n const final = buddy.finish();\r\n\r\n // Combine outputs\r\n const result = new Uint8Array(output.length + final.length);\r\n result.set(output, 0);\r\n result.set(final, output.length);\r\n\r\n if (opts.profile) {\r\n const stats = buddy.stats();\r\n console.log(\"[convert-buddy] Performance Stats:\", stats);\r\n }\r\n\r\n return result;\r\n } catch (err: any) {\r\n // Normalize non-Error throws (e.g., wasm JsValue) into Error with message\r\n if (err instanceof Error) throw err;\r\n try {\r\n // Try to stringify common structures\r\n const msg = typeof err === 'string' ? err : (err && err.message) ? err.message : JSON.stringify(err);\r\n throw new Error(String(msg));\r\n } catch (_) {\r\n throw new Error(String(err));\r\n }\r\n }\r\n}\r\n\r\n// Utility: Convert and return as string\r\nexport async function convertToString(\r\n input: Uint8Array | string,\r\n opts: ConvertBuddyOptions = {}\r\n): Promise<string> {\r\n const result = await convert(input, opts);\r\n return decodeUtf8(result);\r\n}\r\n\r\n/**\r\n * Ultra-simple standalone convert function with auto-detection.\r\n * Accepts any input type (URL, File, Buffer, string, stream) and automatically detects format.\r\n * \r\n * @example\r\n * // From URL\r\n * import { convertAny } from \"convert-buddy-js\";\r\n * const result = await convertAny(\"https://example.com/data.csv\", { outputFormat: \"json\" });\r\n * \r\n * @example\r\n * // From File (browser)\r\n * const file = fileInput.files[0];\r\n * const result = await convertAny(file, { outputFormat: \"ndjson\" });\r\n * \r\n * @example\r\n * // From string data\r\n * const result = await convertAny('{\"name\":\"Ada\"}', { outputFormat: \"csv\" });\r\n */\r\nexport async function convertAny(\r\n input: string | Uint8Array | File | Blob | ReadableStream<Uint8Array>,\r\n opts: ConvertOptions\r\n): Promise<Uint8Array> {\r\n const buddy = new ConvertBuddy();\r\n return buddy.convert(input, opts);\r\n}\r\n\r\n/**\r\n * Ultra-simple standalone convert function that returns a string.\r\n * Same as convertAny but decodes the output to a string.\r\n * \r\n * @example\r\n * import { convertAnyToString } from \"convert-buddy-js\";\r\n * const json = await convertAnyToString(\"https://example.com/data.csv\", { outputFormat: \"json\" });\r\n * console.log(JSON.parse(json));\r\n */\r\nexport async function convertAnyToString(\r\n input: string | Uint8Array | File | Blob | ReadableStream<Uint8Array>,\r\n opts: ConvertOptions\r\n): Promise<string> {\r\n const result = await convertAny(input, opts);\r\n return decodeUtf8(result);\r\n}\r\n\r\n// ===== Helper Functions =====\r\n// File format utilities for common use cases\r\n\r\n/**\r\n * Get MIME type for a given format\r\n * \r\n * @example\r\n * const mimeType = getMimeType(\"json\"); // \"application/json\"\r\n */\r\nexport function getMimeType(format: Format): string {\r\n switch (format) {\r\n case \"json\":\r\n return \"application/json\";\r\n case \"ndjson\":\r\n return \"application/x-ndjson\";\r\n case \"csv\":\r\n return \"text/csv\";\r\n case \"xml\":\r\n return \"application/xml\";\r\n }\r\n}\r\n\r\n/**\r\n * Get file extension for a given format (without the dot)\r\n * \r\n * @example\r\n * const ext = getExtension(\"json\"); // \"json\"\r\n */\r\nexport function getExtension(format: Format): string {\r\n return format;\r\n}\r\n\r\n/**\r\n * Get suggested filename for a converted file\r\n * \r\n * @param originalName - Original filename\r\n * @param outputFormat - Target format\r\n * @param includeTimestamp - Whether to include a timestamp (default: false)\r\n * \r\n * @example\r\n * const name = getSuggestedFilename(\"data.csv\", \"json\"); // \"data.json\"\r\n * const name = getSuggestedFilename(\"data.csv\", \"json\", true); // \"data_converted_1234567890.json\"\r\n */\r\nexport function getSuggestedFilename(\r\n originalName: string,\r\n outputFormat: Format,\r\n includeTimestamp = false\r\n): string {\r\n const baseName = originalName.replace(/\\.[^/.]+$/, \"\");\r\n const extension = getExtension(outputFormat);\r\n \r\n if (includeTimestamp) {\r\n return `${baseName}_converted_${Date.now()}.${extension}`;\r\n }\r\n \r\n return `${baseName}.${extension}`;\r\n}\r\n\r\n/**\r\n * Get File System Access API file type configuration for showSaveFilePicker\r\n * \r\n * @example\r\n * const types = getFileTypeConfig(\"json\");\r\n * const handle = await showSaveFilePicker({ types });\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// WASM Threading Capabilities API\r\n/**\r\n * Check if WASM threading is supported in the current environment\r\n * @returns true if SharedArrayBuffer and Atomics are available (required for WASM threads)\r\n */\r\nexport function isWasmThreadingSupported(): boolean {\r\n return detectWasmThreadingSupport();\r\n}\r\n\r\n/**\r\n * Get the optimal number of worker threads based on CPU cores and WASM capabilities\r\n * @returns Recommended thread count for optimal performance\r\n */\r\nexport function getOptimalThreadCount(): number {\r\n const cores = typeof navigator !== 'undefined' \r\n ? (navigator.hardwareConcurrency || 4)\r\n : (process?.env?.UV_THREADPOOL_SIZE ? parseInt(process.env.UV_THREADPOOL_SIZE) : \r\n typeof require !== 'undefined' ? require('os').cpus().length : 4);\r\n \r\n // For current JavaScript-level parallelism, limit to 4 parallel instances\r\n // When true WASM threading is enabled, this can be increased\r\n return Math.min(cores, 4);\r\n}\r\n\r\n/**\r\n * Get current threading capabilities and configuration\r\n * @returns Object with threading information\r\n */\r\nexport function getThreadingInfo(): {\r\n wasmThreadingSupported: boolean;\r\n customThreadPoolAvailable: boolean;\r\n nodejsWasmThreading: boolean;\r\n recommendedThreads: number;\r\n currentThreads: number;\r\n approach: string;\r\n} {\r\n const isNodejs = typeof process !== 'undefined';\r\n \r\n return {\r\n wasmThreadingSupported: detectWasmThreadingSupport(),\r\n customThreadPoolAvailable: typeof window !== 'undefined',\r\n nodejsWasmThreading: isNodejs && !!nodejsThreadPool,\r\n recommendedThreads: getOptimalThreadCount(),\r\n currentThreads: isNodejs ? \r\n (nodejsThreadPool ? nodejsThreadPool.workers?.length || 0 : 0) :\r\n (threadPool ? threadPool.workers?.length || 0 : 0),\r\n approach: isNodejs ? 'nodejs_enhanced_threading' : 'browser_custom_threading'\r\n };\r\n}\r\n\r\n/**\r\n * Backward compatibility alias for ConvertBuddy\r\n * @deprecated Use ConvertBuddy instead\r\n */\r\nexport const Converter = ConvertBuddy;\r\n"],"mappings":"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","names":["require","mod","result","reader","Converter","chunks","total"]}
package/package.json CHANGED
@@ -1,19 +1,14 @@
1
1
  {
2
2
  "name": "convert-buddy-js",
3
- "version": "0.10.7",
3
+ "version": "0.10.9",
4
4
  "description": "TypeScript wrapper for convert-buddy (Rust/WASM core)",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "main": "./dist/index.js",
8
- "browser": "./dist/browser.js",
9
8
  "types": "./dist/index.d.ts",
10
9
  "exports": {
11
10
  ".": {
12
11
  "types": "./dist/index.d.ts",
13
- "import": {
14
- "browser": "./dist/browser.js",
15
- "default": "./dist/index.js"
16
- },
17
12
  "default": "./dist/index.js"
18
13
  },
19
14
  "./node": {
@@ -23,8 +18,7 @@
23
18
  "./browser": {
24
19
  "types": "./dist/browser.d.ts",
25
20
  "default": "./dist/browser.js"
26
- },
27
- "./*": "./dist/*"
21
+ }
28
22
  },
29
23
  "files": [
30
24
  "dist/**",
@@ -38,9 +32,7 @@
38
32
  "build:wasm:node": "set CONVERT_BUDDY_WASM_TARGET=nodejs&& node ./scripts/build-wasm.mjs",
39
33
  "build:wasm": "npm run build:wasm:web && npm run build:wasm:node",
40
34
  "sync:wasm": "node ./scripts/sync-wasm.mjs",
41
- "build:js": "tsup",
42
- "build:browser:compat": "tsup src/browser.ts --format esm --target es2017 --outDir dist-compat --sourcemap && node ./scripts/copy-browser-compat.mjs",
43
- "build": "npm run build:wasm && npm run build:js && npm run build:browser:compat && npm run sync:wasm",
35
+ "build": "npm run build:wasm && tsup && npm run sync:wasm",
44
36
  "check:wasm": "node ./scripts/check-wasm.mjs",
45
37
  "test": "npm run build && node --test ./dist/tests/edge-cases/*.test.js",
46
38
  "bench": "npm run build && node --expose-gc ./dist/bench/runner.js",