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

@attentionform/astra-engine

v0.3.0

Published

Headless, transactional MS Word (OOXML) document engine

Readme

@attentionform/astra-engine

The core headless OOXML engine for ASTra.

@attentionform/astra-engine provides transactional, in-memory manipulation of Microsoft Word (.docx) documents with strict ISO/IEC 29500 / ECMA-376 schema compliance, persistent DOM node addressing, atomic batch execution with rollback, and Token-Optimized Outline Notation (TOON).


Installation & Quickstart

npm install @attentionform/astra-engine

Basic Example: Inspecting and Mutating a Document

import { DocxParser, OperationEngine } from '@attentionform/astra-engine';
import * as fs from 'node:fs';

async function main() {
  // 1. Load an existing .docx file into an in-memory DOM
  const fileBuffer = fs.readFileSync('document.docx');
  const parser = new DocxParser(fileBuffer);
  
  // 2. Access the typed Document AST and structural summary
  const ast = await parser.getAST();
  console.log(`Document loaded with ${ast.sections.length} section(s).`);

  // 3. Execute an atomic batch mutation with automatic rollback on error
  const engine = new OperationEngine(ast, parser);
  const result = await engine.executeBatch({
    operations: [
      {
        action: 'replace',
        target: ast.sections[0].nodes[0].id,
        text: 'Executive Strategic Review (Q4)'
      },
      {
        action: 'insert',
        type: 'paragraph',
        anchor: ast.sections[0].nodes[0].id,
        position: 'after',
        text: 'Net revenue increased by 28% quarter-over-quarter.'
      }
    ]
  });

  if (result.success) {
    console.log(`Applied ${result.appliedCount} operations successfully.`);
    
    // 4. Validate ECMA-376 schema and serialize back to .docx buffer
    const outBuffer = parser.rezip();
    fs.writeFileSync('document_updated.docx', outBuffer);
  } else {
    console.error('Batch failed:', result.errors);
  }
}

main();

Core Engine Capabilities

1. In-Memory DOM Level 2 with Stable Addressing

  • Parses .docx archives directly in memory using an internal ZIP adapter with zero extraction to disk.
  • Automatically assigns persistent tracking IDs (data-astra-id) to every paragraph (p_001 or w14:paraId), table (t_001), and container.
  • AI agents and automation scripts can reference exact nodes without fragile string offsets or line numbers.

2. 27 Atomic Operations with Transactional Rollback

The OperationEngine dispatches across 27 distinct operation types defined as a strict discriminated union:

  • Content: insert, replace, delete, move
  • Formatting: style, clearFormat, namedStyle
  • Tables & Structure: table, section, pageSetup, pageBorder, coverPage
  • Complex Elements: chart, image, equation, callout, field, list
  • References & Annotations: footnote, endnote, hyperlink, bookmark, comment, headerFooter, watermark
  • Revisions & Compliance: trackedChange, metadata

Transactions: Before executing a batch, the engine captures an immutable snapshot of both the AST and package zip. If any operation violates schema rules or throws an unhandled exception, operations are automatically rolled back (rollbackOnError: true).

3. Pre-Write ECMA-376 Schema Gate

ASTra integrates @attentionform/ooxml-validator directly into its serialization pipeline. No mutated file is committed to storage unless every internal XML part passes strict OpenXML schema validation.

4. Token-Optimized Outline Notation (TOON)

Converts verbose OpenXML markup into dense, tabular outlines tailored for LLM context windows:

  • compact: Terse pipe-delimited outline displaying node IDs, types, and text (about 89 % median reduction; 45 % of documents reach 90 %).
  • standard: Compact outline plus inline styling flags ([B], [I], [C:hex], [SZ:n], [HDR], [ZEBRA]).
  • full: Deep structural dump including margins, borders, and XML property trees (section-scoped).

5. Style Guides (Omitted-Param Defaults + Advisory Linting)

Attach a parsed guide (parseStyleGuide in src/style-guide/parser.ts) as the engine's aesthetic skin:

import { OperationEngine, parseStyleGuide } from '@attentionform/astra-engine';

const { config: styleGuide } = parseStyleGuide(guideMarkdown);
const engine = new OperationEngine(ast, parser, { styleGuide });
// or attach later: engine.setStyleGuide(styleGuide);

