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

documonster

v0.20.2

Published

Zero-dependency TypeScript toolkit for Excel, Word, PDF, CSV, Markdown, XML & ZIP — one API across Node.js, Bun & browsers.

Readme

Documonster

Build Status   中文

The TypeScript ecosystem is heavily fragmented when it comes to document and data processing. To work with spreadsheets, documents, PDFs, and the many data and archive formats around them, developers often need to pull in a different package for each task — and then yet another set of packages to make them work in the browser, plus separate streaming wrappers on top. These libraries vary in API style, quality, and maintenance status, creating a tax on every project that needs more than one of them.

Documonster was built to fix this. One package, one consistent API, one codebase — working identically across Node.js, Bun, and browsers. Streaming is a first-class citizen in every module, not an afterthought bolted on through a third-party adapter. The goal is simple: install once, import what you need, and get the same reliable behavior everywhere — with maximum streaming performance out of the box.

About This Project

Documonster is a zero-dependency TypeScript toolkit for spreadsheets and documents:

  • AI-Friendly — Clean, consistent API designed for AI coding agents. Every module has comprehensive documentation and runnable examples for AI to learn from. An MCP server is available for AI clients that need to work on real files
  • Zero Runtime Dependencies — Pure TypeScript, no external packages
  • Nine Modules — Excel, Word, Formula, PDF, CSV, Markdown, XML, Archive, Stream
  • Cross-Platform — Node.js LTS + Current (22, 24, 26), Bun latest, Chrome 98+, Firefox 102+, Safari 15.4+
  • ESM only — Native ES Modules with full tree-shaking; CommonJS consumers require() it unchanged on Node >= 22.13

Modules

Documonster is organized into nine standalone modules. Each module has its own documentation and runnable examples.

Excel — XLSX/JSON Workbook Manager

Create, read, and modify Excel spreadsheets with full styling, formulas, images, and streaming support. Dates are treated as calendar values rather than instants: Cell.setDateParts / Cell.getDateParts speak timezone-free fields on every runtime, and Cell.setValue / Cell.getTemporal accept and return Temporal.PlainDate, PlainTime and PlainDateTime where the host has them — which also recovers the date/time/date-time distinction a Date cannot carry. See Dates: calendar values, not instants.

Word — DOCX Document Processor

Read, write, and manipulate DOCX files with a full builder, reader, and converter surface. Build documents with headings, tables, images, lists, headers/footers, drawing shapes, math, and charts. Read and modify existing files with text search/replace, format-aware queries, and bookmark/comment lookup. Convert to and from HTML and Markdown, bridge Excel workbooks into Word tables, and render Word straight to PDF. Advanced features include a template engine, form fields, OpenDoPE data binding, font embedding with subsetting, track-changes accept/reject, document diff/merge, streaming writer, password protection, Agile-encryption decryption, and digital-signature inspection.

Formula — Excel-Compatible Calculation Engine

448-function calculation engine with tokenizer, parser, dependency graph, dynamic-array spill, and LAMBDA/LET/MAP/REDUCE support. Recalculate workbooks with calculateFormulas() from documonster/excel/formula; tokenize and parse syntax with Formula from documonster/formula. There is no install step, and the engine stays out of bundles that only read/write XLSX.

PDF — Zero-Dependency PDF Engine

Full-featured PDF generation, reading, building, editing, and signing. Write PDFs with font embedding, AES-256 encryption, images, and Excel-to-PDF conversion. Build free-form PDFs with text, vector graphics, SVG paths, annotations, and form fields. Edit existing PDFs with overlays, form filling, page manipulation, and merging. Read any PDF with text, image, annotation, form field, bookmark, and metadata extraction. Verify and create digital signatures with PKCS#7/CMS.

CSV — RFC 4180 Parser/Formatter

High-performance CSV parsing and formatting with streaming, dynamic typing, data generation, and worker pool support.

Markdown — GFM Table Parser/Formatter

Parse and format GitHub Flavored Markdown tables with alignment round-trip and Workbook integration.

XML — SAX/DOM Parser, Query Engine, Writer

Streaming and buffered XML processing with query engine, namespace support, and dual-mode writing.

