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

@awacloud/odf

v1.0.0

Published

Browser-safe OpenDocument Format (ODT/ODS/ODP) reader, writer and orchestrator for the @awacloud stack.

Downloads

136

Readme

@awacloud/odf

Pure JavaScript library to read and write OpenDocument documents (ODF — .odt, .ods, .odp) in the browser. No npm dependency beyond the monorepo framework: ZIP, XML parsing/serialization and the ODF package container are either implemented here or consumed from @awacloud/fw.

The package exposes a typed document model for the three formats (a serializable JSON tree), a core set of parsers and orchestrators, and opt-in extras that promote more of the ODF vocabulary into typed fields. Whatever the typed model does not cover is preserved: unknown XML stays in _extras, and write(read(x)) re-emits the package parts it does not regenerate (pictures, thumbnails, embedded objects) byte-for-byte with their manifest media types, together with the read styles, settings and metadata; meta:generator is rewritten to @awacloud/odf. One limitation: a frame anchored directly in a paragraph is re-emitted after the paragraph's runs, not at its original position (inside a text:span, frames, fields, spacing and nested spans keep their position). It mirrors the architecture of the sibling package @awacloud/ooxml.

Installation

npm install @awacloud/odf

In the browser, via import map:

<script type="importmap">
{ "imports": {
    "@awacloud/fw":   "/node_modules/@awacloud/fw/src/main.js",
    "@awacloud/fw/":  "/node_modules/@awacloud/fw/src/",
    "@awacloud/odf":  "/node_modules/@awacloud/odf/src/main.js",
    "@awacloud/odf/": "/node_modules/@awacloud/odf/src/"
}}
</script>

Quick Start

Core (factory wiring)

Every odf module is a { name, dependencies, factory } descriptor resolved by an @awacloud/fw ModuleRuntime. The package entry exports the fw modules the odf modules depend on (fw_require) next to the odf ones (modules):

import { ModuleRuntime } from '@awacloud/fw/core/runtime.js';
import { fw_require, modules } from '@awacloud/odf';

const runtime = new ModuleRuntime();
runtime.registerAll(fw_require);
runtime.registerAll(modules);
const odt = runtime.resolve('odt');

const bytes = odt.write(odt.fromText(['Hello, world.']));
const decoded = odt.read(bytes);
console.log(odt.toText(decoded)); // → "Hello, world."

Typed paragraph manipulation

Continuing with the odt instance resolved above:

const doc = {
    body: [
        odt.paragraph('Title', { styleName: 'Title' }),
        {
            type: 'paragraph',
            runs: [
                { type: 'text', value: 'plain ' },
                { type: 'span', value: 'styled', styleName: 'T1' },
                { type: 'line-break' },
                { type: 'text', value: 'next line' }
            ]
        }
    ]
};
const styledBytes = odt.write(doc, { meta: { title: 'Doc', creator: 'Alice' } });

Reading styles back

odt.read() turns a style reference into semantic fields (bold / italic / strike / monospace, list numbering, bordered cells, margins-aligned tables) only when the style is fully mapped and comes from the content.xml automatic styles or from the styles.xml office:styles named styles; it never follows style:parent-style-name chains, ignores the automatic styles of styles.xml, and leaves every other style as an opaque styleName — see docs/guide/read-write-odt.md.

Pre-built bundles (dist/)

Each assembly root (odt, odt-large, odt-full, and the same three for ods and odp) ships as a two-surface build, generated by tools/generate-bundles.mjs (repository only, not part of the published package; a driver over @awacloud/tool-prebuild-generator) and regenerated with:

bun run gen:bundles

| Surface | Path | dependencies | |---------|------|-----------------| | dist/build/<root>.{js,min.js,meta.json} (@awacloud/odf/build/<root>.js) | fw-mode | the fw modules xml, bitstream, huffman, deflate, zip and crc32 — DI-injected by an @awacloud/fw ModuleRuntime | | dist/standalone/<root>.{js,min.js,meta.json} (@awacloud/odf/standalone/<root>.js) | framework-free | none — every fw + odf-local factory inlined |

dist/build/index.js (@awacloud/odf/build/index.js) is an fw-mode barrel re-exporting the whole @awacloud/odf namespace (the registration arrays and every named descriptor) for bulk registration on an @awacloud/fw runtime. See docs/api/bundles/prebuilt/README.md for the resolve-key table and usage examples.

Source structure

src/
├── main.js          entry point — `modules[]`, `extras[]`, `bundle[]`, `fw_require[]` + named descriptors
├── errors.js        OdfError + ParseError/RenderError/ContractError
├── (xml parser consumed from `@awacloud/fw/io/codec/xml.js`)
├── _shared/         odfShared (namespaces, XML helpers) + odfWalker (hook engine)
├── pkg/             ODF container (ZIP + mimetype + manifest.xml)
├── meta/            meta.xml (dc:* + meta:*)
├── settings/        settings.xml (preserve-unknowns)
├── style/           styles.xml, automatic styles, page layout, master pages
├── text/            text:p, headings, lists, sections, fields, tracked changes, style registry
├── table/  draw/  chart/  math/  form/  dr3d/  number/  mc/
├── odt/  ods/  odp/ top-level orchestrators (+ their walkers)
├── extra/           opt-in extras (typed or passthrough)
└── bundles/         `*-large` / `*-full` bundle descriptors

