npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mog-sdk/node

v0.4.0

Published

Headless spreadsheet engine for Node.js — full Excel-compatible compute, formulas, and file I/O

Readme

@mog-sdk/node

Shortcut Data OS SDK — headless spreadsheet engine for Node.js. Runs the real kernel + Rust compute-core without a browser.

Quick Start

import { createWorkbook } from '@mog-sdk/node';

const wb = await createWorkbook();
const ws = wb.activeSheet;

await ws.setCell('A1', 42);
await ws.setCell('A2', 58);
await ws.setCell('A3', '=A1+A2');

const val = await ws.getValue('A3'); // 100
await wb.dispose();

Three lines to a running spreadsheet engine. No addon injection, no context threading, no active-sheet callbacks.

Install

# Monorepo — already available as workspace dependency
pnpm add @mog-sdk/node

# The native Rust addon must be built first
cd compute-core-napi && pnpm build

API Reference

Creating Workbooks

// Blank workbook
const wb = await createWorkbook();

// From file path
const wb = await createWorkbook('data.xlsx');

// From XLSX buffer
const wb = await createWorkbook(readFileSync('data.xlsx'));

// With import options
const wb = await createWorkbook('data.xlsx', { valuesOnly: true });

// Options bag (when you need a custom document ID)
const wb = await createWorkbook({ xlsx: buffer, documentId: 'my-doc' });

// Power-user: pre-existing kernel context (browser app path)
const wb = await createWorkbook({ ctx, eventBus });

Reading Data

const ws = wb.activeSheet;

// Single cell value (computed)
const val = await ws.getValue('A1');        // CellValue | null
const val2 = await ws.getValue(0, 0);       // numeric addressing

// Full cell data (value + formula + format)
const cell = await ws.getCell('A1');

// All data in used range as 2D array
const data = await ws.getData();            // CellValue[][]

// Range read
const range = await ws.getRange('A1:C10');  // CellData[][]

// LLM-friendly presentation
await ws.describe('A3');                    // "100(=A1+A2)"
await ws.describeRange('A1:B3');            // Tabular text
await ws.summarize();                       // Full sheet overview

Writing Data

// Single cell (A1 or numeric)
await ws.setCell('A1', 42);
await ws.setCell('A2', '=A1*2');
await ws.setCell(2, 0, 'text');

// Bulk write
await ws.setRange('A1', [
  ['Name', 'Score'],
  ['Alice', 92],
  ['Bob', 85],
]);

Working with Sheets

const count = wb.sheetCount;
const names = wb.sheetNames;
const ws2 = await wb.sheets.add('Sheet2');

// Get or create (idempotent)
const { sheet, created } = await wb.getOrCreateSheet('Data');

Tables and Structured Data

// Create a table from existing data
await ws.setRange('A1', [['Product', 'Q1', 'Q2'], ['Widget', 100, 150], ['Gadget', 200, 180]]);
await ws.tables.add('SalesData', 'A1:C3', { hasHeaders: true });

Serialization

// CSV (RFC 4180, formula injection protected)
const csv = await ws.toCSV();
const tsvData = await ws.toCSV({ separator: '\t' });

// JSON (array of objects, first row as headers)
const json = await ws.toJSON();
// [{ Product: 'Widget', Q1: 100, Q2: 150 }, ...]

const jsonNoHeader = await ws.toJSON({ headerRow: 'none' });
// [{ A: 'Product', B: 'Q1', C: 'Q2' }, ...]

File I/O

// Save to file (returns buffer too)
await wb.save('output.xlsx');

// Save to buffer only
const buf = await wb.save();
const buf = await wb.toXlsx();

Formulas

Each setCell mutation triggers automatic recalc in Rust. Formulas are evaluated by the time setCell returns — no manual calculate() needed.

await ws.setCell('A1', 10);
await ws.setCell('A2', 20);
await ws.setCell('A3', '=SUM(A1:A2)');

const val = await ws.getValue('A3'); // 30

// Search by formula
const cells = await ws.findByFormula(/SUM/);  // ['A3']
const formula = await ws.getFormula('A3');     // '=SUM(A1:A2)'

Formatting & Structure

await ws.formats.set('A1', { bold: true, fontColor: '#FF0000' });
await ws.formats.setRange('A1:B3', { italic: true });

await ws.structure.insertRows(2, 3);
await ws.structure.deleteColumns(1, 1);
await ws.structure.merge('A1:B1');

Full Kernel API

The full kernel API is accessible — charts, tables, filters, validation, conditional formatting, pivots, and all 23 domain sub-APIs:

// Charts
await ws.charts.add({ type: 'bar', dataRange: 'A1:B5' });

// Conditional formatting
await ws.conditionalFormats.add({ range: 'B2:B10', rule: { type: 'greaterThan', value: 100 } });

// Tables
await ws.tables.add('MyTable', 'A1:C5', { hasHeaders: true });

// Filters
await ws.filters.add('A1:C10');

Low-Level Access

Drop to the raw compute bridge when the high-level API isn't enough:

const bridge = wb.context.computeBridge;
const sheetId = (await bridge.getAllSheetIds())[0];
const result = await bridge.setCell(sheetId, crypto.randomUUID(), 0, 0, '=1+1');

Cleanup

Always dispose when done to avoid resource leaks:

await wb.dispose();

Interactive Script Runner

# From sdk/
node run.cjs                          # runs examples/hello.ts
node run.cjs examples/explore-api.ts  # explore the full API
node run.cjs my-script.ts             # run your own script

Scripts export a default async function that receives a ready Workbook:

import type { Workbook } from '../src/index';

export default async function (wb: Workbook) {
  const ws = wb.activeSheet;
  await ws.setCell('A1', 'Hello from SDK!');
  console.log(await ws.getValue('A1'));
}

Backward Compatibility

HeadlessEngine and createHeadlessEngine() are preserved for existing consumers:

import { createHeadlessEngine } from '@mog-sdk/node';

const engine = await createHeadlessEngine({ computeAddon: addon });
const ws = engine.workbook.getActiveSheet();

New code should use createWorkbook() directly.

Architecture

createWorkbook()
  └─ DocumentFactory.create({ environment: 'headless' })
       └─ DocumentLifecycleSystem (XState machine)
            ├─ createTransport() → auto-detects NAPI
            │    ├─ LazyNapiTransport → compute-core-napi.node (Rust)
            │    └─ CompositeTransport → xlsx-parser-napi.node (optional)
            ├─ ComputeBridge (async cell ops, recalc)
            └─ DocumentContext (kernel services, event bus)
                 └─ Workbook / Worksheet (unified API)

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.

Prerequisites

  • Node.js 20+
  • pnpm 10+
  • Native addon built: cd compute-core-napi && pnpm build

To check if the addon is current:

node check-addon.cjs

Example Scripts

| Script | What it does | |--------|-------------| | examples/hello.ts | Boot, write cells, read back | | examples/explore-api.ts | Write dataset, read, search, summarize | | examples/getrange-test.ts | Validate batch_get_cells: formulas, empty cells, identity | | examples/test-interactive.ts | Interactive API exploration | | examples/test-usedrange.ts | Used range detection |

Known Issues

Console noise on boot: [SchemaValidationBridge] errors during startup are harmless — the schema bridge tries to populate caches before the compute bridge is fully ready.

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.