Archive — Create/Read/Edit Archives

ZIP and TAR archive creation, reading, editing, streaming, encryption, and compression utilities — plus encodePng, since a PNG is a DEFLATE stream with CRC-32-checked chunks and this is where both primitives live.

Stream — Cross-Platform Streaming

Node.js-compatible Readable/Writable/Transform/Duplex that works identically in Node.js and browsers.

Draw — Shared Drawing Engine

One structured display list, one walker, many backends. Build a DrawList and get SVG markup, RGBA pixels, or a PDF page from the same output — no renderer ever re-parses another's SVG. Includes text measurement and wrapping, so a producer can size its boxes before it builds a list.

Mermaid — Diagram Text to Drawings

Twenty-one Mermaid diagram types — flowchart, state, class, ER, sequence, Gantt, mindmap, git graph and more — rendered without a browser or headless Chrome. The module produces a display list and implements no backend, so SVG, pixels and PDF pages all come for free. Parse, layout and render are separate passes; stop after any of them.

MCP Server — Documonster for AI Clients

@documonster/mcp puts the toolkit behind the Model Context Protocol, so Claude Desktop, Claude Code, Cursor, and other MCP clients can read and write real spreadsheets, documents, PDFs, forms, and archives instead of guessing about them. It ships as a separate package, keeping the MCP SDK out of documonster and its zero-dependency promise intact.

Installation

npm install documonster
# or
pnpm add documonster
# or
bun add documonster

Each module is available as a standalone subpath export. All subpaths support browser, import (ESM), and require (CJS) conditions.

Quick Start

import { Workbook, Worksheet, Row } from "documonster/excel";

// Create
const workbook = Workbook.create();
const sheet = Workbook.addWorksheet(workbook, "Sheet1");
Worksheet.addRow(sheet, ["Name", "Age"]);
Worksheet.addRow(sheet, ["Alice", 30]);
await Workbook.writeFile(workbook, "output.xlsx");

// Read
const wb = Workbook.create();
await Workbook.readFile(wb, "output.xlsx");
const readSheet = Workbook.getWorksheet(wb, 1);
Worksheet.eachRow(readSheet, (_row, n) => console.log(n, Row.getValues(readSheet, n)));

// PDF — generate from data, no Workbook needed
import { Pdf } from "documonster/pdf";
const pdfBytes = await Pdf.create([
  ["Product", "Revenue"],
  ["Widget", 1000]
]);

// PDF — read text, images, and metadata from any PDF
const result = await Pdf.read(pdfBytes);
console.log(result.text); // extracted text
console.log(result.metadata); // title, author, etc.

// PDF — build free-form PDFs with text, shapes, SVG paths
const doc = new Pdf.Builder();
const page = doc.addPage();
page.drawText("Hello!", { x: 72, y: 770, fontSize: 24 });
page.drawSvgPath("M10 10 L90 10 L50 80 Z", { fill: { r: 1, g: 0, b: 0 } });
page.addAnnotation({ type: "Highlight", rect: [72, 765, 150, 785] });

// PDF — edit existing PDFs (overlay, merge, fill forms)
const editor = Pdf.Editor.load(existingPdf);
editor.getPage(0).drawText("Stamp", { x: 200, y: 400, fontSize: 36 });
editor.setFormField("name", "Jane");
editor.copyPagesFrom(otherPdf);

// CSV — parse and format
import { Csv } from "documonster/csv";
const rows = Csv.parse("name,age\nAlice,30", { headers: true });
const csv = Csv.format([{ name: "Bob", age: 25 }], { headers: true });

// XML — parse, query, write
import { Xml } from "documonster/xml";
const titles = Xml.queryAll(Xml.parse(xmlString).root, "book/title");

// ZIP — create and extract
import { Archive } from "documonster/archive";
const archive = await Archive.zip().add("hello.txt", "Hello!").bytes();

// Markdown — parse and format tables
import { Markdown } from "documonster/markdown";
const table = Markdown.parse("| A | B |\n|---|---|\n| 1 | 2 |");

