convert-buddy-js 0.10.18 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +49 -4
  2. package/dist/browser-stream-controller.d.ts +107 -0
  3. package/dist/browser-stream-controller.js +226 -0
  4. package/dist/browser-stream-controller.js.map +1 -0
  5. package/dist/browser.d.ts +16 -195
  6. package/dist/browser.js +78 -339
  7. package/dist/browser.js.map +1 -1
  8. package/dist/index-BpUN6Tdz.d.ts +440 -0
  9. package/dist/index.d.ts +1 -271
  10. package/dist/index.js +34 -0
  11. package/dist/index.js.map +1 -1
  12. package/dist/node-stream-controller.d.ts +133 -0
  13. package/dist/node-stream-controller.js +274 -0
  14. package/dist/node-stream-controller.js.map +1 -0
  15. package/dist/node.d.ts +3 -2
  16. package/dist/node.js +2 -0
  17. package/dist/node.js.map +1 -1
  18. package/dist/stream-controller.d.ts +1 -0
  19. package/dist/stream-controller.js +277 -0
  20. package/dist/stream-controller.js.map +1 -0
  21. package/dist/streaming-worker.js +1 -1
  22. package/dist/streaming-worker.js.map +1 -1
  23. package/dist/tests/stream-controller.test.js +237 -0
  24. package/dist/tests/stream-controller.test.js.map +1 -0
  25. package/dist/wasm/nodejs/convert_buddy.d.ts +6 -0
  26. package/dist/wasm/nodejs/convert_buddy.js +58 -28
  27. package/dist/wasm/nodejs/convert_buddy_bg.wasm +0 -0
  28. package/dist/wasm/nodejs/convert_buddy_bg.wasm.d.ts +4 -3
  29. package/dist/wasm/web/convert_buddy.d.ts +10 -3
  30. package/dist/wasm/web/convert_buddy.js +55 -27
  31. package/dist/wasm/web/convert_buddy_bg.wasm +0 -0
  32. package/dist/wasm/web/convert_buddy_bg.wasm.d.ts +4 -3
  33. package/package.json +3 -5
  34. package/dist/browser-core.d.ts +0 -196
  35. package/dist/browser-core.js +0 -787
  36. package/dist/browser-core.js.map +0 -1
  37. package/dist/wasm/nodejs/convert_buddy.cjs +0 -712
