JavaScript SDK
The witan npm package installs the Witan CLI and a Node.js SDK. The SDK opens a witan xlsx rpc subprocess, keeps a workbook session alive, and exposes the spreadsheet API through promise-based Workbook methods.
Use it when a Node.js or TypeScript application needs to read, write, search, recalculate, render, or lint Excel workbooks programmatically.
For the full method list, signatures, and return shapes, see the xlsx API.
Install
npm install witan
The package installs the SDK plus the platform-specific Witan binary. Node.js 22 or later is required.
Open a workbook
import { Workbook } from 'witan';
await using wb = await Workbook.open('report.xlsx');
const sheets = await wb.listSheets();
const tsv = await wb.readRangeTsv('Summary!A1:F20');
console.log(sheets.map(sheet => sheet.sheet));
console.log(tsv);
Workbook implements AsyncDisposable, so await using closes the subprocess automatically.
If your runtime does not use explicit resource management, close the workbook in finally:
import { Workbook } from 'witan';
const wb = await Workbook.open('report.xlsx');
try {
const tsv = await wb.readRangeTsv('Summary!A1:F20');
console.log(tsv);
} finally {
await wb.close();
}
Create and save
import { Workbook } from 'witan';
await using wb = await Workbook.open('model.xlsx', { create: true });
await wb.addSheet('Inputs');
const result = await wb.setCells([
{ address: 'Inputs!A1', value: 'Revenue' },
{ address: 'Inputs!B1', value: 1250000 },
{ address: 'Inputs!C1', value: null, formula: '=B1*1.1' },
]);
if (result.errors.length > 0) {
throw new Error(JSON.stringify(result.errors));
}
await wb.save();
Writes update the live workbook session and recalculate dependent formulas. Call save() when you want to write the workbook bytes back to disk.
Common workflows
Read and search
import { Workbook } from 'witan';
await using wb = await Workbook.open('report.xlsx');
const cell = await wb.readCell('Summary!B5');
const rows = await wb.readRangeTsv('Summary!A1:F20');
const matches = await wb.findCells(/revenue|ebitda/i, {
in: 'Summary!A:Z',
context: 2,
});
Use readRangeTsv, readRowTsv, and readColumnTsv when passing workbook data to a language model. TSV is usually smaller and easier to scan than nested JSON.
Edit and verify
await using wb = await Workbook.open('report.xlsx');
const before = await wb.previewStyles('Summary!A1:F20');
const result = await wb.setCells([
{ address: 'Summary!B5', value: null, formula: '=SUM(Revenue!B2:B13)' },
]);
const lint = await wb.lint({ rangeAddresses: ['Summary!A1:F20'] });
const after = await wb.previewStyles('Summary!A1:F20');
if (result.errors.length > 0 || lint.total > 0) {
throw new Error(JSON.stringify({ formulaErrors: result.errors, lint }));
}
await wb.save();
previewStyles() returns a data:image/...;base64,... URL for the rendered range. For command-line image files and pixel diffs, use witan xlsx render.
Trace and run sweeps
await using wb = await Workbook.open('model.xlsx');
const inputs = await wb.traceToInputs('Summary!F25');
const sweep = await wb.sweepInputs(
[{ address: 'Inputs!B5', values: [0.02, 0.04, 0.06] }],
['Summary!F25'],
{ mode: 'cartesian', includeStats: true }
);
console.log(sweep.tsv);
Author tables and charts
await using wb = await Workbook.open('dashboard.xlsx');
await wb.addListObject('Sheet1', {
name: 'SalesTable',
ref: 'A1:C4',
showTotalsRow: true,
columns: [
{ name: 'Region', totalsRowLabel: 'Total' },
{ name: 'Sales', totalsRowFunction: 'sum' },
{ name: 'DoubleSales', calculatedColumnFormula: '=B2*2' },
],
rows: [
[{ value: 'North' }, { value: 10 }, {}],
[{ value: 'South' }, { value: 20 }, {}],
],
});
await wb.addChart('Sheet1', {
name: 'Revenue',
position: { from: { cell: 'F2' }, to: { cell: 'N18' } },
groups: [
{
type: 'column',
series: [
{
name: { ref: 'Sheet1!B1' },
categories: 'Sheet1!A2:A4',
values: 'Sheet1!B2:B4',
},
],
},
],
title: { text: 'Revenue' },
legend: { position: 'right' },
});
await wb.previewStyles('Sheet1!F2:N18');
await wb.save();
API reference
The JavaScript SDK follows the same xlsx API as witan xlsx exec, with camelCase method names. See xlsx API for the full method list, signatures, and return shapes across JavaScript, Python, and xlsx exec.
Options
Pass options to Workbook.open:
const wb = await Workbook.open('report.xlsx', {
locale: 'en-US',
stateless: true,
apiKey: 'sk_...',
apiUrl: 'https://api.witanlabs.com',
requestTimeoutMs: 60_000,
});
Most configuration can also come from environment variables. See CLI Reference.
CLI from npm
The npm package also exposes the witan command:
npx witan xlsx calc report.xlsx
npx witan xlsx render report.xlsx -r "Summary!A1:F20"
npx witan xlsx lint report.xlsx
Errors
import {
Workbook,
WitanError,
WitanProcessError,
WitanRPCError,
WitanTimeoutError,
} from 'witan';
try {
await using wb = await Workbook.open('report.xlsx');
await wb.readRange('InvalidRange!!!');
} catch (err) {
if (err instanceof WitanTimeoutError) {
console.error('Request timed out:', err.message);
} else if (err instanceof WitanRPCError) {
console.error('RPC error:', err.code, err.message);
} else if (err instanceof WitanProcessError) {
console.error('Process error:', err.message);
} else if (err instanceof WitanError) {
console.error('Witan error:', err.message);
}
}
Next steps
- xlsx API — full method signatures and return shapes.
- Python SDK — use the same xlsx API from Python.
- CLI Scripting — run one-off workbook scripts with
witan xlsx exec. - Concepts — understand the shared workbook model underneath every SDK.