// Word — create, read, and convert DOCX
import { Document, Io } from "documonster/word";
const wdoc = Document.create();
Document.addHeading(wdoc, "Report", 1);
Document.addParagraph(wdoc, "Generated by Documonster.");
const docxBytes = await Io.toBuffer(Document.build(wdoc));
const parsedDocx = await Io.read(docxBytes); // round-trip read

// Formula — opt-in calculation engine (kept out of the base bundle)
// Recalculate an excel workbook via the excel/formula subpath.
import { calculateFormulas } from "documonster/excel/formula";
import { Cell } from "documonster/excel";
Cell.setValue(sheet, "A4", { formula: "SUM(A1:A3)" });
calculateFormulas(workbook); // now populates cell results

// Syntax inspection is available separately
import { Formula } from "documonster/formula";
const ast = Formula.parse(Formula.tokenize("SUM(A1:A3)"));

Browser Support

Documonster has native browser support with zero configuration for modern bundlers.

// Bundlers (Vite, Webpack, Rollup, esbuild) — just import
import { Workbook } from "documonster/excel";
const wb = Workbook.create();
Workbook.addWorksheet(wb, "S1");
const buffer = await Workbook.toBuffer(wb);
<!-- Script tag (no bundler) — one IIFE per module, each under the shared `Documonster` global -->
<script src="https://unpkg.com/[email protected]/dist/iife/documonster.excel.iife.min.js"></script>
<script>
  const { Workbook, Cell } = Documonster.Excel;
  const wb = Workbook.create();
  const ws = Workbook.addWorksheet(wb, "S1");
  Cell.setValue(ws, "A1", "Hello, Browser!");
  Workbook.toBuffer(wb).then(buffer => console.log(buffer.byteLength));
</script>

The URL is pinned on purpose: an unpinned unpkg.com/documonster/… resolves to whatever is newest, so a future release would change a page that never asked to change. Every module ships its own bundle, and the file name names the module:

excel, word, pdf, csv, markdown, xml, formula, archive, stream, draw, mermaid

Swap the name in the URL and read the namespace back off Documonster.Word, Documonster.Pdf, Documonster.Mermaid, … Loading several is fine; they extend one shared global. There is no whole-family bundle, so a page pays only for the modules it names.

The IIFE bundle does not include the formula calculation engine. Use ESM + documonster/excel/formula if you need to recalculate formulas.

For older browsers without native CompressionStream API, Documonster automatically uses a built-in pure JavaScript DEFLATE implementation — no polyfills needed.

Requirements

| Runtime | Supported | | ---------- | ----------------- | | Node.js 22 | LTS — floor 22.13 | | Node.js 24 | LTS | | Node.js 26 | Current | | Bun | latest |

| Browser | Minimum Version | | ------- | ------------------- | | Chrome | 98+ (February 2022) | | Edge | 98+ (February 2022) | | Firefox | 102+ (June 2022) | | Safari | 15.4+ (March 2022) | | Opera | 84+ (February 2022) |

The package is ESM-only. Nothing changes for Node ESM, a bundler or a <script> tag, and a CommonJS require() call site is unchanged too — Node loads an ES module through require() from 22.12, and stops warning about it from 22.13, which is why the floor is that patch.

Set nodenext instead. TypeScript's node16 mode predates require(esm) and rejects the import before Node ever sees it:

error TS1479: The current file is a CommonJS module whose imports will produce 'require'
calls; however, the referenced file is an ECMAScript module and cannot be imported with
'require'.

nodenext knows about require(esm) and accepts it — verified on tsc 5.9, along with bundler and the legacy commonjs + node10 pair, which resolves types through typesVersions. The emitted JavaScript is identical and runs either way; only the type checker objects.

Jest cannot require() an ES module, so it needs a transform. This is the same two-file change a Jest project already needs for chalk, uuid, nanoid, strip-ansi and most other modern packages — if you have one of those, add documonster to the pattern you already have:

// babel.config.cjs
module.exports = { presets: [["@babel/preset-env", { targets: { node: "current" } }]] };
// jest.config.json
{
  "transform": { "\\.[jt]sx?$": "babel-jest" },
  "transformIgnorePatterns": ["/node_modules/(?!documonster)"]
}

Vitest needs no configuration.

Links