Hook .use(...)

The odt / ods / odp orchestrators expose a walker extensible via .use(...extensions): each extra can publish hydrate* / dehydrate* hooks (Paragraph, Span, Heading, List, Table, Cell, Frame, Slide, Metadata, Settings, Styles — each orchestrator walks the node types it carries). Idempotent (duplicates are filtered out). See docs/guide/extending.md and docs/api/ for the per-module coverage.

Documentation

Tests

Co-located unit tests (src/**/*.test.js) + integration tests in tests/; run them from the monorepo root:

bun test packages/front/office/odf/

Coverage

  • Core — .odt / .ods / .odp orchestrators + typed parsers for text:* / table:* / draw:* / style:* / chart:* / math:math / form:* / dr3d:* + mimetype, manifest, meta, settings, styles.
  • Opt-in extras (extras in src/main.js, one file per extra under src/extra/), in four tiers:
    • P0 deep typing: tracked-changes, fields, lists, table-advanced, page-styles, properties-typed, shapes, presentation.
    • P1 complementary deep typing: text-meta-extended, sections-advanced, toc/index, image-extended, chart-typed, animations-smil, forms-controls, number-format-extended, meta-extended, math-mathml.
    • P2 secondary-domain typing: dr3d-3d, database-sources, settings-extended, script-macros, dsig-signatures.
    • P3 *-misc passthrough (catch-all _passthrough: true): text, style, draw, table, office, legacy-staroffice.
  • Bundles ready to plug in: odt|ods|odp-large (core + P0) and odt|ods|odp-full (*-large + P1/P2/P3).

Design choices

  • Typed document model — serializable JSON tree rather than a flat object.
  • _extras mechanism — untyped elements and attributes are preserved in _extras and re-emitted on write.
  • mimetype STORED — first ZIP entry, compression 0, as required by the ODF spec.
  • Single dependency — only @awacloud/fw (workspace).
  • Worker-safe — each factory is self-sufficient (serializable via factory.toString()).
  • Browser-only — no Node API: Uint8Array, TextEncoder, TextDecoder only.
  • Bounded ZIP reading — read() caps entry count, total uncompressed size and per-entry ratio (see the guide's security section).
  • Mirror of @awacloud/ooxml — same factory pattern, same conventions, same docs format.

See also

Exposed sub-paths

| Sub-path | Target | Usage | |----------|--------|-------| | @awacloud/odf | src/main.js | Index — modules[], extras[], bundle[], fw_require[] and every named descriptor | | @awacloud/odf/errors | src/errors.js | odfErrors — OdfError / ParseError / RenderError / ContractError factory | | @awacloud/odf/odt | src/odt/odt.js | .odt orchestrator | | @awacloud/odf/odt-large | src/bundles/odt-large.js | Core odt + P0 extras | | @awacloud/odf/odt-full | src/bundles/odt-full.js | odt-large + P1/P2/P3 extras | | @awacloud/odf/ods | src/ods/ods.js | .ods orchestrator | | @awacloud/odf/ods-large | src/bundles/ods-large.js | Core ods + P0 extras | | @awacloud/odf/ods-full | src/bundles/ods-full.js | ods-large + P1/P2/P3 extras | | @awacloud/odf/odp | src/odp/odp.js | .odp orchestrator | | @awacloud/odf/odp-large | src/bundles/odp-large.js | Core odp + P0 extras | | @awacloud/odf/odp-full | src/bundles/odp-full.js | odp-large + P1/P2/P3 extras | | @awacloud/odf/pkg | src/pkg/package.js | ODF container (ZIP + mimetype + manifest) | | @awacloud/odf/text | src/text/content.js | textContent — <office:text> body orchestrator | | @awacloud/odf/table | src/table/table.js | tableTable — <table:table> parser/renderer | | @awacloud/odf/draw | src/draw/frame.js | drawFrame — <draw:frame> wrapping image / text-box / object children | | @awacloud/odf/chart | src/chart/chart.js | chartChart — <chart:chart> root + chart content helpers | | @awacloud/odf/math | src/math/math.js | mathMath — embedded MathML passthrough | | @awacloud/odf/form | src/form/forms.js | formForms — <office:forms> + typed form:* controls | | @awacloud/odf/dr3d | src/dr3d/dr3d.js | dr3dScene — <dr3d:scene> + typed lights and solids | | @awacloud/odf/extra/* | src/extra/*.js | Direct imports of the opt-in extras | | @awacloud/odf/bundles/* | src/bundles/*.js | Direct imports of the bundles | | @awacloud/odf/build/* | dist/build/* | Pre-built bundles — fw-mode (dependencies declared) + the index.js barrel | | @awacloud/odf/standalone/* | dist/standalone/* | Pre-built bundles — framework-free (every fw factory inlined) |

Maturity

L4 (awa.maturity in package.json) — the highest level of the monorepo's maturity scale: typed .odt / .ods / .odp, tested and documented to publication quality.

Licence

AGPL-3.0-only — see LICENSE.

Copyright (c) 2026 AwaCloud SAS

This package is also available under a commercial licence from AwaCloud SAS, as stated in NOTICE.

Project