Precedence is global: explicit op param > guide value > built-in default. Guides fill only omitted params (dark table fills gain the guide header text by computed WCAG AA contrast, uncolored chart series pull the guide palette in order, callouts fall back to the guide theme, code blocks take the guide background/borders); caller-passed values always win. Composed Markdown has no per-table or per-alert theme syntax, so a guided compose skins tables with tables.headerFill (and shades the odd data rows with tables.alternatingFill) and > [!TAG] alerts with callouts.defaultTheme outright. A compose with no guide uses the built-in Default Corporate guide (navy header, bold white header text, striped rows, per-tag alert colours); pass styleGuide: 'legacy' for the old gray headers. Palette base colors, typography.*, tables.borderColor, callouts.preferredThemes, and layout.* are advisory-only: parsed and linted, never rendered. lintDocumentStyle(ast, guide) reports { nodeId, rule, message } findings (header contrast, duplicate chart colors, splittable tables) without ever failing; DocumentManager save/validate paths carry them as additive styleWarnings. Guide-parse notes ride the same machine keys (guide-parse entries on validate, string notes on create/import/batch, MCP warnings/styleGuideWarnings). Resolve file or bundled refs with resolveStyleGuide(ref, { allowedDir }); unknown names and missing files fail closed with E_VALIDATION. Full file spec, precedence table, sandbox matrix, and session semantics: docs/cli-guide.md §6. Bundled ref report carries display title Corporate.


API Reference

DocxParser

The primary entry point for reading and parsing Word documents:

import { DocxParser } from '@attentionform/astra-engine';

// From Buffer
const parser = new DocxParser(buffer);

// Create fresh document from template ('report' | 'memo' | 'blank')
const freshDoc = DocxParser.createNewDocument('report');

// Retrieve typed AST
const ast = await parser.getAST();

// Retrieve structural summary
const summary = parser.getStructuralSummary();

// Validate OOXML schema compliance
const validation = await parser.validateOOXML();

// Rezip into .docx Buffer with canonical namespace normalization
const outputBuffer = parser.rezip();

validateDocxBuffer & assertValidDocx

Direct validation utility functions:

import { validateDocxBuffer, assertValidDocx } from '@attentionform/astra-engine';

const result = await validateDocxBuffer(buffer);
if (!result.ok) {
  console.error('Validation errors:', result.errors);
}

// Throws OoxmlValidationError if invalid
await assertValidDocx(buffer);

sanitizeDocxBuffer

Privacy and metadata scrubbing:

import { sanitizeDocxBuffer } from '@attentionform/astra-engine';

const { buffer: cleanBuffer, report } = sanitizeDocxBuffer(buffer, {
  zeroRetention: true,
  purgePII: true,
  acceptAllRevisions: true,
  stripComments: true
});

console.log(`Scrubbed ${report.removedRSIDs} RSIDs and ${report.strippedComments} comments.`);

With acceptAllRevisions, sanitizeDocxBuffer throws E_VALIDATION (naming the part and the revision kinds) and returns no buffer when revision markup remains that cannot be resolved safely, because a partly cleaned file could still contain deleted text and reviewer names.

TOON Generator

import { ToonGenerator } from '@attentionform/astra-engine';

const generator = new ToonGenerator();

// Generate standard outline
const table = generator.generateToon(ast, undefined, { fidelity: 'compact' });
const outline = generator.renderToonText(table);

// Generate budget-capped outline fitting inside 1500 tokens
// (over-budget docs slice on row boundaries; page the rest with
// { offset: nextOffset } until hasMore is false)
const { rendered: budgetOutline, tokenCount, truncated, hasMore, nextOffset } =
  generator.generateTokenBudgetToon(ast, 1500);

Building & Testing Locally

# Build engine package
npm run build -w @attentionform/astra-engine

# Run unit tests
npm test -w @attentionform/astra-engine

License

Business Source License 1.1 (BUSL-1.1): source-available, free for individuals, education, non-profits, public bodies and small businesses; other production use needs a commercial license. Each version converts to Apache-2.0 four years after release. See LICENSE and write to [email protected] for a commercial license.