@dipanshuhandoo/excelio 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,584 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+
29
+ // src/index.js
30
+ var src_exports = {};
31
+ __export(src_exports, {
32
+ ExcelIoError: () => ExcelIoError,
33
+ default: () => src_default,
34
+ excelio: () => excelio
35
+ });
36
+ module.exports = __toCommonJS(src_exports);
37
+
38
+ // src/writer.js
39
+ var import_node_stream = require("node:stream");
40
+ var import_node_fs = require("node:fs");
41
+ var import_exceljs = __toESM(require("exceljs"), 1);
42
+
43
+ // src/errors.js
44
+ var ExcelIoError = class extends Error {
45
+ constructor(message, { code = "IO_ERROR", cause, details } = {}) {
46
+ super(message);
47
+ this.name = "ExcelIoError";
48
+ this.code = code;
49
+ if (cause !== void 0) this.cause = cause;
50
+ if (details !== void 0) this.details = details;
51
+ }
52
+ };
53
+
54
+ // src/columns.js
55
+ function resolveColumns(declaredColumns, data) {
56
+ if (Array.isArray(declaredColumns) && declaredColumns.length) {
57
+ return declaredColumns.map(normaliseColumn);
58
+ }
59
+ if (!data?.length) return [];
60
+ const firstRow = data[0] || {};
61
+ return Object.keys(firstRow).map((k) => normaliseColumn({ key: k }));
62
+ }
63
+ function normaliseColumn(c) {
64
+ if (!c || typeof c !== "object" || !c.key) {
65
+ throw new Error(`excelio: column entry must have a "key" property; got ${JSON.stringify(c)}`);
66
+ }
67
+ return {
68
+ key: String(c.key),
69
+ header: c.header ?? c.key,
70
+ type: c.type ?? null,
71
+ format: c.format ?? defaultFormatFor(c.type),
72
+ width: c.width ?? 15
73
+ };
74
+ }
75
+ function defaultFormatFor(type) {
76
+ switch (type) {
77
+ case "date":
78
+ return "yyyy-mm-dd hh:mm:ss";
79
+ case "number":
80
+ return null;
81
+ default:
82
+ return null;
83
+ }
84
+ }
85
+
86
+ // src/coerce.js
87
+ var ISO_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:?\d{2})?)?$/;
88
+ function valueForWrite(value, columnType) {
89
+ if (value === null || value === void 0) return null;
90
+ if (columnType === "date") {
91
+ if (value instanceof Date) return value;
92
+ if (typeof value === "number") return new Date(value);
93
+ if (typeof value === "string" && ISO_DATE_PATTERN.test(value)) {
94
+ const d = new Date(value);
95
+ return isNaN(d.getTime()) ? value : d;
96
+ }
97
+ return value;
98
+ }
99
+ if (columnType === "number" && typeof value === "string" && value !== "") {
100
+ const n = Number(value);
101
+ return Number.isFinite(n) ? n : value;
102
+ }
103
+ if (columnType === "boolean") {
104
+ if (typeof value === "boolean") return value;
105
+ if (value === "true" || value === 1) return true;
106
+ if (value === "false" || value === 0) return false;
107
+ }
108
+ return value;
109
+ }
110
+ function valueForRead(cell, { nullForBlank = true, trimStrings = true, dateFormat = "iso" } = {}) {
111
+ if (cell === void 0 || cell === null) return nullForBlank ? null : "";
112
+ const raw = cell && typeof cell === "object" && "value" in cell ? cell.value : cell;
113
+ if (raw === null || raw === void 0 || raw === "") return nullForBlank ? null : "";
114
+ if (raw instanceof Date) return formatDate(raw, dateFormat);
115
+ if (typeof raw === "object" && raw.text !== void 0 && raw.hyperlink !== void 0) {
116
+ return trimStrings ? String(raw.text).trim() : String(raw.text);
117
+ }
118
+ if (typeof raw === "object" && Array.isArray(raw.richText)) {
119
+ const joined = raw.richText.map((r) => r.text).join("");
120
+ return trimStrings ? joined.trim() : joined;
121
+ }
122
+ if (typeof raw === "object" && raw.formula !== void 0) {
123
+ return raw.result !== void 0 ? raw.result : null;
124
+ }
125
+ if (typeof raw === "object" && raw.error !== void 0) return null;
126
+ if (typeof raw === "string") return trimStrings ? raw.trim() : raw;
127
+ return raw;
128
+ }
129
+ function formatDate(d, fmt) {
130
+ switch (fmt) {
131
+ case "date":
132
+ return d;
133
+ case "epoch":
134
+ return d.getTime();
135
+ case "iso":
136
+ default:
137
+ return d.toISOString();
138
+ }
139
+ }
140
+
141
+ // src/writer.js
142
+ var DEFAULT_BATCH = 5e3;
143
+ var SHEET_NAME_MAX = 31;
144
+ async function writeSpec(spec, options = {}) {
145
+ validateSpec(spec);
146
+ const { to } = options;
147
+ if (to !== void 0 && spec.length > 1) {
148
+ throw new ExcelIoError(
149
+ `Multi-workbook output requires omitting "to" \u2014 caller writes each buffer itself.`,
150
+ { code: "INVALID_SPEC" }
151
+ );
152
+ }
153
+ if (to !== void 0) {
154
+ await writeOneWorkbook(spec[0], 0, to, options);
155
+ return to;
156
+ }
157
+ const buffers = [];
158
+ for (let wbIndex = 0; wbIndex < spec.length; wbIndex++) {
159
+ const buf = await writeOneWorkbookToBuffer(spec[wbIndex], wbIndex, options);
160
+ buffers.push(buf);
161
+ }
162
+ return buffers.length === 1 ? buffers[0] : buffers;
163
+ }
164
+ function writeSpecStream(spec, options = {}) {
165
+ validateSpec(spec);
166
+ const passthrough = new import_node_stream.PassThrough();
167
+ writeOneWorkbook(spec[0], 0, passthrough, options).catch((err) => passthrough.destroy(err));
168
+ return passthrough;
169
+ }
170
+ async function writeOneWorkbookToBuffer(workbookSpec, wbIndex, options) {
171
+ const chunks = [];
172
+ const collector = new import_node_stream.PassThrough();
173
+ collector.on("data", (chunk) => chunks.push(chunk));
174
+ await writeOneWorkbook(workbookSpec, wbIndex, collector, options);
175
+ return Buffer.concat(chunks);
176
+ }
177
+ async function writeOneWorkbook(workbookSpec, wbIndex, target, options) {
178
+ const { signal, onProgress, beforeWrite, batchSize = DEFAULT_BATCH, logger } = options;
179
+ const sink = resolveSink(target);
180
+ const wb = new import_exceljs.default.stream.xlsx.WorkbookWriter({
181
+ stream: sink.writable,
182
+ useStyles: true,
183
+ useSharedStrings: true
184
+ });
185
+ applyWorkbookProperties(wb, workbookSpec.properties);
186
+ const usedNames = /* @__PURE__ */ new Set();
187
+ const sheets = workbookSpec.sheets || [];
188
+ let totalRows = sheets.reduce((n, s) => n + (s.data?.length || 0), 0);
189
+ let rowsProcessed = 0;
190
+ for (let sIndex = 0; sIndex < sheets.length; sIndex++) {
191
+ if (signal?.aborted) throw new ExcelIoError("Aborted", { code: "ABORTED" });
192
+ const sheetSpec = sheets[sIndex];
193
+ const sheetName = sanitiseSheetName(sheetSpec.sheet || `Sheet ${sIndex + 1}`, usedNames, logger);
194
+ const wsOptions = {};
195
+ if (sheetSpec.styling?.freezeHeader) {
196
+ wsOptions.views = [{ state: "frozen", ySplit: 1 }];
197
+ }
198
+ const ws = wb.addWorksheet(sheetName, wsOptions);
199
+ const cols = resolveColumns(sheetSpec.columns, sheetSpec.data);
200
+ if (cols.length) {
201
+ ws.columns = cols.map((c) => ({
202
+ key: c.key,
203
+ header: c.header,
204
+ width: c.width,
205
+ style: c.format ? { numFmt: c.format } : void 0
206
+ }));
207
+ }
208
+ applyStylingPostColumns(ws, sheetSpec.styling, cols.length);
209
+ const data = sheetSpec.data || [];
210
+ for (let i = 0; i < data.length; i++) {
211
+ if (signal?.aborted) throw new ExcelIoError("Aborted", { code: "ABORTED" });
212
+ let row = data[i];
213
+ if (beforeWrite) {
214
+ row = beforeWrite(row, {
215
+ workbookIndex: wbIndex,
216
+ workbookName: workbookSpec.workbook,
217
+ sheetIndex: sIndex,
218
+ sheetName,
219
+ rowNumber: i + 2
220
+ // header is row 1
221
+ }) ?? row;
222
+ }
223
+ const rowValues = cols.length ? cols.reduce((acc, c) => {
224
+ acc[c.key] = valueForWrite(row[c.key], c.type);
225
+ return acc;
226
+ }, {}) : row;
227
+ ws.addRow(rowValues).commit();
228
+ rowsProcessed++;
229
+ if (onProgress && rowsProcessed % batchSize === 0) {
230
+ onProgress({ phase: "write", workbookIndex: wbIndex, sheetIndex: sIndex, rowsProcessed, totalRows });
231
+ }
232
+ }
233
+ ws.commit();
234
+ }
235
+ await wb.commit();
236
+ if (sink.cleanup) await sink.cleanup();
237
+ if (onProgress) {
238
+ onProgress({ phase: "write", workbookIndex: wbIndex, sheetIndex: sheets.length - 1, rowsProcessed, totalRows });
239
+ }
240
+ }
241
+ function resolveSink(target) {
242
+ if (typeof target === "string") {
243
+ const fileStream = (0, import_node_fs.createWriteStream)(target);
244
+ const closed = new Promise((resolve, reject) => {
245
+ fileStream.once("finish", resolve);
246
+ fileStream.once("error", reject);
247
+ });
248
+ return { writable: fileStream, cleanup: () => closed };
249
+ }
250
+ if (target && typeof target.write === "function") {
251
+ return { writable: target, cleanup: null };
252
+ }
253
+ throw new ExcelIoError(`Invalid write target \u2014 expected file path or writable stream`, { code: "INVALID_SPEC" });
254
+ }
255
+ function applyWorkbookProperties(wb, props) {
256
+ if (!props) return;
257
+ if (props.author) wb.creator = props.author;
258
+ if (props.created) wb.created = props.created instanceof Date ? props.created : new Date(props.created);
259
+ if (props.modified) wb.modified = props.modified instanceof Date ? props.modified : new Date(props.modified);
260
+ if (props.company) wb.company = props.company;
261
+ if (props.title) wb.title = props.title;
262
+ }
263
+ function applyStylingPostColumns(ws, styling, colCount) {
264
+ if (!styling) return;
265
+ if (styling.headerBold) {
266
+ ws.getRow(1).font = { bold: true };
267
+ }
268
+ if (styling.autoFilter && colCount > 0) {
269
+ ws.autoFilter = { from: { row: 1, column: 1 }, to: { row: 1, column: colCount } };
270
+ }
271
+ }
272
+ var FORBIDDEN_SHEET_CHARS = /[\\/?*[\]:]/g;
273
+ function sanitiseSheetName(raw, used, logger) {
274
+ let name = String(raw).replace(FORBIDDEN_SHEET_CHARS, "_");
275
+ if (name.length > SHEET_NAME_MAX) {
276
+ if (logger?.warn) logger.warn(`excelio: sheet name "${raw}" truncated to ${SHEET_NAME_MAX} chars`);
277
+ name = name.slice(0, SHEET_NAME_MAX);
278
+ }
279
+ if (!used.has(name)) {
280
+ used.add(name);
281
+ return name;
282
+ }
283
+ let i = 2;
284
+ while (true) {
285
+ const suffix = ` (${i})`;
286
+ const candidate = (name.length + suffix.length > SHEET_NAME_MAX ? name.slice(0, SHEET_NAME_MAX - suffix.length) : name) + suffix;
287
+ if (!used.has(candidate)) {
288
+ used.add(candidate);
289
+ return candidate;
290
+ }
291
+ i++;
292
+ }
293
+ }
294
+ function validateSpec(spec) {
295
+ if (!Array.isArray(spec) || spec.length === 0) {
296
+ throw new ExcelIoError("Spec must be a non-empty array of workbooks", { code: "INVALID_SPEC" });
297
+ }
298
+ for (const wb of spec) {
299
+ if (!wb || typeof wb !== "object") {
300
+ throw new ExcelIoError("Workbook entries must be objects", { code: "INVALID_SPEC" });
301
+ }
302
+ if (!Array.isArray(wb.sheets) || wb.sheets.length === 0) {
303
+ throw new ExcelIoError("Workbook must have at least one sheet", { code: "INVALID_SPEC" });
304
+ }
305
+ }
306
+ }
307
+
308
+ // src/reader.js
309
+ var import_node_buffer = require("node:buffer");
310
+ var import_exceljs2 = __toESM(require("exceljs"), 1);
311
+ var DEFAULT_BATCH2 = 5e3;
312
+ async function readSource(input, options = {}) {
313
+ const startedAt = Date.now();
314
+ const stats = { totalRows: 0, totalSheets: 0, durationMs: 0 };
315
+ const errors = [];
316
+ const {
317
+ headerRow = 1,
318
+ nullForBlank = true,
319
+ trimStrings = true,
320
+ dateFormat = "iso",
321
+ validateRow,
322
+ afterRead,
323
+ onRowError = "collect",
324
+ batchSize = DEFAULT_BATCH2,
325
+ onProgress,
326
+ signal
327
+ } = options;
328
+ const wb = new import_exceljs2.default.Workbook();
329
+ try {
330
+ if (import_node_buffer.Buffer.isBuffer(input)) {
331
+ await wb.xlsx.load(input);
332
+ } else if (input instanceof Uint8Array) {
333
+ await wb.xlsx.load(import_node_buffer.Buffer.from(input.buffer, input.byteOffset, input.byteLength));
334
+ } else if (typeof input === "string") {
335
+ await wb.xlsx.readFile(input);
336
+ } else if (input && typeof input.pipe === "function") {
337
+ await wb.xlsx.read(input);
338
+ } else {
339
+ throw new ExcelIoError("Invalid input \u2014 expected Buffer, file path, or readable stream", { code: "INVALID_SPEC" });
340
+ }
341
+ } catch (err) {
342
+ if (err instanceof ExcelIoError) throw err;
343
+ throw new ExcelIoError(`Failed to parse workbook: ${err.message}`, { code: "IO_ERROR", cause: err });
344
+ }
345
+ const sheets = [];
346
+ for (let s = 0; s < wb.worksheets.length; s++) {
347
+ if (signal?.aborted) throw new ExcelIoError("Aborted", { code: "ABORTED" });
348
+ const ws = wb.worksheets[s];
349
+ stats.totalSheets++;
350
+ const sheetMeta = { sheet: ws.name, columns: [], data: [] };
351
+ let columnKeys = null;
352
+ ws.eachRow({ includeEmpty: false }, (row, rowNumber) => {
353
+ if (rowNumber === headerRow) {
354
+ columnKeys = readHeaderRow(row);
355
+ sheetMeta.columns = columnKeys.filter(Boolean).map((k) => ({ key: k, header: k }));
356
+ return;
357
+ }
358
+ if (rowNumber < headerRow || !columnKeys) return;
359
+ if (signal?.aborted) throw new ExcelIoError("Aborted", { code: "ABORTED" });
360
+ const obj = {};
361
+ let isEmpty = true;
362
+ for (let i = 0; i < columnKeys.length; i++) {
363
+ const key = columnKeys[i];
364
+ if (!key) continue;
365
+ const cell = row.getCell(i + 1);
366
+ const v = valueForRead(cell, { nullForBlank, trimStrings, dateFormat });
367
+ if (v !== null && v !== "" && v !== void 0) isEmpty = false;
368
+ obj[key] = v;
369
+ }
370
+ if (isEmpty) return;
371
+ const ctx = {
372
+ workbookIndex: 0,
373
+ workbookName: void 0,
374
+ sheetIndex: s,
375
+ sheetName: ws.name,
376
+ rowNumber
377
+ };
378
+ let outRow = obj;
379
+ if (afterRead) {
380
+ try {
381
+ outRow = afterRead(obj, ctx) ?? obj;
382
+ } catch (err) {
383
+ const e = mkRowError(ctx, "TRANSFORM_ERROR", err.message);
384
+ if (onRowError === "fail") throw new ExcelIoError(e.message, { code: "ROW_VALIDATION", details: e });
385
+ errors.push(e);
386
+ return;
387
+ }
388
+ }
389
+ if (validateRow) {
390
+ const issue = validateRow(outRow, ctx);
391
+ if (issue) {
392
+ const e = mkRowError(ctx, issue.code || "VALIDATION_FAILED", issue.message, issue.column);
393
+ if (onRowError === "fail") throw new ExcelIoError(e.message, { code: "ROW_VALIDATION", details: e });
394
+ errors.push(e);
395
+ return;
396
+ }
397
+ }
398
+ sheetMeta.data.push(outRow);
399
+ stats.totalRows++;
400
+ if (onProgress && stats.totalRows % batchSize === 0) {
401
+ onProgress({ phase: "read", sheetName: ws.name, rowsProcessed: stats.totalRows });
402
+ }
403
+ });
404
+ sheets.push(sheetMeta);
405
+ }
406
+ stats.durationMs = Date.now() - startedAt;
407
+ return {
408
+ ok: errors.length === 0,
409
+ data: [{ workbook: void 0, sheets }],
410
+ errors,
411
+ stats
412
+ };
413
+ }
414
+ function readHeaderRow(row) {
415
+ const headers = [];
416
+ const values = row.values;
417
+ if (!Array.isArray(values)) return headers;
418
+ for (let i = 1; i < values.length; i++) {
419
+ const v = values[i];
420
+ headers.push(v == null ? null : String(v).trim());
421
+ }
422
+ return headers;
423
+ }
424
+ function mkRowError(ctx, code, message, column) {
425
+ return {
426
+ workbook: ctx.workbookIndex,
427
+ sheet: ctx.sheetName,
428
+ row: ctx.rowNumber,
429
+ column: column ?? null,
430
+ code,
431
+ message
432
+ };
433
+ }
434
+
435
+ // src/workerPool.js
436
+ var import_node_worker_threads = require("node:worker_threads");
437
+ var import_node_url = require("node:url");
438
+ var import_node_buffer2 = require("node:buffer");
439
+ var import_node_path = __toESM(require("node:path"), 1);
440
+ var import_node_fs2 = require("node:fs");
441
+ var DEFAULT_THRESHOLD = { rows: 5e4, bytes: 10 * 1024 * 1024 };
442
+ var moduleDirectory = typeof __dirname !== "undefined" ? __dirname : import_node_path.default.dirname((0, import_node_url.fileURLToPath)(void 0));
443
+ var workerExtension = true ? ".cjs" : ".js";
444
+ var WORKER_PATHS = {
445
+ write: import_node_path.default.join(moduleDirectory, "workers", `writer.worker${workerExtension}`),
446
+ read: import_node_path.default.join(moduleDirectory, "workers", `reader.worker${workerExtension}`)
447
+ };
448
+ async function maybeUseWorker(op, payload, options, inlineFn) {
449
+ const decision = decideMode(op, payload, options);
450
+ if (decision.mode === "inline") return inlineFn();
451
+ return runInWorker(op, payload, sanitiseOptions(options));
452
+ }
453
+ function decideMode(op, payload, options) {
454
+ const useWorker = options.useWorker ?? "auto";
455
+ if (op === "read" && payload && typeof payload.pipe === "function") {
456
+ return { mode: "inline", reason: "stream input" };
457
+ }
458
+ if (hasHook(options)) return { mode: "inline", reason: "hooks present" };
459
+ if (useWorker === false) return { mode: "inline", reason: "disabled" };
460
+ if (useWorker === true) return { mode: "worker", reason: "forced" };
461
+ const threshold = { ...DEFAULT_THRESHOLD, ...options.workerThreshold || {} };
462
+ if (op === "write") {
463
+ const totalRows = estimateRows(payload);
464
+ if (totalRows >= threshold.rows) return { mode: "worker", reason: `rows ${totalRows} \u2265 ${threshold.rows}` };
465
+ return { mode: "inline", reason: "below threshold" };
466
+ }
467
+ if (op === "read") {
468
+ const bytes = estimateBytes(payload);
469
+ if (bytes !== null && bytes >= threshold.bytes) return { mode: "worker", reason: `bytes ${bytes} \u2265 ${threshold.bytes}` };
470
+ return { mode: "inline", reason: "below threshold or unknown size" };
471
+ }
472
+ return { mode: "inline", reason: "unknown op" };
473
+ }
474
+ function hasHook(options) {
475
+ return Boolean(
476
+ options.validateRow || options.beforeWrite || options.afterRead || options.onProgress || options.logger || options.signal || // streams can't cross thread boundaries via postMessage either
477
+ options.to && typeof options.to !== "string"
478
+ );
479
+ }
480
+ function estimateRows(spec) {
481
+ if (!Array.isArray(spec)) return 0;
482
+ let n = 0;
483
+ for (const wb of spec) {
484
+ for (const sheet of wb?.sheets || []) {
485
+ n += sheet.data?.length || 0;
486
+ }
487
+ }
488
+ return n;
489
+ }
490
+ function estimateBytes(input) {
491
+ if (typeof input === "string") {
492
+ try {
493
+ return (0, import_node_fs2.statSync)(input).size;
494
+ } catch {
495
+ return null;
496
+ }
497
+ }
498
+ if (import_node_buffer2.Buffer.isBuffer(input)) return input.length;
499
+ return null;
500
+ }
501
+ function sanitiseOptions(options) {
502
+ const { validateRow, beforeWrite, afterRead, onProgress, signal, logger, to, ...rest } = options;
503
+ void validateRow;
504
+ void beforeWrite;
505
+ void afterRead;
506
+ void onProgress;
507
+ void signal;
508
+ void logger;
509
+ return { ...rest, ...typeof to === "string" ? { to } : {} };
510
+ }
511
+ function runInWorker(op, payload, options) {
512
+ return new Promise((resolve, reject) => {
513
+ const workerPath = WORKER_PATHS[op];
514
+ if (!workerPath) {
515
+ reject(new ExcelIoError(`No worker for op "${op}"`, { code: "WORKER_ERROR" }));
516
+ return;
517
+ }
518
+ let worker;
519
+ try {
520
+ worker = new import_node_worker_threads.Worker(workerPath, { workerData: { op, payload, options } });
521
+ } catch (err) {
522
+ reject(new ExcelIoError(err.message, { code: "WORKER_ERROR", cause: err }));
523
+ return;
524
+ }
525
+ let settled = false;
526
+ worker.once("message", (msg) => {
527
+ settled = true;
528
+ void worker.terminate().catch(() => {
529
+ });
530
+ if (msg.ok) {
531
+ const result = op === "write" && options.to === void 0 ? Array.isArray(msg.result) ? msg.result.map((value) => import_node_buffer2.Buffer.from(value)) : import_node_buffer2.Buffer.from(msg.result) : msg.result;
532
+ resolve(result);
533
+ } else reject(new ExcelIoError(msg.error?.message || "Worker error", {
534
+ code: msg.error?.code || "WORKER_ERROR",
535
+ cause: msg.error,
536
+ details: msg.error?.details
537
+ }));
538
+ });
539
+ worker.once("error", (err) => {
540
+ settled = true;
541
+ void worker.terminate().catch(() => {
542
+ });
543
+ reject(new ExcelIoError(err.message, { code: "WORKER_ERROR", cause: err }));
544
+ });
545
+ worker.once("exit", (code) => {
546
+ if (!settled) {
547
+ reject(new ExcelIoError(`Worker exited without a result (code ${code})`, { code: "WORKER_ERROR" }));
548
+ }
549
+ });
550
+ });
551
+ }
552
+
553
+ // src/index.js
554
+ var excelio = {
555
+ /**
556
+ * Write one or more workbooks. Returns a Buffer (or array of Buffers for
557
+ * multi-workbook specs) when `to` is omitted; writes to file/stream when `to`
558
+ * is provided and returns the target.
559
+ */
560
+ async write(spec, options = {}) {
561
+ return maybeUseWorker("write", spec, options, () => writeSpec(spec, options));
562
+ },
563
+ /**
564
+ * Returns a Readable stream for the first workbook. Synchronous return;
565
+ * errors during the underlying write surface via the stream's 'error' event.
566
+ */
567
+ writeStream(spec, options = {}) {
568
+ return writeSpecStream(spec, options);
569
+ },
570
+ /**
571
+ * Read a workbook from a Buffer, file path, or Readable stream. Returns a
572
+ * structured result with parsed data, per-row errors, and stats.
573
+ */
574
+ async read(input, options = {}) {
575
+ return maybeUseWorker("read", input, options, () => readSource(input, options));
576
+ }
577
+ };
578
+ var src_default = excelio;
579
+ // Annotate the CommonJS export names for ESM import in node:
580
+ 0 && (module.exports = {
581
+ ExcelIoError,
582
+ excelio
583
+ });
584
+ //# sourceMappingURL=index.cjs.map