# spreadsheet (adapter system)

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...


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

```js
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-csv` owns pure CSV** — parsing/writing RFC-4180 delimited **text**. This pack does NOT
  re-implement general CSV manipulation.
- **This pack owns the real binary `.xlsx`** format (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.


---
Source: shared/engines/adapters/domain/spreadsheet/README.md
Canonical: https://docs.leumas.tech/p/adapters/adapter-spreadsheet
