@domternal-pro/extension-export
v1.0.0
Published
Client-side document export for Domternal: Word (.docx) with native threaded comments and PDF with merged-cell tables, entirely in the browser or Node, no conversion service
Maintainers
Readme
@domternal-pro/extension-export
Document export for Domternal in the browser or Node: Word (.docx) with native
threaded comments and PDF with merged-cell tables. Document conversion runs in your
browser or Node process, with no conversion service, metering or document
upload to Domternal. By default, an http(s) image referenced by the document
is fetched directly from its source URL during export. Set
allowRemoteImages: false or provide an imageResolver to control that
network access.
Links
Licensing
This is a commercial package distributed through the public npm registry. A DOM-connected editor surface remains fully featured without a key for internal evaluation and shows a small evaluation badge. Word, PDF and browser-print output remains available but carries an evaluation footer unless a covered DMP2 Commercial Key is active, or a covered DMP2 Evaluation or Internal Key is used in explicit evaluation mode; Word and PDF also carry the documented metadata mark. The document body is never changed. Evaluation does not permit production use. See files an unlicensed build produces.
Keyless headless evaluation is explicit and remains fully functional:
import { configureProLicense } from '@domternal-pro/core';
configureProLicense({ mode: 'evaluation' });Production uses the signed Commercial Key from the Order confirmation:
import { configureProLicense } from '@domternal-pro/core';
configureProLicense({
mode: 'production',
key: 'DMP2...',
});A Commercial DMP2 Key carries exactly one signed Product Line. Every registered commercial package in an ordinary release must carry that same Product Line. A security-only release must carry it in both package metadata and its separate DMS1 certificate. Missing, conflicting or mismatched Product Line metadata remains uncovered and does not activate production. DMS1 never changes the key or grants another Product Line. Evaluation, Internal and legacy DMP1 keys do not use this Commercial Product Line field.
The signed key payload is not encrypted and may be readable in delivered browser code. Permitted embedding is expected, but the raw key must remain within the Customer scope allowed by the license. DMP2 omits Customer identity, contact details, Order reference, plan, price, separate payment and paid-through fields, and Developer limits. Commercial entitlement and per-key identifiers are random and opaque; the public status API does not expose them.
License validation runs entirely offline and never contacts Domternal: there is no online activation, license telemetry, metering, seat-counting or revocation request. A DMP2 Evaluation Key can remove visible evaluation notices only in explicit evaluation mode and only through its signed UTC expiry day; it can never activate production mode. In production mode it remains visibly badged or marked. A DMP1 key is recognized only for legacy diagnostics: it leaves editor badges and marked-output notices in place and never authorizes guarded production use. A DMP2 Commercial Key does not activate before its signed not-before day. For ordinary and renewal keys that day is the Subscription start; an exceptional surviving-rights or remedy key can use the later decision or issuance day required by the license. During its paid Subscription and 14-day grace period, ordinary package coverage stops at its signed ordinaryReleaseThrough day; grace does not extend that boundary. After grace, a key without signed technical post-grace eligibility reports subscription-expired. A technically eligible key can continue coverage through ordinaryReleaseThrough, qualifying DMS1 releases and exact Section 10 remedy days, while the public status exposes a compatible derived fallbackThrough equal to ordinaryReleaseThrough. That technical marker does not prove 12 paid months or define the surviving legal scope: the Agreement and accepted Order define the legal scope, while the key and minimum durable entitlement state support later recognition of that scope, including whether it covers Qualified Builds, discontinuation final retained builds or another express surviving right. Post-expiry use is runtime-only for the exact permitted artifacts. Development, modification, rebuilding and new Applications require an active Subscription, subject only to the Agreement's narrow security, intellectual-property and replacement-key exceptions. A key-only reproduction changes no other code, dependency or feature and inherits the original build status. The contractual post-expiry Developer limit remains as a final derived value in the minimum durable entitlement state while it is relevant; supporting Order, payment and calculation records follow their separate retention periods; the runtime does not count people or expose that limit. Rights from different expiries remain attached to their own Commercial Keys. Coverage therefore uses both baked package release dates and the current UTC day reported by the runtime. Guarded headless production activates only when that Commercial Key covers every registered Pro package. A standalone Word, PDF or browser-print operation is a marked-output surface and is never blocked merely because activation is absent; the notice travels with the result instead. Importing the package, its mapper subpath or a serializer remains neutral. Reads, conversion for recovery and access to the document body never become license locks. Activation is technical, not the license itself: permitted use is defined by LICENSE.md. See Installation and licensing for the complete setup.
Security-only releases use a separate signed DMS1 Security Release Certificate embedded in the package set; DMS1 does not add fields to or modify the Customer's DMP2 key. During the paid Subscription and grace, DMS1 requires a signed feature-baseline Release Date on or before ordinaryReleaseThrough; after grace, the key must also have technical post-grace eligibility. An exact Section 10 replacement date does not establish DMS1 baseline eligibility. A key without post-grace eligibility is never revived after grace. DMS1 does not renew a Subscription, move an ordinary-release boundary, change a Developer limit, unlock features or grant another Product Line. Post-expiry use is limited to the narrow security replacement of an eligible artifact, with no unrelated code, dependency or feature change, and the result inherits that artifact's status. The fixed Product Line Security Support End Date ends the obligation to issue further Security Updates, subject to mandatory law. An eligible DMS1 update signed and released during that period may remain usable afterward only within the same existing or surviving production right and limits; continued use does not make the Product Line supported or create, restore, renew or expand a right. The controlling terms are in Section 8 of LICENSE.md and the public security policy.
Install
pnpm add @domternal-pro/core @domternal-pro/extension-export docx pdfmakedocx (^9.7.1) and pdfmake (^0.3.11) are required peer dependencies:
install both. Each backend loads lazily on first use, so the format you
never export costs install size only, nothing at runtime. Bundlers that
resolve every import eagerly need both present even for a single-format
app, which is why neither peer is optional.
pdf-lib (^1.17.1) is an optional peer. Install it and set
pdf: { comments: { annotations: true } } to add clickable sticky-note
annotations in the PDF's page margin, the ones Acrobat lists in its
Comments panel. Without it the export still succeeds, warns once, and
keeps the comment appendix.
The default PDF fonts are installed automatically through
@domternal-pro/extension-export-fonts. Their bytes load only during PDF
generation or when DOCX embedFonts is enabled. The default PDF family keys
are DomternalSans and DomternalMono; embedded DOCX files use the matching
internal names Domternal Sans and Domternal Mono.
Node 22 or newer.
One copy of the core
@domternal/core must resolve to a single instance across your app. An extension belongs to
the core that created it, and the exporter walks the document with the schema that core built, so
an extension bound to a second copy serialises against node types the document does not use. This
package checks at construction and refuses, naming the fix.
The free core performs the same check from its own side. This one exists because the peer range
on @domternal/core is open-ended on purpose, so you may be holding a core released before that
check existed. Full dedupe recipe per package manager and bundler:
https://domternal.dev/v1/guides/single-prosemirror-copy/
Editor usage
import { Export } from '@domternal-pro/extension-export';
const editor = new Editor({
extensions: [
// ...your extensions
Export.configure({
pageSetup: { size: 'A4', metadata: { creator: 'Ada' } },
onWarnings: (warnings, format) => showToast(warnings, format),
}),
],
});
editor.commands.exportDocx();
editor.commands.exportPdf();The extension adds an Export dropdown to the toolbar (disable with
toolbar: false) and works in read-only editors. Both commands take
per-call overrides that merge over the configured options for that one
run: editor.commands.exportPdf({ fileName: 'report' }).
Options
| Option | Default | Description |
| --- | --- | --- |
| fileName | null | Download name without extension, or (editor) => string; derived from the document when null. |
| pageSetup | null | Page size, margins, footer preset and metadata shared by both formats. |
| tokenColors | null | Token color palette; the theme's light palette by default. |
| imageResolver | null | Custom image byte resolution; data URLs and http(s) fetch by default. |
| codeHighlighter | null | Token-colored code blocks in both formats; plain monospace otherwise. |
| docx | null | DOCX-only extras: comments, embedFonts, baseFont/monoFont, node and mark mappings. |
| pdf | null | PDF-only extras: fonts, baseFont/monoFont, comments, renderMathSvg, node and mark mappings. |
| toolbar | true | Show the Export dropdown; false keeps the commands only. |
| onExport | null | Replaces the browser download; receives the finished export. |
| onWarnings | null | Fires after every export that produced warnings. |
| onError | null | Called when an export fails; the console gets the error otherwise. |
The Pro column mappers stay importable from
@domternal-pro/extension-export/mappers (columnsDocxMapper,
columnsPdfMapper) for composing custom nodeMappings.
Headless and Node usage
import { exportToDocx } from '@domternal-pro/extension-export/docx';
import { exportToPdf } from '@domternal-pro/extension-export/pdf';
const { blob, warnings } = await exportToDocx({ doc, schema });
await writeFile('report.docx', Buffer.from(await blob.arrayBuffer()));Both backends accept a live Editor or a headless { doc, schema } pair and
run in the browser and Node. Environment-dependent inputs such as SVG
rasterization can degrade differently, as documented. Remote images are fetched
by default; pass allowRemoteImages: false to export them as links instead
(recommended for server-side use).
Documented degradation handling
Built-in handling degrades unsupported or unloadable document content where
documented, for example to links or plain text, and reports those degradations
in result.warnings with stable codes. Invalid configuration, missing required
dependencies, consumer callback failures or an unrecoverable backend error can
still fail the export through the normal error path. The onWarnings option
surfaces warnings without replacing the download flow.
License
Commercial; see LICENSE.md. Font licensing ships with the font dependency. Other third-party attributions are in THIRD-PARTY-LICENSES.md.
Support
Report a defect that reproduces with synthetic content on the public tracker, using the Pro bug report template. Anything involving your own documents, your data or a collaboration update goes to email instead, and security vulnerabilities go to email only.
The Support and reporting issues policy explains where confirmed defects may be documented and how material notices are handled. Public channels are not a complete record of internal reports, investigations or other issues. Security vulnerabilities are handled through coordinated private disclosure.
