{
  "schema": "leumas.docs.page/1",
  "id": "pkg:@leumas/adapter-spreadsheet",
  "slug": "adapters/adapter-spreadsheet",
  "kind": "capabilities",
  "bucket": "package",
  "title": "spreadsheet (adapter system)",
  "name": "spreadsheet",
  "eyebrow": "adapter system",
  "chip": null,
  "summary": "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...",
  "keywords": [
    "adapter-spreadsheet",
    "excel",
    "xlsx",
    "append",
    "spreadsheet",
    "leumas adapter spreadsheet",
    "lazy-guarded",
    "unavailable"
  ],
  "audience": "both",
  "funnel": {
    "product": null,
    "cta": null
  },
  "body": "# spreadsheet (adapter system)\n\nReal **XLSX / Excel** spreadsheet capability pack, backed by the `exceljs` npm dependency. This produces\nand parses the actual Office Open XML (`.xlsx`) binary — not delimited text. Workbooks travel as\n**base64** so an entire binary workbook fits in one JSON POST body (in and out).\n\n## Dependency & lazy guard\n\n`exceljs` is installed at the workspace root. It is **lazy-guarded** (imported on first use, never at\nmodule load): the pack always loads, and if `exceljs` cannot be imported, every XLSX-backed tool returns\n`{ ok:false, unavailable:true, error:'exceljs not installed' }` instead of throwing. The pure helpers\n(row normalization, CSV split/join used by the bridge tools) keep working regardless.\n\n## Tools (`adapters`)\n\nEach tool takes ONE args object (an HTTP POST body maps 1:1) and is `async`.\n\n| tool | args | result |\n|------|------|--------|\n| `create` | `{ sheets:[{name,rows}], options?:{headerStyle,autoWidth} }` | `{ base64, bytes, sheets[] }` |\n| `read` | `{ base64 }` | `{ sheetNames[], sheets:{ <name>: matrix } }` |\n| `csvToXlsx` | `{ csv, delimiter?, name?, options? }` | `{ base64, bytes, sheet }` |\n| `xlsxToCsv` | `{ base64, sheet?, delimiter? }` | `{ csv, rows, columns }` |\n| `appendRows` | `{ base64, rows, sheet? }` | `{ base64, bytes, appended, totalRows }` |\n| `addSheet` | `{ base64, name, rows? }` | `{ base64, bytes, sheetNames[] }` |\n| `styleHeader` | `{ base64, sheet?, options?:{bold,fill,color,freeze} }` | `{ base64, bytes, styledCells }` |\n| `autoWidth` | `{ base64, sheet?, options?:{min,max,padding} }` | `{ base64, bytes, widths[] }` |\n| `toBase64` | `{ sheets? } \\| { base64 }` | `{ base64, bytes, sheets[] }` |\n| `getSheetNames` | `{ base64 }` | `{ sheetNames[], count }` |\n| `info` | `{ base64 }` | `{ sheetCount, sheets[], creator, totalRows }` |\n\n### Row shapes\n\nEvery tool that takes `rows` accepts two shapes:\n\n- **array-of-arrays** — `[[\"name\",\"age\"],[\"Ada\",36]]` — written verbatim, you manage the header row.\n- **array-of-objects** — `[{name:\"Ada\",age:36}]` — the union of keys becomes the header row and each\n  object is mapped to columns.\n\nCell values may be string / number / boolean / date. Dates read back as ISO strings; stored formula\ncells read back as `{ formula, result }`.\n\n## Usage example\n\n```js\nimport pack from './index.js';\n\n// Build a 2-sheet workbook with a styled, auto-fit header, then read it back.\nconst built = await pack.adapters.create({\n  sheets: [\n    { name: 'People', rows: [{ name: 'Ada', role: 'Engineer' }, { name: 'Alan', role: 'Logician' }] },\n    { name: 'Totals', rows: [['metric', 'value'], ['count', 2]] },\n  ],\n  options: { headerStyle: true, autoWidth: true },\n});\n// built.base64 is a real .xlsx you can save or send.\n\nconst back = await pack.adapters.read({ base64: built.base64 });\n// back.sheetNames -> [\"People\",\"Totals\"]; back.sheets.People -> [[\"name\",\"role\"],[\"Ada\",\"Engineer\"],...]\n\n// CSV <-> XLSX bridge:\nconst xlsx = await pack.adapters.csvToXlsx({ csv: 'a,b\\n1,2\\n3,4', options: { headerStyle: true } });\nconst csv  = await pack.adapters.xlsxToCsv({ base64: xlsx.base64 });\n```\n\n## DRY boundary\n\n- **`a-csv` owns pure CSV** — parsing/writing RFC-4180 delimited **text**. This pack does NOT\n  re-implement general CSV manipulation.\n- **This pack owns the real binary `.xlsx`** format (workbooks, worksheets, cells, styling, column\n  widths). `csvToXlsx` / `xlsxToCsv` are the **bridge between the two formats** — they necessarily touch\n  the xlsx binary (only `exceljs` can), so they belong here. The small CSV split/join inside is a local\n  convenience for that bridge, not a competing CSV toolkit.\n\n## Out of scope: formula evaluation\n\n`exceljs` **stores** formula strings (e.g. `=SUM(A1:A3)`) but does **not** evaluate them — it has no\ncalc engine. This pack reads and writes formula text as-is and never computes formula results. For live\nformula calculation, use a real spreadsheet application or a dedicated calc engine.\n",
  "source": {
    "path": "shared/engines/adapters/domain/spreadsheet/README.md",
    "blobSha": "",
    "commit": "",
    "committedAt": "",
    "provenance": "no-git",
    "bytes": 4233,
    "hash": "b536d909932ae2ea7cb8a8739c1b56602c5776a6"
  },
  "urls": {
    "html": "/p/adapters/adapter-spreadsheet",
    "json": "/docs/adapters/adapter-spreadsheet.json",
    "md": "/docs/adapters/adapter-spreadsheet.md"
  },
  "links": {
    "composes": [],
    "usedBy": [],
    "product": [],
    "howTo": [],
    "skills": []
  },
  "exports": null
}