package/README.md CHANGED
@@ -111,9 +111,9 @@ const json = await convertToString("input.csv", {
111
111
 
112
112
  ## API Overview
113
113
 
114
- Convert Buddy offers four layers of control, from one-liners to fully manual streaming.
114
+ Convert Buddy offers multiple layers of control, from one-liners to fully manual streaming.
115
115
 
116
- 1. Ultra-simple API
116
+ ### 1. Ultra-simple API
117
117
 
118
118
  ```ts
119
119
  import { convert, convertToString } from "convert-buddy-js";
@@ -130,7 +130,52 @@ Supported input types
130
130
  - `ReadableStream<Uint8Array>`
131
131
  - Node file paths
132
132
 
133
- 2. Instance-based API
133
+ ### 2. StreamController API (NEW! 🎉)
134
+
135
+ **Per-record processing with backpressure management**
136
+
137
+ ```ts
138
+ import { NodeStreamController } from "convert-buddy-js/node";
139
+
140
+ const controller = new NodeStreamController({
141
+ inputFormat: "csv",
142
+ outputFormat: "ndjson",
143
+ onRecord: async (record, index) => {
144
+ // Process each record as it's converted
145
+ await saveToDatabase(record);
146
+ },
147
+ onStreamProgress: (stats, recordCount) => {
148
+ console.log(`Processed ${recordCount} records`);
149
+ },
150
+ progressBatchSize: 1000,
151
+ });
152
+
153
+ // Option 1: Await (wait for completion)
154
+ await controller.process("large-file.csv");
155
+
156
+ // Option 2: Fire-and-forget (non-blocking, runs in background)
157
+ controller.process("large-file.csv").then(() => {
158
+ console.log("Done!");
159
+ });
160
+ ```
161
+
162
+ **Browser version**
163
+
164
+ ```ts
165
+ import { BrowserStreamController } from "convert-buddy-js/browser";
166
+
167
+ const controller = new BrowserStreamController({
168
+ inputFormat: "csv",
169
+ outputFormat: "ndjson",
170
+ onRecord: (record) => displayRecord(record),
171
+ });
172
+
173
+ await controller.process(fileInput.files[0]);
174
+ ```
175
+
176
+ 📚 **[See Full StreamController Documentation](./STREAM_CONTROLLER_GUIDE.md)**
177
+
178
+ ### 3. Instance-based API
134
179
 
135
180
  ```ts
136
181
  import { ConvertBuddy } from "convert-buddy-js";
@@ -144,7 +189,7 @@ const buddy = new ConvertBuddy({
144
189
  const out = await buddy.convert(file, { outputFormat: "ndjson" });
145
190
  ```
146
191
 
147
- 3. High-level helpers
192
+ ### 4. High-level helpers
148
193
 
149
194
  **Browser helpers**
150
195
 
@@ -0,0 +1,107 @@
1
+ import { A as StreamControllerOptions, i as Stats } from './index-BpUN6Tdz.js';
2
+
3
+ /**
4
+ * Browser-specific StreamController implementation
5
+ *
6
+ * Provides high-level streaming API for browser environments with ReadableStream support.
7
+ */
8
+
9
+ type BrowserStreamInput = ReadableStream<Uint8Array> | string | Blob | File;
10
+ /**
11
+ * BrowserStreamController - High-level streaming API for browser environments
12
+ *
13
+ * Features:
14
+ * - Per-record callbacks with backpressure management
15
+ * - Pause/resume/abort controls
16
+ * - Progress tracking
17
+ * - Automatic NDJSON/CSV/JSON/XML splitting and parsing
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * const controller = new BrowserStreamController({
22
+ * inputFormat: "csv",
23
+ * outputFormat: "ndjson",
24
+ * onRecord: async (record, index) => {
25
+ * await processRecord(record);
26
+ * },
27
+ * onProgress: (stats, recordCount) => {
28
+ * console.log(`Processed ${recordCount} records`);
29
+ * }
30
+ * });
31
+ *
32
+ * await controller.process(fetch('/data.csv').then(r => r.body!));
33
+ * ```
34
+ */
35
+ declare class BrowserStreamController {
36
+ private options;
37
+ private buddy;
38
+ private reader;
39
+ private aborted;
40
+ private paused;
41
+ private recordCount;
42
+ private splitter;
43
+ constructor(options: StreamControllerOptions);
44
+ /**
45
+ * Process a stream/URL/File/Blob and invoke callbacks for each record
46
+ */
47
+ process(input: BrowserStreamInput): Promise<void>;
48
+ /**
49
+ * Convert various input types to ReadableStream
50
+ */
51
+ private inputToStream;
52
+ /**
53
+ * Process the stream chunk by chunk
54
+ */
55
+ private processStream;
56
+ /**
57
+ * Process output bytes and split into records
58
+ */
59
+ private processOutput;
60
+ /**
61
+ * Invoke the onRecord callback with proper backpressure handling
62
+ */
63
+ private invokeRecordCallback;
64
+ /**
65
+ * Pause the stream processing
66
+ */
67
+ pause(): void;
68
+ /**
69
+ * Resume the stream processing
70
+ */
71
+ resume(): void;
72
+ /**
73
+ * Abort the stream processing
74
+ */
75
+ abort(): void;
76
+ /**
77
+ * Get current statistics
78
+ */
79
+ stats(): Stats | null;
80
+ /**
81
+ * Get current record count
82
+ */
83
+ getRecordCount(): number;
84
+ /**
85
+ * Check if processing is paused
86
+ */
87
+ isPaused(): boolean;
88
+ /**
89
+ * Check if processing is aborted
90
+ */
91
+ isAborted(): boolean;
92
+ }
93
+ /**
94
+ * Convenience function to process a stream with a simple callback
95
+ *
96
+ * @example
97
+ * ```ts
98
+ * await processStream('/data.csv', {
99
+ * inputFormat: 'csv',
100
+ * outputFormat: 'ndjson',
101
+ * onRecord: (record) => console.log(record),
102
+ * });
103
+ * ```
104
+ */
105
+ declare function processStream(input: BrowserStreamInput, options: StreamControllerOptions): Promise<void>;
106
+
107
+ export { BrowserStreamController, type BrowserStreamInput, processStream };
@@ -0,0 +1,226 @@
1
+ import { ConvertBuddy } from "./index.js";
2
+ import { createSplitter } from "./stream-controller.js";
3
+ class BrowserStreamController {
4
+ options;
5
+ buddy = null;
6
+ reader = null;
7
+ aborted = false;
8
+ paused = false;
9
+ recordCount = 0;
10
+ splitter;
11
+ constructor(options) {
12
+ this.options = {
13
+ outputFormat: "ndjson",
14
+ progressBatchSize: 1e3,
15
+ autoPause: true,
16
+ ...options
17
+ };
18
+ this.splitter = createSplitter(this.options.outputFormat, this.options);
19
+ }
20
+ /**
21
+ * Process a stream/URL/File/Blob and invoke callbacks for each record
22
+ */
23
+ async process(input) {
24
+ try {
25
+ const stream = await this.inputToStream(input);
26
+ this.buddy = await ConvertBuddy.create({
27
+ ...this.options,
28
+ profile: true
29
+ // Enable stats for progress tracking
30
+ });
31
+ this.reader = stream.getReader();
32
+ await this.processStream();
33
+ } finally {
34
+ if (this.reader) {
35
+ try {
36
+ await this.reader.cancel();
37
+ } catch (e) {
38
+ }
39
+ this.reader = null;
40
+ }
41
+ this.buddy = null;
42
+ }
43
+ }
44
+ /**
45
+ * Convert various input types to ReadableStream
46
+ */
47
+ async inputToStream(input) {
48
+ if (typeof input === "string") {
49
+ if (input.startsWith("http://") || input.startsWith("https://")) {
50
+ const response = await fetch(input);
51
+ if (!response.ok) {
52
+ throw new Error(`Failed to fetch ${input}: ${response.statusText}`);
53
+ }
54
+ if (!response.body) {
55
+ throw new Error("Response body is null");
56
+ }
57
+ return response.body;
58
+ } else {
59
+ const encoder = new TextEncoder();
60
+ const bytes = encoder.encode(input);
61
+ return new ReadableStream({
62
+ start(controller) {
63
+ controller.enqueue(bytes);
64
+ controller.close();
65
+ }
66
+ });
67
+ }
68
+ } else if (typeof ReadableStream !== "undefined" && input instanceof ReadableStream) {
69
+ return input;
70
+ } else if (typeof Blob !== "undefined" && input instanceof Blob || typeof File !== "undefined" && input instanceof File) {
71
+ return input.stream();
72
+ } else {
73
+ throw new Error("Unsupported input type for BrowserStreamController");
74
+ }
75
+ }
76
+ /**
77
+ * Process the stream chunk by chunk
78
+ */
79
+ async processStream() {
80
+ if (!this.buddy || !this.reader) {
81
+ throw new Error("Stream not initialized");
82
+ }
83
+ try {
84
+ while (true) {
85
+ if (this.aborted) {
86
+ this.buddy.abort();
87
+ break;
88
+ }
89
+ while (this.paused && !this.aborted) {
90
+ await new Promise((resolve) => setTimeout(resolve, 100));
91
+ }
92
+ const { done, value } = await this.reader.read();
93
+ if (done) {
94
+ const finalOutput = this.buddy.finish();
95
+ if (finalOutput.length > 0) {
96
+ await this.processOutput(finalOutput);
97
+ }
98
+ const finalRecords = this.splitter.flush();
99
+ for (const record of finalRecords) {
100
+ await this.invokeRecordCallback(record);
101
+ }
102
+ break;
103
+ }
104
+ const needsRecords = !!this.options.onRecord;
105
+ const result = this.buddy.pushWithRecords(value, needsRecords);
106
+ if (typeof result === "object" && "output" in result) {
107
+ if (result.output.length > 0) {
108
+ await this.processOutput(result.output, result.records);
109
+ }
110
+ } else if (result.length > 0) {
111
+ await this.processOutput(result);
112
+ }
113
+ }
114
+ } catch (error) {
115
+ if (this.aborted) {
116
+ return;
117
+ }
118
+ throw error;
119
+ }
120
+ }
121
+ /**
122
+ * Process output bytes and split into records
123
+ */
124
+ async processOutput(output, wasmRecords) {
125
+ if (this.options.onData) {
126
+ this.options.onData(output);
127
+ }
128
+ const records = wasmRecords && wasmRecords.length > 0 ? wasmRecords : this.splitter.push(output);
129
+ for (const record of records) {
130
+ if (this.aborted) break;
131
+ await this.invokeRecordCallback(record);
132
+ if (this.options.onStreamProgress && this.recordCount % (this.options.progressBatchSize || 1e3) === 0) {
133
+ const stats = this.buddy.stats();
134
+ this.options.onStreamProgress(stats, this.recordCount);
135
+ }
136
+ }
137
+ }
138
+ /**
139
+ * Invoke the onRecord callback with proper backpressure handling
140
+ */
141
+ async invokeRecordCallback(record) {
142
+ if (!this.options.onRecord) {
143
+ this.recordCount++;
144
+ return;
145
+ }
146
+ try {
147
+ const result = this.options.onRecord(record, this.recordCount);
148
+ if (this.options.autoPause && result instanceof Promise) {
149
+ const shouldContinue = await result;
150
+ if (shouldContinue === false) {
151
+ this.pause();
152
+ }
153
+ } else if (result === false) {
154
+ this.pause();
155
+ }
156
+ this.recordCount++;
157
+ } catch (error) {
158
+ console.error("[BrowserStreamController] Error in onRecord callback:", error);
159
+ throw error;
160
+ }
161
+ }
162
+ /**
163
+ * Pause the stream processing
164
+ */
165
+ pause() {
166
+ this.paused = true;
167
+ if (this.buddy) {
168
+ this.buddy.pause();
169
+ }
170
+ }
171
+ /**
172
+ * Resume the stream processing
173
+ */
174
+ resume() {
175
+ this.paused = false;
176
+ if (this.buddy) {
177
+ this.buddy.resume();
178
+ }
179
+ }
180
+ /**
181
+ * Abort the stream processing
182
+ */
183
+ abort() {
184
+ this.aborted = true;
185
+ if (this.buddy) {
186
+ this.buddy.abort();
187
+ }
188
+ if (this.reader) {
189
+ this.reader.cancel().catch(() => {
190
+ });
191
+ }
192
+ }
193
+ /**
194
+ * Get current statistics
195
+ */
196
+ stats() {
197
+ return this.buddy ? this.buddy.stats() : null;
198
+ }
199
+ /**
200
+ * Get current record count
201
+ */
202
+ getRecordCount() {
203
+ return this.recordCount;
204
+ }
205
+ /**
206
+ * Check if processing is paused
207
+ */
208
+ isPaused() {
209
+ return this.paused;
210
+ }
211
+ /**
212
+ * Check if processing is aborted
213
+ */
214
+ isAborted() {
215
+ return this.aborted;
216
+ }
217
+ }
218
+ async function processStream(input, options) {
219
+ const controller = new BrowserStreamController(options);
220
+ await controller.process(input);
221
+ }
222
+ export {
223
+ BrowserStreamController,
224
+ processStream
225
+ };
226
+ //# sourceMappingURL=browser-stream-controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/browser-stream-controller.ts"],"sourcesContent":["/**\r\n * Browser-specific StreamController implementation\r\n * \r\n * Provides high-level streaming API for browser environments with ReadableStream support.\r\n */\r\n\r\nimport { ConvertBuddy } from \"./index.js\";\r\nimport type { Stats } from \"./index.js\";\r\nimport { StreamControllerOptions, createSplitter } from \"./stream-controller.js\";\r\n\r\nexport type BrowserStreamInput = ReadableStream<Uint8Array> | string | Blob | File;\r\n\r\n/**\r\n * BrowserStreamController - High-level streaming API for browser environments\r\n * \r\n * Features:\r\n * - Per-record callbacks with backpressure management\r\n * - Pause/resume/abort controls\r\n * - Progress tracking\r\n * - Automatic NDJSON/CSV/JSON/XML splitting and parsing\r\n * \r\n * @example\r\n * ```ts\r\n * const controller = new BrowserStreamController({\r\n * inputFormat: \"csv\",\r\n * outputFormat: \"ndjson\",\r\n * onRecord: async (record, index) => {\r\n * await processRecord(record);\r\n * },\r\n * onProgress: (stats, recordCount) => {\r\n * console.log(`Processed ${recordCount} records`);\r\n * }\r\n * });\r\n * \r\n * await controller.process(fetch('/data.csv').then(r => r.body!));\r\n * ```\r\n */\r\nexport class BrowserStreamController {\r\n private options: StreamControllerOptions;\r\n private buddy: ConvertBuddy | null = null;\r\n private reader: ReadableStreamDefaultReader<Uint8Array> | null = null;\r\n private aborted = false;\r\n private paused = false;\r\n private recordCount = 0;\r\n private splitter: any;\r\n\r\n constructor(options: StreamControllerOptions) {\r\n this.options = {\r\n outputFormat: \"ndjson\",\r\n progressBatchSize: 1000,\r\n autoPause: true,\r\n ...options,\r\n };\r\n\r\n // Create appropriate splitter for output format\r\n this.splitter = createSplitter(this.options.outputFormat!, this.options);\r\n }\r\n\r\n /**\r\n * Process a stream/URL/File/Blob and invoke callbacks for each record\r\n */\r\n async process(input: BrowserStreamInput): Promise<void> {\r\n try {\r\n // Convert input to ReadableStream\r\n const stream = await this.inputToStream(input);\r\n\r\n // Create ConvertBuddy instance\r\n this.buddy = await ConvertBuddy.create({\r\n ...this.options,\r\n profile: true, // Enable stats for progress tracking\r\n });\r\n\r\n // Get reader\r\n this.reader = stream.getReader();\r\n\r\n // Process stream\r\n await this.processStream();\r\n\r\n } finally {\r\n // Cleanup\r\n if (this.reader) {\r\n try {\r\n await this.reader.cancel();\r\n } catch (e) {\r\n // Ignore cancel errors\r\n }\r\n this.reader = null;\r\n }\r\n this.buddy = null;\r\n }\r\n }\r\n\r\n /**\r\n * Convert various input types to ReadableStream\r\n */\r\n private async inputToStream(input: BrowserStreamInput): Promise<ReadableStream<Uint8Array>> {\r\n if (typeof input === \"string\") {\r\n // URL\r\n if (input.startsWith(\"http://\") || input.startsWith(\"https://\")) {\r\n const response = await fetch(input);\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch ${input}: ${response.statusText}`);\r\n }\r\n if (!response.body) {\r\n throw new Error(\"Response body is null\");\r\n }\r\n return response.body;\r\n } else {\r\n // Raw string data\r\n const encoder = new TextEncoder();\r\n const bytes = encoder.encode(input);\r\n return new ReadableStream({\r\n start(controller) {\r\n controller.enqueue(bytes);\r\n controller.close();\r\n },\r\n });\r\n }\r\n } else if (typeof ReadableStream !== \"undefined\" && input instanceof ReadableStream) {\r\n return input;\r\n } else if ((typeof Blob !== \"undefined\" && input instanceof Blob) || \r\n (typeof File !== \"undefined\" && input instanceof File)) {\r\n return (input as Blob | File).stream() as ReadableStream<Uint8Array>;\r\n } else {\r\n throw new Error(\"Unsupported input type for BrowserStreamController\");\r\n }\r\n }\r\n\r\n /**\r\n * Process the stream chunk by chunk\r\n */\r\n private async processStream(): Promise<void> {\r\n if (!this.buddy || !this.reader) {\r\n throw new Error(\"Stream not initialized\");\r\n }\r\n\r\n try {\r\n while (true) {\r\n // Check if aborted\r\n if (this.aborted) {\r\n this.buddy.abort();\r\n break;\r\n }\r\n\r\n // Wait while paused\r\n while (this.paused && !this.aborted) {\r\n await new Promise((resolve) => setTimeout(resolve, 100));\r\n }\r\n\r\n // Read next chunk\r\n const { done, value } = await this.reader!.read();\r\n\r\n if (done) {\r\n // Finish conversion and process final output\r\n const finalOutput = this.buddy.finish();\r\n if (finalOutput.length > 0) {\r\n await this.processOutput(finalOutput);\r\n }\r\n\r\n // Flush splitter\r\n const finalRecords = this.splitter.flush();\r\n for (const record of finalRecords) {\r\n await this.invokeRecordCallback(record);\r\n }\r\n\r\n break;\r\n }\r\n\r\n // Push chunk to ConvertBuddy with record parsing\r\n const needsRecords = !!this.options.onRecord;\r\n const result = this.buddy.pushWithRecords(value, needsRecords);\r\n\r\n // Process output if any\r\n if (typeof result === 'object' && 'output' in result) {\r\n // Dual output with records\r\n if (result.output.length > 0) {\r\n await this.processOutput(result.output, result.records);\r\n }\r\n } else if (result.length > 0) {\r\n // Fallback: just bytes\r\n await this.processOutput(result);\r\n }\r\n }\r\n } catch (error) {\r\n if (this.aborted) {\r\n // Ignore errors after abort\r\n return;\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Process output bytes and split into records\r\n */\r\n private async processOutput(output: Uint8Array, wasmRecords?: any[]): Promise<void> {\r\n // Call onData callback with raw bytes if provided\r\n if (this.options.onData) {\r\n this.options.onData(output);\r\n }\r\n\r\n // Use WASM-parsed records if available, otherwise use TypeScript splitter\r\n const records = wasmRecords && wasmRecords.length > 0 ? wasmRecords : this.splitter.push(output);\r\n\r\n // Process each record\r\n for (const record of records) {\r\n if (this.aborted) break;\r\n\r\n await this.invokeRecordCallback(record);\r\n\r\n // Check progress callback\r\n if (\r\n this.options.onStreamProgress &&\r\n this.recordCount % (this.options.progressBatchSize || 1000) === 0\r\n ) {\r\n const stats = this.buddy!.stats();\r\n this.options.onStreamProgress(stats, this.recordCount);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Invoke the onRecord callback with proper backpressure handling\r\n */\r\n private async invokeRecordCallback(record: any): Promise<void> {\r\n if (!this.options.onRecord) {\r\n this.recordCount++;\r\n return;\r\n }\r\n\r\n try {\r\n // Call the callback\r\n const result = this.options.onRecord(record, this.recordCount);\r\n\r\n // If autoPause is enabled and callback returns a Promise, wait for it\r\n if (this.options.autoPause && result instanceof Promise) {\r\n const shouldContinue = await result;\r\n \r\n // If callback returns false, pause\r\n if (shouldContinue === false) {\r\n this.pause();\r\n }\r\n } else if (result === false) {\r\n // If callback returns false synchronously, pause\r\n this.pause();\r\n }\r\n\r\n this.recordCount++;\r\n } catch (error) {\r\n console.error(\"[BrowserStreamController] Error in onRecord callback:\", error);\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Pause the stream processing\r\n */\r\n pause(): void {\r\n this.paused = true;\r\n if (this.buddy) {\r\n this.buddy.pause();\r\n }\r\n }\r\n\r\n /**\r\n * Resume the stream processing\r\n */\r\n resume(): void {\r\n this.paused = false;\r\n if (this.buddy) {\r\n this.buddy.resume();\r\n }\r\n }\r\n\r\n /**\r\n * Abort the stream processing\r\n */\r\n abort(): void {\r\n this.aborted = true;\r\n if (this.buddy) {\r\n this.buddy.abort();\r\n }\r\n if (this.reader) {\r\n this.reader.cancel().catch(() => {\r\n // Ignore cancel errors\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Get current statistics\r\n */\r\n stats(): Stats | null {\r\n return this.buddy ? this.buddy.stats() : null;\r\n }\r\n\r\n /**\r\n * Get current record count\r\n */\r\n getRecordCount(): number {\r\n return this.recordCount;\r\n }\r\n\r\n /**\r\n * Check if processing is paused\r\n */\r\n isPaused(): boolean {\r\n return this.paused;\r\n }\r\n\r\n /**\r\n * Check if processing is aborted\r\n */\r\n isAborted(): boolean {\r\n return this.aborted;\r\n }\r\n}\r\n\r\n/**\r\n * Convenience function to process a stream with a simple callback\r\n * \r\n * @example\r\n * ```ts\r\n * await processStream('/data.csv', {\r\n * inputFormat: 'csv',\r\n * outputFormat: 'ndjson',\r\n * onRecord: (record) => console.log(record),\r\n * });\r\n * ```\r\n */\r\nexport async function processStream(\r\n input: BrowserStreamInput,\r\n options: StreamControllerOptions\r\n): Promise<void> {\r\n const controller = new BrowserStreamController(options);\r\n await controller.process(input);\r\n}\r\n"],"mappings":"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","names":[]}
package/dist/browser.d.ts CHANGED
@@ -1,209 +1,30 @@
1
- import { ConvertBuddyOptions, ConvertOptions, Format } from './browser-core.js';
2
- export { Coerce, ConvertBuddy, ConvertBuddyTransformStream, Converter, CsvConfig, CsvDetection, DetectInput, DetectOptions, FieldMap, JsonDetection, NdjsonDetection, ProgressCallback, Stats, StructureDetection, TransformConfig, TransformMode, XmlConfig, XmlDetection, autoDetectConfig, convertAny, convertAnyToString, detectCsvFieldsAndDelimiter, detectFormat, detectStructure, detectXmlElements, getExtension, getFileTypeConfig, getMimeType, getSuggestedFilename } from './browser-core.js';
1
+ import { C as ConvertOptions, F as Format } from './index-BpUN6Tdz.js';
2
+ export { G as CSVSplitter, f as Coerce, j as ConvertBuddy, a as ConvertBuddyOptions, p as ConvertBuddyTransformStream, j as Converter, d as CsvConfig, b as CsvDetection, D as DetectInput, c as DetectOptions, g as FieldMap, H as JSONSplitter, J as JsonDetection, E as NDJSONSplitter, N as NdjsonDetection, B as ParsedRecord, P as ProgressCallback, i as Stats, A as StreamControllerOptions, S as StructureDetection, h as TransformConfig, T as TransformMode, I as XMLSplitter, e as XmlConfig, X as XmlDetection, o as autoDetectConfig, q as convertAny, r as convertAnyToString, K as createSplitter, m as detectCsvFieldsAndDelimiter, k as detectFormat, l as detectStructure, n as detectXmlElements, t as getExtension, s as getMimeType, x as getOptimalThreadCount, u as getSuggestedFilename, y as getThreadingInfo, w as isWasmThreadingSupported } from './index-BpUN6Tdz.js';
3
+ export { BrowserStreamController, BrowserStreamInput, processStream } from './browser-stream-controller.js';
3
4
 
4
5
  /**
5
- * Browser-only entry point for convert-buddy-js
6
- * This module is designed to work in any browser environment, including StackBlitz
7
- * WITHOUT requiring WebContainers or special worker thread support.
8
- *
9
- * Key differences from the main entry point:
10
- * - No Node.js code paths (no worker_threads, no fs, no path)
11
- * - Browser-optimized WASM loading
12
- * - Web Worker functionality is optional and gracefully degrades
6
+ * Browser entry point for convert-buddy-js
7
+ * Re-exports the main API but optimized for browser environments
13
8
  */
14
9
 
15
- type BrowserConvertOptions = ConvertBuddyOptions & {};
16
10
  /**
17
- * Ultra-simple convert function for browser.
18
- * Auto-detects input type (File, URL, string, etc.) and format.
19
- *
20
- * @example
21
- * // From File
22
- * const file = fileInput.files[0];
23
- * const result = await convert(file, { outputFormat: "json" });
24
- *
25
- * @example
26
- * // From URL
27
- * const result = await convert("https://example.com/data.csv", { outputFormat: "json" });
28
- *
29
- * @example
30
- * // From string
31
- * const result = await convert(csvString, { outputFormat: "json" });
32
- */
33
- declare function convert(input: string | Uint8Array | File | Blob | ReadableStream<Uint8Array>, opts: ConvertOptions): Promise<Uint8Array>;
34
- /**
35
- * Ultra-simple convert function that returns a string.
36
- *
37
- * @example
38
- * const json = await convertToString(file, { outputFormat: "json" });
39
- * console.log(JSON.parse(json));
11
+ * Browser-optimized convert function for strings
40
12
  */
41
13
  declare function convertToString(input: string | Uint8Array | File | Blob | ReadableStream<Uint8Array>, opts: ConvertOptions): Promise<string>;
42
14
  /**
43
- * Convert a browser File or Blob object to a string.
44
- * Handles streaming internally using FileReader and web streams.
45
- *
46
- * @example
47
- * // From file input
48
- * const fileInput = document.querySelector('input[type="file"]');
49
- * const file = fileInput.files[0];
50
- * const result = await convertFileToString(file, {
51
- * inputFormat: "csv",
52
- * outputFormat: "json"
53
- * });
54
- *
55
- * @example
56
- * // With auto-detection
57
- * const result = await convertFileToString(file, {
58
- * inputFormat: "auto",
59
- * outputFormat: "ndjson"
60
- * });
61
- */
62
- declare function convertFileToString(file: File | Blob, opts?: BrowserConvertOptions): Promise<string>;
63
- /**
64
- * Convert a browser File or Blob object to a Uint8Array.
65
- * Handles streaming internally using FileReader and web streams.
66
- *
67
- * @example
68
- * const file = fileInput.files[0];
69
- * const result = await convertFile(file, {
70
- * inputFormat: "csv",
71
- * outputFormat: "json",
72
- * onProgress: (stats) => {
73
- * console.log(`Progress: ${stats.bytesIn} bytes processed`);
74
- * }
75
- * });
76
- */
77
- declare function convertFile(file: File | Blob, opts?: BrowserConvertOptions): Promise<Uint8Array>;
78
- /**
79
- * Convert a browser File or Blob and download the result as a file.
80
- *
81
- * @example
82
- * const fileInput = document.querySelector('input[type="file"]');
83
- * const file = fileInput.files[0];
84
- * await convertFileToFile(file, "output.json", {
85
- * inputFormat: "csv",
86
- * outputFormat: "json"
87
- * });
88
- */
89
- declare function convertFileToFile(inputFile: File | Blob, outputFilename: string, opts?: BrowserConvertOptions): Promise<void>;
90
- /**
91
- * Create a ReadableStream that converts data on-the-fly from a File or Blob.
92
- * Useful for piping through other stream processors.
93
- *
94
- * @example
95
- * const file = fileInput.files[0];
96
- * const stream = convertFileStream(file, {
97
- * inputFormat: "csv",
98
- * outputFormat: "ndjson"
99
- * });
100
- *
101
- * const reader = stream.getReader();
102
- * while (true) {
103
- * const { done, value } = await reader.read();
104
- * if (done) break;
105
- * // Process each chunk as it's converted
106
- * console.log(new TextDecoder().decode(value));
107
- * }
15
+ * Browser-optimized convert function for bytes
108
16
  */
109
- declare function convertFileStream(file: File | Blob, opts?: BrowserConvertOptions): Promise<ReadableStream<Uint8Array>>;
110
- /**
111
- * Auto-detect format and create a ReadableStream for conversion.
112
- * This is a convenience helper that combines format detection with streaming conversion.
113
- *
114
- * @example
115
- * const file = fileInput.files[0];
116
- * const stream = await autoConvertStream(file, { outputFormat: "json" });
117
- *
118
- * // Pipe to response
119
- * return new Response(stream);
120
- */
121
- declare function autoConvertStream(file: File | Blob, opts: Omit<BrowserConvertOptions, "inputFormat"> & {
122
- outputFormat: Format;
123
- }): Promise<ReadableStream<Uint8Array>>;
124
- /**
125
- * Stream a file conversion directly to a writable destination.
126
- * This is useful for streaming large conversions to disk using File System Access API
127
- * or to other writable streams.
128
- *
129
- * @example
130
- * // Using File System Access API
131
- * const fileInput = document.querySelector('input[type="file"]');
132
- * const file = fileInput.files[0];
133
- *
134
- * const fileHandle = await window.showSaveFilePicker({
135
- * suggestedName: "output.json",
136
- * types: [{ description: "JSON", accept: { "application/json": [".json"] } }]
137
- * });
138
- * const writable = await fileHandle.createWritable();
139
- *
140
- * await convertStreamToWritable(file, writable, {
141
- * inputFormat: "csv",
142
- * outputFormat: "json",
143
- * onProgress: (stats) => console.log(`${stats.bytesIn} bytes processed`)
144
- * });
145
- */
146
- declare function convertStreamToWritable(file: File | Blob, writable: WritableStream<Uint8Array> | FileSystemWritableFileStream, opts?: BrowserConvertOptions): Promise<void>;
147
- /**
148
- * Check if File System Access API is supported in the current browser.
149
- * Use this to determine if you can use File System Access API features.
150
- *
151
- * @example
152
- * if (isFileSystemAccessSupported()) {
153
- * // Use File System Access API
154
- * const handle = await window.showSaveFilePicker();
155
- * } else {
156
- * // Fall back to download link
157
- * await convertFileToFile(file, "output.json", opts);
158
- * }
159
- */
160
- declare function isFileSystemAccessSupported(): boolean;
161
- /**
162
- * Convert a file and save it using File System Access API with a user-selected location.
163
- * This provides a better UX than automatic downloads by letting users choose where to save.
164
- * Falls back to regular download if File System Access API is not supported.
165
- *
166
- * @example
167
- * const file = fileInput.files[0];
168
- * await convertAndSave(file, {
169
- * inputFormat: "csv",
170
- * outputFormat: "json",
171
- * suggestedName: "output.json"
172
- * });
173
- */
174
- declare function convertAndSave(file: File | Blob, opts?: BrowserConvertOptions & {
175
- suggestedName?: string;
176
- }): Promise<void>;
17
+ declare function convert(input: string | Uint8Array | File | Blob | ReadableStream<Uint8Array>, opts: ConvertOptions): Promise<Uint8Array>;
177
18
  /**
178
- * Stream a File/Blob conversion in a Web Worker with progress updates.
179
- *
180
- * NOTE: This function requires Web Worker support and may not work in all environments
181
- * (e.g., StackBlitz without WebContainers). For maximum compatibility, use the
182
- * non-worker versions: convertFile(), convertFileStream(), etc.
183
- *
184
- * @param file File or Blob to convert
185
- * @param opts Convert options (inputFormat, outputFormat, etc)
186
- * @param onProgress Callback for progress updates
187
- * @returns Promise<Uint8Array> with the converted result
19
+ * Convert a browser File or Blob and trigger download of the result
188
20
  */
189
- declare function streamProcessFileInWorker(file: File | Blob, opts?: BrowserConvertOptions, onProgress?: (progress: {
190
- bytesRead: number;
191
- bytesWritten: number;
192
- percentComplete: number;
193
- recordsProcessed: number;
194
- }) => void): Promise<Uint8Array>;
21
+ declare function convertFileToFile(inputFile: File | Blob, outputFilename: string, opts: ConvertOptions): Promise<void>;
195
22
  /**
196
- * Stream a File/Blob conversion in a Web Worker and pipe output to a Writable.
197
- * This is useful for saving directly to disk using File System Access API.
198
- *
199
- * NOTE: This function requires Web Worker support and may not work in all environments.
200
- * For maximum compatibility, use convertStreamToWritable() instead.
23
+ * Get file type configuration for browser file pickers
201
24
  */
202
- declare function streamProcessFileInWorkerToWritable(file: File | Blob, writable: WritableStream<Uint8Array> | FileSystemWritableFileStream, opts?: BrowserConvertOptions, onProgress?: (progress: {
203
- bytesRead: number;
204
- bytesWritten: number;
205
- percentComplete: number;
206
- recordsProcessed: number;
207
- }) => void): Promise<void>;
25
+ declare function getFileTypeConfig(format: Format): Array<{
26
+ description: string;
27
+ accept: Record<string, string[]>;
28
+ }>;
208
29
 
209
- export { type BrowserConvertOptions, ConvertBuddyOptions, ConvertOptions, Format, autoConvertStream, convert, convertAndSave, convertFile, convertFileStream, convertFileToFile, convertFileToString, convertStreamToWritable, convertToString, isFileSystemAccessSupported, streamProcessFileInWorker, streamProcessFileInWorkerToWritable };
30
+ export { ConvertOptions, Format, convert, convertFileToFile, convertToString, getFileTypeConfig };