@mog-sdk/node 0.1.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.
package/README.md ADDED
@@ -0,0 +1,277 @@
1
+ # @mog/sdk
2
+
3
+ Shortcut Data OS SDK — headless spreadsheet engine for Node.js. Runs the real kernel + Rust compute-core without a browser.
4
+
5
+ ## Quick Start
6
+
7
+ ```typescript
8
+ import { createWorkbook } from '@mog/sdk';
9
+
10
+ const wb = await createWorkbook();
11
+ const ws = wb.activeSheet;
12
+
13
+ await ws.setCell('A1', 42);
14
+ await ws.setCell('A2', 58);
15
+ await ws.setCell('A3', '=A1+A2');
16
+
17
+ const val = await ws.getValue('A3'); // 100
18
+ await wb.dispose();
19
+ ```
20
+
21
+ Three lines to a running spreadsheet engine. No addon injection, no context threading, no active-sheet callbacks.
22
+
23
+ ## Install
24
+
25
+ ```bash
26
+ # Monorepo — already available as workspace dependency
27
+ pnpm add @mog/sdk
28
+
29
+ # The native Rust addon must be built first
30
+ cd compute-core-napi && pnpm build
31
+ ```
32
+
33
+ ## API Reference
34
+
35
+ ### Creating Workbooks
36
+
37
+ ```typescript
38
+ // Zero-arg: blank workbook, auto-detects platform
39
+ const wb = await createWorkbook();
40
+
41
+ // With options: import XLSX
42
+ const wb = await createWorkbook({
43
+ source: { type: 'bytes', data: new Uint8Array(buffer) }
44
+ });
45
+
46
+ // Power-user: pre-existing kernel context (browser app path)
47
+ const wb = await createWorkbook({ ctx, eventBus });
48
+ ```
49
+
50
+ ### Reading Data
51
+
52
+ ```typescript
53
+ const ws = wb.activeSheet;
54
+
55
+ // Single cell value (computed)
56
+ const val = await ws.getValue('A1'); // CellValue | null
57
+ const val2 = await ws.getValue(0, 0); // numeric addressing
58
+
59
+ // Full cell data (value + formula + format)
60
+ const cell = await ws.getCell('A1');
61
+
62
+ // All data in used range as 2D array
63
+ const data = await ws.getData(); // CellValue[][]
64
+
65
+ // Range read
66
+ const range = await ws.getRange('A1:C10'); // CellData[][]
67
+
68
+ // LLM-friendly presentation
69
+ await ws.describe('A3'); // "100(=A1+A2)"
70
+ await ws.describeRange('A1:B3'); // Tabular text
71
+ await ws.summarize(); // Full sheet overview
72
+ ```
73
+
74
+ ### Writing Data
75
+
76
+ ```typescript
77
+ // Single cell (A1 or numeric)
78
+ await ws.setCell('A1', 42);
79
+ await ws.setCell('A2', '=A1*2');
80
+ await ws.setCell(2, 0, 'text');
81
+
82
+ // Bulk write
83
+ await ws.setRange('A1', [
84
+ ['Name', 'Score'],
85
+ ['Alice', 92],
86
+ ['Bob', 85],
87
+ ]);
88
+ ```
89
+
90
+ ### Working with Sheets
91
+
92
+ ```typescript
93
+ const count = await wb.getSheetCount();
94
+ const names = await wb.getSheetNames();
95
+ const ws2 = await wb.sheets.add('Sheet2');
96
+
97
+ // Get or create (idempotent)
98
+ const { sheet, created } = await wb.getOrCreateSheet('Data');
99
+ ```
100
+
101
+ ### Tables and Structured Data
102
+
103
+ ```typescript
104
+ // One-liner table creation
105
+ await ws.createTable('SalesData', {
106
+ headers: ['Product', 'Q1', 'Q2'],
107
+ data: [
108
+ ['Widget', 100, 150],
109
+ ['Gadget', 200, 180],
110
+ ],
111
+ });
112
+ ```
113
+
114
+ ### Serialization
115
+
116
+ ```typescript
117
+ // CSV (RFC 4180, formula injection protected)
118
+ const csv = await ws.toCSV();
119
+ const tsvData = await ws.toCSV({ separator: '\t' });
120
+
121
+ // JSON (array of objects, first row as headers)
122
+ const json = await ws.toJSON();
123
+ // [{ Product: 'Widget', Q1: 100, Q2: 150 }, ...]
124
+
125
+ const jsonNoHeader = await ws.toJSON({ headerRow: 'none' });
126
+ // [{ A: 'Product', B: 'Q1', C: 'Q2' }, ...]
127
+ ```
128
+
129
+ ### File I/O (SDK-only, Node.js)
130
+
131
+ ```typescript
132
+ import { save } from '@mog/sdk';
133
+
134
+ // Export workbook to file (format by extension)
135
+ await save(wb, 'output.xlsx');
136
+ ```
137
+
138
+ ### Formulas
139
+
140
+ Each `setCell` mutation triggers automatic recalc in Rust. Formulas are evaluated by the time `setCell` returns — no manual `calculate()` needed.
141
+
142
+ ```typescript
143
+ await ws.setCell('A1', 10);
144
+ await ws.setCell('A2', 20);
145
+ await ws.setCell('A3', '=SUM(A1:A2)');
146
+
147
+ const val = await ws.getValue('A3'); // 30
148
+
149
+ // Search by formula
150
+ const cells = await ws.findByFormula(/SUM/); // ['A3']
151
+ const formula = await ws.getFormula('A3'); // '=SUM(A1:A2)'
152
+ ```
153
+
154
+ ### Formatting & Structure
155
+
156
+ ```typescript
157
+ await ws.setFormat('A1', { bold: true, fontColor: '#FF0000' });
158
+ await ws.setRangeFormat('A1:B3', { italic: true });
159
+
160
+ await ws.structure.insertRows(2, 3);
161
+ await ws.structure.deleteColumns(1, 1);
162
+ await ws.structure.mergeCells('A1:B1');
163
+ ```
164
+
165
+ ### Full Kernel API
166
+
167
+ The full kernel API is accessible — charts, tables, filters, validation, conditional formatting, pivots, and all 23 domain sub-APIs:
168
+
169
+ ```typescript
170
+ // Charts
171
+ await ws.charts.add({ type: 'bar', dataRange: 'A1:B5' });
172
+
173
+ // Conditional formatting
174
+ await ws.conditionalFormatting.add({ range: 'B2:B10', rule: { type: 'greaterThan', value: 100 } });
175
+
176
+ // Tables
177
+ await ws.tables.add('MyTable', 'A1:C5', { hasHeaders: true });
178
+
179
+ // Filters
180
+ await ws.filters.add('A1:C10');
181
+ ```
182
+
183
+ ### Low-Level Access
184
+
185
+ Drop to the raw compute bridge when the high-level API isn't enough:
186
+
187
+ ```typescript
188
+ const bridge = wb.context.computeBridge;
189
+ const sheetId = (await bridge.getAllSheetIds())[0];
190
+ const result = await bridge.setCell(sheetId, crypto.randomUUID(), 0, 0, '=1+1');
191
+ ```
192
+
193
+ ### Cleanup
194
+
195
+ **Always dispose when done** to avoid resource leaks:
196
+
197
+ ```typescript
198
+ await wb.dispose();
199
+ ```
200
+
201
+ ## Interactive Script Runner
202
+
203
+ ```bash
204
+ # From sdk/
205
+ node run.cjs # runs examples/hello.ts
206
+ node run.cjs examples/explore-api.ts # explore the full API
207
+ node run.cjs my-script.ts # run your own script
208
+ ```
209
+
210
+ Scripts export a default async function that receives a ready `Workbook`:
211
+
212
+ ```typescript
213
+ import type { Workbook } from '../src/index';
214
+
215
+ export default async function (wb: Workbook) {
216
+ const ws = wb.activeSheet;
217
+ await ws.setCell('A1', 'Hello from SDK!');
218
+ console.log(await ws.getValue('A1'));
219
+ }
220
+ ```
221
+
222
+ ## Backward Compatibility
223
+
224
+ `HeadlessEngine` and `createHeadlessEngine()` are preserved for existing consumers:
225
+
226
+ ```typescript
227
+ import { createHeadlessEngine } from '@mog/sdk';
228
+
229
+ const engine = await createHeadlessEngine({ computeAddon: addon });
230
+ const ws = engine.workbook.getActiveSheet();
231
+ ```
232
+
233
+ New code should use `createWorkbook()` directly.
234
+
235
+ ## Architecture
236
+
237
+ ```
238
+ createWorkbook()
239
+ └─ DocumentFactory.create({ environment: 'headless' })
240
+ └─ DocumentLifecycleSystem (XState machine)
241
+ ├─ createTransport() → auto-detects NAPI
242
+ │ ├─ LazyNapiTransport → compute-core-napi.node (Rust)
243
+ │ └─ CompositeTransport → xlsx-parser-napi.node (optional)
244
+ ├─ ComputeBridge (async cell ops, recalc)
245
+ └─ DocumentContext (kernel services, event bus)
246
+ └─ Workbook / Worksheet (unified API)
247
+ ```
248
+
249
+ The SDK boots the **same kernel** used by the browser app, with headless stubs for browser-only services (Canvas, DOM, IndexedDB). Transport goes through napi-rs directly to Rust — no WASM, no IPC, full native speed.
250
+
251
+ ## Prerequisites
252
+
253
+ - **Node.js** 20+
254
+ - **pnpm** 10+
255
+ - **Native addon** built: `cd compute-core-napi && pnpm build`
256
+
257
+ To check if the addon is current:
258
+
259
+ ```bash
260
+ node check-addon.cjs
261
+ ```
262
+
263
+ ## Example Scripts
264
+
265
+ | Script | What it does |
266
+ |--------|-------------|
267
+ | `examples/hello.ts` | Boot, write cells, read back |
268
+ | `examples/explore-api.ts` | Write dataset, read, search, summarize |
269
+ | `examples/getrange-test.ts` | Validate batch_get_cells: formulas, empty cells, identity |
270
+ | `examples/test-interactive.ts` | Interactive API exploration |
271
+ | `examples/test-usedrange.ts` | Used range detection |
272
+
273
+ ## Known Issues
274
+
275
+ **Console noise on boot**: `[SchemaValidationBridge]` errors during startup are harmless — the schema bridge tries to populate caches before the compute bridge is fully ready.
276
+
277
+ **IndexedDB error on dispose**: `indexedDB is not defined` appears on shutdown. The kernel tries to save to IndexedDB (browser API) which doesn't exist in Node.js. Caught and harmless.