spreadsheet
Spreadsheet domain adapter — real XLSX (Excel) create/read/convert/append/style via exceljs. exceljs is lazy-guarded so the pack always loads; XLSX tools return { ok:false, unavailable:true } when...
spreadsheet (adapter system)
Real XLSX / Excel spreadsheet capability pack, backed by the exceljs npm dependency. This produces and parses the actual Office Open XML (.xlsx) binary — not delimited text. Workbooks travel as base64 so an entire binary workbook fits in one JSON POST body (in and out).
Dependency & lazy guard
exceljs is installed at the workspace root. It is lazy-guarded (imported on first use, never at module load): the pack always loads, and if exceljs cannot be imported, every XLSX-backed tool returns { ok:false, unavailable:true, error:'exceljs not installed' } instead of throwing. The pure helpers (row normalization, CSV split/join used by the bridge tools) keep working regardless.
Tools (adapters)
Each tool takes ONE args object (an HTTP POST body maps 1:1) and is async.
| tool | args | result | |
|---|---|---|---|
create | { sheets:[{name,rows}], options?:{headerStyle,autoWidth} } | { base64, bytes, sheets[] } | |
read | { base64 } | { sheetNames[], sheets:{ <name>: matrix } } | |
csvToXlsx | { csv, delimiter?, name?, options? } | { base64, bytes, sheet } | |
xlsxToCsv | { base64, sheet?, delimiter? } | { csv, rows, columns } | |
appendRows | { base64, rows, sheet? } | { base64, bytes, appended, totalRows } | |
addSheet | { base64, name, rows? } | { base64, bytes, sheetNames[] } | |
styleHeader | { base64, sheet?, options?:{bold,fill,color,freeze} } | { base64, bytes, styledCells } | |
autoWidth | { base64, sheet?, options?:{min,max,padding} } | { base64, bytes, widths[] } | |
toBase64 | `{ sheets? } \ | { base64 }` | { base64, bytes, sheets[] } |
getSheetNames | { base64 } | { sheetNames[], count } | |
info | { base64 } | { sheetCount, sheets[], creator, totalRows } |
Row shapes
Every tool that takes rows accepts two shapes:
- array-of-arrays —
[["name","age"],["Ada",36]]— written verbatim, you manage the header row. - array-of-objects —
[{name:"Ada",age:36}]— the union of keys becomes the header row and each
object is mapped to columns.
Cell values may be string / number / boolean / date. Dates read back as ISO strings; stored formula cells read back as { formula, result }.
Usage example
import pack from './index.js';
// Build a 2-sheet workbook with a styled, auto-fit header, then read it back.
const built = await pack.adapters.create({
sheets: [
{ name: 'People', rows: [{ name: 'Ada', role: 'Engineer' }, { name: 'Alan', role: 'Logician' }] },
{ name: 'Totals', rows: [['metric', 'value'], ['count', 2]] },
],
options: { headerStyle: true, autoWidth: true },
});
// built.base64 is a real .xlsx you can save or send.
const back = await pack.adapters.read({ base64: built.base64 });
// back.sheetNames -> ["People","Totals"]; back.sheets.People -> [["name","role"],["Ada","Engineer"],...]
// CSV <-> XLSX bridge:
const xlsx = await pack.adapters.csvToXlsx({ csv: 'a,b\n1,2\n3,4', options: { headerStyle: true } });
const csv = await pack.adapters.xlsxToCsv({ base64: xlsx.base64 });
DRY boundary
a-csvowns pure CSV — parsing/writing RFC-4180 delimited text. This pack does NOT
re-implement general CSV manipulation.
- This pack owns the real binary
.xlsxformat (workbooks, worksheets, cells, styling, column
widths). csvToXlsx / xlsxToCsv are the bridge between the two formats — they necessarily touch the xlsx binary (only exceljs can), so they belong here. The small CSV split/join inside is a local convenience for that bridge, not a competing CSV toolkit.
Out of scope: formula evaluation
exceljs stores formula strings (e.g. =SUM(A1:A3)) but does not evaluate them — it has no calc engine. This pack reads and writes formula text as-is and never computes formula results. For live formula calculation, use a real spreadsheet application or a dedicated calc engine.