Skip to content
Apertura
API reference

@apertura/viewer

Framework-independent Apertura viewer: detects the format, parses the file and mounts a view

58 exported symbols · 11 declared here · 47 re-exported

Classes

AperturaErrorfrom @apertura/core
class AperturaError extends Error

Base class for every error raised by Apertura. A common ancestor lets consumers distinguish "the file failed to open" from a genuine bug in their own code with a single `instanceof` check.

code
string
Stable machine-readable code; unaffected by message wording changes.
ContentDocumentfrom @apertura/extract
class ContentDocument

An extracted document: the tree, and every way of writing it down. The serialisers are methods rather than free functions for one reason: the addresses. A caller who has the tree and reaches for a `render` from somewhere else gets text with no way back into the document, which is the thing this package exists to prevent. Everything that produces text from here can also produce the map beside it.

format
FormatId
hash
string
metadata
DocumentMetadata
blocks
readonly Block[]
annotations
readonly Annotation[]
profile
string
walk
() => Generator<Block>
Every block in reading order, parents before children.
sections
readonly Block[]
The top-level sections: slides, sheets, or the parts of a document.
toPlainText
{ (options?: TextOptions & { withMap?: false; }): string; (options: TextOptions & { withMap: true; }): { text: string; map: OffsetMap; }; }
toPlainText
{ (options?: TextOptions & { withMap?: false; }): string; (options: TextOptions & { withMap: true; }): { text: string; map: OffsetMap; }; }
toMarkdown
{ (options?: MarkdownOptions & { withMap?: false; }): string; (options: MarkdownOptions & { withMap: true; }): { markdown: string; map: OffsetMap; }; }
toMarkdown
{ (options?: MarkdownOptions & { withMap?: false; }): string; (options: MarkdownOptions & { withMap: true; }): { markdown: string; map: OffsetMap; }; }
toHtml
{ (options?: HtmlOptions & { withMap?: false; }): string; (options: HtmlOptions & { withMap: true; }): { html: string; map: OffsetMap; }; }
toHtml
{ (options?: HtmlOptions & { withMap?: false; }): string; (options: HtmlOptions & { withMap: true; }): { html: string; map: OffsetMap; }; }
toJSON
() => ContentDocumentJson
chunks
(options?: ChunkOptions) => Chunk[]
Structure-aware chunks, each carrying the selectors to find it again.
selectorsFor
(text: string, map: OffsetMap, start: number, end: number, output?: OutputKind) => Selector[]
Selectors for a range of one of this document's text outputs. The bridge for everybody who chunked the text themselves. Give it the offsets a splitter reported, the map that produced them and which output they came from, and it gives back the anchor triple: exact, portable and robust.
CorruptFileErrorfrom @apertura/core
class CorruptFileError extends AperturaError

The file was identified, but its contents violate the format specification.

offset
number | undefined
Byte offset where the violation was found, when known.
DocumentSearch
class DocumentSearch
content
ContentDocument
highlights
HighlightRegistry
hits
readonly SearchHit[]
currentIndex
number
Index of the hit currently marked as active, or -1.
find
(query: string, options?: SearchOptions) => readonly SearchHit[]
Finds every occurrence and highlights all of them. All of them, not the visible ones: a highlight is a registered intention, so the four hundredth hit is already painted by the time the reader scrolls to it. That is what makes "next" instant on a long document.
next
() => number
Moves to the next hit, wrapping. Returns its index, or -1.
previous
() => number
clear
() => void
show
(selectors: readonly Selector[], options?: HighlightOptions) => HighlightHandle
Highlights a passage identified by stored selectors, and scrolls to it. The other half of the loop: a chunk extracted months ago, embedded, stored, retrieved by a question, and now shown in the document it came from.
FormatRegistryfrom @apertura/core
class FormatRegistry

Registry of parsers. An instance rather than a global singleton: a single page may host several independently configured viewers, and tests must not see each other's registrations. {@link defaultRegistry} is available for simple cases. Renderers are registered in `ViewRegistry` from `@apertura/render`, which extends this class. The split is what lets a server open a document without the DOM appearing anywhere in the type graph.

registerParser
<TDocument extends AperturaDocument>(plugin: ParserPlugin<TDocument>) => this
getParser
(format: FormatId) => ParserPlugin | undefined
supportedFormats
() => FormatId[]
Formats that have a registered parser.
open
(source: ByteSource, options?: OpenOptions) => Promise<AperturaDocument>
Detects the format and opens the document with the matching plugin. When detection returns `unknown` (the typical case for a ZIP container) the registered plugins are polled through `canOpen`, so docx, xlsx and pptx sort themselves out without the core knowing anything about their internals.
HighlightRegistryfrom @apertura/highlight
class HighlightRegistry
add
(selectors: readonly Selector[], options?: HighlightOptions) => HighlightHandle
Registers a highlight and paints whatever of it is currently on the page. Resolution happens once, here, rather than on every repaint: a scroll through a document with four hundred hits would otherwise re-resolve four hundred anchors per frame, and quote resolution scans the whole text.
highlights
readonly HighlightHandle[]
Every registered highlight, painted or not.
get
(id: string) => HighlightHandle | undefined
remove
(id: string) => void
clear
() => void
refresh
() => void
Repaints from the DOM as it is now. Cheap enough to call on every scroll: the work is one selector lookup and one range construction per highlight whose block is mounted, and none at all for the rest. Coalesced to an animation frame so a burst of mount events costs one repaint.
scrollTo
(id: string, options?: ScrollIntoViewOptions) => boolean
Brings a highlight into view. Returns false when the highlight is not on the page and the host has given no way to get there. That is not a failure to report as an error — it is the ordinary state of a highlight nine hundred pages away — but the caller has to know, because "scroll to the answer" that silently does nothing is worse than a message saying the document has moved on.
pageOf
((block: Locator) => number | undefined) | undefined
Set by the host: which page a block landed on after layout.
onScrollToPage
((page: number) => void) | undefined
Set by the host: scroll to a page so its content mounts.
dispose
() => void
NotImplementedErrorfrom @apertura/core
class NotImplementedError extends AperturaError

A format feature that has not been implemented yet. A dedicated type lets the viewer show "this part of the document is not supported yet" instead of a generic read failure.

UnsupportedFormatErrorfrom @apertura/core
class UnsupportedFormatError extends AperturaError

The file format was not recognised, or no plugin is registered for it.

detectedFormat
string | undefined
Viewer
class Viewer

A framework-independent document viewer. The single place that knows the full path from bytes to format to document to DOM. The React, Vue and Angular wrappers are thin adapters over this class, so their behaviour is identical by construction rather than by convention.

state
ViewerState
container
HTMLElement
view
DocumentView | undefined
The live view, for reaching format-specific APIs such as page navigation.
subscribe
(listener: (state: ViewerState) => void) => () => void
Subscribes to state changes. Returns an unsubscribe function.
open
(input: ByteSourceInput, options?: ViewerOptions) => Promise<void>
Opens a file and mounts its view. Calling it again before the previous call settles is correct: the older result is discarded. That is the normal case when a user picks files in quick succession.
refresh
() => void
Re-renders the current view.
close
() => void
Closes the document and clears the container.
destroy
() => void
Releases every resource. The instance must not be used afterwards.
ViewRegistryfrom @apertura/render
class ViewRegistry extends FormatRegistry

A format registry that also knows how to draw. Parsers are registered in `@apertura/core`, which knows nothing about the browser; renderers are registered here. Subclassing rather than composing keeps the fluent chain a caller expects — `registerParser` returns `this`, so a registry can be built in one expression — while leaving the parser half usable on a server that has no DOM at all.

registerView
<TDocument extends AperturaDocument>(plugin: ViewPlugin<TDocument>) => this
getView
(format: FormatId) => ViewPlugin | undefined
viewableFormats
() => FormatId[]
Formats that have both a parser and a renderer.

Functions

createDefaultRegistry
function createDefaultRegistry(): ViewRegistry

A registry with every supported format registered. The convenient entry point for an application that just needs to open a file. When bundle size matters, build a {@link ViewRegistry} by hand so only the parsers actually used are included.

createDocxRegistry
function createDocxRegistry(): ViewRegistry

A registry holding only the Word format, for applications that need just that.

createSearch
function createSearch(container: HTMLElement, source: ByteSourceInput, options?: ExtractOptions): Promise<DocumentSearch>

Builds the search index for a document already on screen. The bytes are wanted but not required. With them the addresses carry a hash and a stored anchor from a different file is refused rather than resolved to whatever sits at that path; without them everything still works and simply cannot warn.

createViewer
function createViewer(container: HTMLElement, options?: ViewerOptions): Viewer

Creates a viewer mounted into the given element.

describeFormatfrom @apertura/core
function describeFormat(id: FormatId): FormatDescriptor | undefined
detectFormatfrom @apertura/core
function detectFormat(source: ByteSource): Promise<DetectionResult>

Determines the file format from its contents, name and MIME type. For ZIP containers the result is always `probable`: telling docx, xlsx, pptx and odt apart requires looking inside the archive, which is the job of `@apertura/ooxml`. The core deliberately avoids pulling in decompression just to detect a format.

extractfrom @apertura/extract
function extract(input: ByteSourceInput | AperturaDocument, options?: ExtractOptions): Promise<ContentDocument>

Read a document's content. Takes anything a byte source can be made of — a path is not one of them, that is `@apertura/node` — or an already-open document, which is the path a viewer takes when it wants to search what is already on screen without parsing it twice.

extractMarkdownfrom @apertura/extract
function extractMarkdown(input: ByteSourceInput | AperturaDocument, options?: ExtractOptions): Promise<string>

The whole document as markdown, in one call.

extractTextfrom @apertura/extract
function extractText(input: ByteSourceInput | AperturaDocument, options?: ExtractOptions): Promise<string>

The whole text, in one call. The shortest path in and the one most people will take first, so it does the conventional thing without being asked: no section labels, no markers, no markup.

findTextfrom @apertura/extract
function findText(document: ContentDocument, query: string, options?: { caseSensitive?: boolean; wholeWord?: boolean; limit?: number; }): { range: { start: Locator; end: Locator; }; text: string; }[]

Plain search over a document, returning anchors rather than offsets. What the viewer's find box is built on. Everything it returns is a selector set, so a hit found here highlights through exactly the same path as a chunk retrieved from a vector database — one mechanism, not two.

fromDocumentfrom @apertura/extract
function fromDocument(document: AperturaDocument, bytes: Uint8Array | undefined, options?: ExtractOptions): Promise<ContentDocument>

Read the content of a document that is already open. The viewer's path. A hash is computed from the bytes when they are to hand and omitted otherwise — an address with no hash still resolves, it simply cannot warn that it came from a different file.

resolveSelectorsfrom @apertura/extract
function resolveSelectors(document: ContentDocument, selectors: readonly Selector[], options?: ResolveOptions): ResolvedRange | undefined
toByteSourcefrom @apertura/core
function toByteSource(input: ByteSourceInput): Promise<ByteSource>

Normalises any supported input into a {@link ByteSource}. Strings are URLs.

Interfaces

AperturaDocumentfrom @apertura/core
interface AperturaDocument

An opened document: the contract shared by every parser. Deliberately narrow — it only carries what is meaningful for any format. Everything else (docx sections, xlsx sheets, pptx slides) lives in subtypes inside the format packages. The viewer works against this interface so that it can still show a title and a page count for a format whose renderer is not registered.

format
FormatId
kind
DocumentKind
metadata
DocumentMetadata
pageCount?
number | undefined
Number of pages/sheets/slides, when the format exposes it cheaply. For docx this is `undefined` until the document has been laid out: splitting a text flow into pages depends on fonts, hyphenation and the printable area.
extractText
() => Promise<string>
Extracts the whole document text for search, indexing and previews. A dedicated method because this is the one operation every format needs in the same way and which requires no rendering.
dispose
() => void
Releases retained resources. Calling it twice is safe.
ByteSourcefrom @apertura/core
interface ByteSource

A random-access source of bytes. This is the central abstraction of the project: parsers never touch `File`, `Blob` or the network directly. That makes it possible to read a ZIP central directory at the end of a file, or a PDF xref table, without pulling the whole document into memory, and to run the same parser in a browser, in Node, or on top of HTTP range requests.

byteLength
number
Total size of the source in bytes.
name?
string | undefined
File name when known. Used as a hint for format detection.
mimeType?
string | undefined
MIME type when the source reports one.
slice
(start: number, end?: number) => Promise<Uint8Array>
Reads the `[start, end)` range. Implementations must return exactly the requested number of bytes or throw {@link OutOfBoundsError}. Short reads are not allowed, otherwise every parser would have to re-check the length after each call.
dispose?
(() => void) | undefined
Releases retained resources such as caches or network connections.
Chunkfrom @apertura/extract
interface Chunk
text
string
The chunk as stored and embedded, contextualised if that was asked for.
contextLength
number
How much of `text` is the prepended heading path.
selectors
readonly Selector[]
Where to find it again: exact, portable and robust, in that order.
breadcrumbs
readonly string[]
The heading path above it.
section
string | undefined
`Slide 5`, `Sheet Budget`, or the section's label.
tokens
number
start
number
Offsets into the serialised output this came from.
end
number
ChunkOptionsfrom @apertura/extract
interface ChunkOptions

Chunking that knows what a document is. The state of the art in JavaScript is to take the text, split it every 512 characters, and hope. That destroys exactly the things retrieval depends on: a table loses its header three rows in, a heading is separated from the section it names, a sentence is cut in half, and every chunk arrives at the index with no idea where it came from. This walks the tree instead. Headings become breadcrumbs and stay with their content, a table row is never split, a table too big for one chunk is split by rows with its header repeated in each, and every chunk carries the selectors that find it again in the document it came from — which is the part nobody else has, and the reason a retrieval hit can be highlighted rather than merely quoted.

maxTokens?
number | undefined
Target size. Default 512.
overlap?
number | undefined
Overlap between neighbours, in tokens. Default 64.
tokenCounter?
((text: string) => number) | undefined
How to count. Default: characters over four. Pluggable because the right answer depends on a model this package has never heard of, and a default that shipped a tokenizer would be a megabyte of tables for something the caller can do in one line.
contextualize?
boolean | undefined
Prepend the heading path to each chunk's text. Default true. "Q3 Results › Risks › Currency exposure" in front of a paragraph that says "the position was closed in October" is the difference between a chunk that retrieves and one that does not. The context is marked in `contextLength` so a caller that wants the bare text can strip it.
tables?
"whole" | "rows" | undefined
`whole` keeps a table together; `rows` splits large ones. Default `rows`.
source?
"text" | "markdown" | undefined
Which output the chunk text comes from. Default `markdown`.
DetectionResultfrom @apertura/core
interface DetectionResult

Result of format detection.

format
FormatId
container
ContainerKind
confidence
"certain" | "probable" | "guess"
How much the detector can be trusted. `certain` — an unambiguous signature matched; `probable` — the container was identified and the concrete format was inferred from the extension or MIME type and still needs confirmation from the contents; `guess` — no signature matched and the decision rests on the file name alone.
reason
string
What led to the decision — useful when debugging third-party files.
DocumentMetadatafrom @apertura/core
interface DocumentMetadata

Metadata common to every format.

title?
string | undefined
author?
string | undefined
subject?
string | undefined
keywords?
readonly string[] | undefined
description?
string | undefined
producer?
string | undefined
The application that produced the file.
createdAt?
Date | undefined
modifiedAt?
Date | undefined
language?
string | undefined
Language of the main content, BCP 47.
custom?
Readonly<Record<string, string | number | boolean | Date>> | undefined
Format-specific fields that do not fit the common schema.
DocumentViewfrom @apertura/render
interface DocumentView

A live view of a document mounted into the DOM.

update
() => void
Re-render after the container was resized or settings changed.
destroy
() => void
Tear the view down and release resources. The container is left empty.
ExtractOptionsfrom @apertura/extract
interface ExtractOptions

What to do with the things that are not words. The defaults are chosen for the commonest use, which is feeding a language model, and they are not the conservative choices. `charts: 'data'` reads a chart out as the numbers it plots, because a chart is a table and leaving a hole where one was is how every other extractor in this space loses the content of a quarterly report. `headers: 'first'` drops the running head repeated on every page, because eighty repetitions of a company name is what poisons a retrieval index.

signal?
AbortSignal | undefined
concurrency?
number | undefined
How many handler calls may be in flight at once. Default 4. The handlers are the slow part — an OCR round trip is a second where everything else in this package is a microsecond — so the number that matters is this one, and it belongs to the caller who knows what is on the other end of it.
images?
"reference" | "omit" | "alt" | "dataUri" | undefined
`omit` drops images; `alt` keeps the block with its alt text and no bytes; `reference` adds the part name so the caller can fetch them; `dataUri` embeds them. Default `alt`.
charts?
"omit" | "title" | "data" | undefined
`data` reads the plotted values out. Default `data`.
diagrams?
"omit" | "nodes" | undefined
Default `nodes`: SmartArt comes out as the nesting it draws.
headers?
"all" | "first" | "omit" | undefined
Running heads and feet. Default `first`. `first` keeps one copy per section, which is where the information is; `all` keeps every repetition, which is what a fidelity-minded caller wants and a retrieval index does not.
comments?
"omit" | "annotate" | undefined
Default `annotate`: comments come out as annotations, not inline text.
notes?
"inline" | "omit" | "annotate" | undefined
Footnotes and endnotes. Default `annotate`.
revisions?
"final" | "original" | "markup" | undefined
Which side of a tracked change to take. Default `final`. `final` is the document as its last author left it; `original` is what it said before; `markup` keeps both, marked.
hiddenText?
boolean | undefined
Hidden text (`w:vanish`). Default false, which is what hiding it meant.
hiddenSheets?
boolean | undefined
Hidden worksheets. Default false: they hold the lookup tables.
formulas?
"both" | "value" | "formula" | undefined
Default `value`: the number as the sheet displays it, not the formula.
emptyCells?
boolean | undefined
Empty rows and columns inside a sheet's used range. Default false. Excel's idea of the used range is generous, and a sheet whose author once typed in `ZZ4000` reports four thousand rows of nothing.
headings?
"auto" | "none" | "style" | "outline" | HeadingRule | undefined
How a paragraph becomes a heading. Default `auto`. `auto` believes the style first, then `w:outlineLevel`, and does not guess from type size — a document whose author never used a heading style has no headings, and inventing them from font size produces a table of contents full of pull quotes.
styleMap?
readonly StyleRule[] | undefined
Map a named style onto an output element, the way mammoth does. The escape hatch for the house style nobody outside the company has heard of: `Zitat` is a blockquote, `Code Block` is code, `Untertitel` is a level two heading. Rules are tried in order and the first match wins.
onImage?
ImageHandler | undefined
onTable?
TableHandler | undefined
onChart?
ChartHandler | undefined
onMath?
MathHandler | undefined
transforms?
readonly Transform[] | undefined
Applied to the tree in order, after the walk and before serialisation.
HighlightHandlefrom @apertura/highlight
interface HighlightHandle
id
string
selectors
readonly Selector[]
resolvedBy
"locator" | "position" | "quote" | "native" | undefined
How the address was found: exact, portable, robust — or not at all.
confidence
number
fragments
readonly HighlightFragment[]
What is on the page right now. Empty while the pages are elsewhere.
data
unknown
remove
() => void
HighlightOptionsfrom @apertura/highlight
interface HighlightOptions extends HighlightStyle

Highlights, as state rather than as an operation. This is the design decision virtualisation forces, and it is not a detail. Only the pages near the viewport exist in the DOM — that is what lets a thousand-page document open as quickly as a five-page one — so "highlight this passage" cannot mean "find it and paint it". The passage is usually not there yet. So a highlight is a registered intention. The registry keeps it, paints what is currently on the page, and repaints when the page changes: a scroll, a zoom, a mount. Add a highlight on page four hundred of an unopened document and nothing visible happens until page four hundred arrives, at which point it is already there. The other thing that falls out of this: a highlight is a *list of fragments*, never a rectangle. A paragraph split between page three and page four gives two groups of rectangles on two pages, and an API that promised one would have to be rewritten the first time somebody highlighted a long quotation.

id?
string | undefined
A caller-chosen id. Adding twice with the same id replaces the first.
data?
unknown
Carried through to the caller; the registry does not read it.
HtmlOptionsfrom @apertura/extract
interface HtmlOptions

Semantic HTML: the structure, not the appearance. Not a renderer, and the distinction is the whole design. `@apertura/docx-view` reproduces what a document looks like — fonts, page boxes, measured line breaks. This produces what it *is*: headings that are headings, tables that are tables, a `<figure>` around a picture and its caption. There is no CSS and no colour, because the consumer is a language model, a search index, or a page that has its own stylesheet and does not want this one. Every element carries its address in `data-loc`, which is what makes an HTML extraction round-trip: a click in the rendered output can be turned back into a place in the document.

locators?
boolean | undefined
Write `data-loc` on every element that has an address. Default true.
figures?
boolean | undefined
`<figure>`/`<figcaption>` around images. Default true.
sections?
boolean | undefined
`<section>` per slide, sheet or document section. Default true.
wrap?
boolean | undefined
Wrap the output in `<article>`. Default false.
footnotes?
boolean | undefined
Footnotes as a `<section class="footnotes">` at the end. Default true.
withMap?
boolean | undefined
MarkdownOptionsfrom @apertura/extract
interface MarkdownOptions

Markdown, written properly. The bar is not "produces something a renderer accepts". Every library in this space clears that. The bar is that a person reading the output can tell what the document said, and a language model reading it does not have to guess — which means the table alignment survives, the nested list stays nested, a pipe inside a cell does not end the column, a paragraph starting with `1.` does not silently become a list, and a footnote is a footnote rather than a number floating in the middle of a sentence. Every one of those is a bug this had at some point.

tables?
"html" | "list" | "gfm" | undefined
`gfm` for pipe tables, `html` for a `<table>`, `list` for one line a row. `html` is not a cop-out: a pipe table cannot express a row span, and a merged cell rendered as a pipe table is silently wrong in a way nobody notices. `list` is for tables so wide that either of the others is unreadable — a workbook of forty columns, most often.
tableColumnLimit?
number | undefined
Widest table, in columns, still worth a pipe table. Default 12.
images?
"text" | "link" | "omit" | "alt" | undefined
`alt` writes `![alt]()`; `link` writes a real path; `omit` drops them; `text` writes just the alt text with no image syntax at all.
footnotes?
boolean | undefined
`[^1]` footnotes plus a section at the end. Default true.
comments?
boolean | undefined
Comments as footnotes too, marked with the author. Default false.
frontMatter?
boolean | undefined
A YAML block of the document metadata at the top. Default false.
sections?
"none" | "heading" | "rule" | undefined
`---` between sections, and a heading naming each. Default `heading`.
bullet?
"-" | "*" | "+" | undefined
`*` or `-`. Default `-`.
nativeMarkers?
boolean | undefined
Keep the document's own list markers instead of `1.` and `-`. On by default, and it is the right default: Word's `%1.%2` patterns produce `2.3.1`, which three levels of markdown nesting cannot express, and a numbered list that restarts partway down is invisible to a counter. The marker is `derived` text and anchors to the item.
math?
boolean | undefined
`$…$` for maths. Default true where a LaTeX form is available.
marks?
boolean | undefined
Emphasis, strikethrough and the rest. Default true.
withMap?
boolean | undefined
OpenOptionsfrom @apertura/core
interface OpenOptions

Options shared by every parser.

signal?
AbortSignal | undefined
Aborts parsing of large files.
tolerant?
boolean | undefined
Keep parsing when the file locally violates the specification. Defaults to `true`: real files produced by office suites break the standard routinely, and failing the whole document where a single paragraph could be dropped is a bad trade.
password?
string | undefined
Password for encrypted documents.
onProgress?
((fraction: number) => void) | undefined
Progress callback, 0..1.
ResolvedRangefrom @apertura/core
interface ResolvedRange

A resolution, and how much to trust it. `resolvedBy` is not decoration. An application that watches it can see its documents drifting — the day the exact selectors stop matching and everything falls through to quotes is the day somebody started editing the corpus — and it can see that before a user reports a highlight in the wrong place.

range
ModelRange
resolvedBy
"locator" | "position" | "quote" | "native"
confidence
number
1 for an exact match, lower for a fuzzy one.
SearchHit
interface SearchHit
text
string
selectors
readonly Selector[]
handle
HighlightHandle
SearchOptions
interface SearchOptions

Search and highlighting, over one mechanism rather than two. The temptation is to write a find box that walks the DOM looking for a string, which every viewer has, and which is wrong here for three reasons: it cannot see the pages that are not mounted, it finds the list numbers and page numbers the renderer computed, and what it produces is a DOM node rather than an address — so a hit cannot be stored, sent anywhere, or found again after a relayout. Instead the search runs over the extracted text, which the extractor can produce in the browser because it depends on nothing that is not there. A hit is a range of that text, which is an address, which is a highlight. The same path a chunk retrieved from a vector database takes. So `find` and `showChunk` are the same operation with different inputs, and neither had to be built twice.

caseSensitive?
boolean | undefined
wholeWord?
boolean | undefined
limit?
number | undefined
Stop after this many hits. Default 1000.
TextOptionsfrom @apertura/extract
interface TextOptions

Plain text: the output with nothing added. The one that has to be genuinely plain. It is what goes into a search index, a diff, a `grep`, and every pipeline whose next stage is not a markdown parser — and every character of markup in it is a false hit waiting to happen. So the only characters here that are not from the document are the separators between blocks, and a caller who wants none of those can say so.

separator?
string | undefined
Between blocks. Default `\n`.
sectionBreaks?
boolean | undefined
An extra newline between sections. Default true.
sectionLabels?
boolean | undefined
Name each section (`Slide 5`) before its content. Default true.
tables?
"tab" | "align" | "lines" | undefined
How a table row is written. Default `tab`. `tab` keeps the columns machine-readable — a row is still a record — and `align` pads them so a person can read the table in a terminal. `align` costs a second pass over the table to measure it.
markers?
boolean | undefined
Include list markers. Default true.
annotations?
boolean | undefined
Append footnote and comment text at the end. Default true.
withMap?
boolean | undefined
ViewerOptions
interface ViewerOptions extends ViewOptions, OpenOptions
registry?
ViewRegistry | undefined
The plugin set to use. Defaults to every supported format. Pass a custom registry to keep unused parsers out of the bundle.
renderOptions?
Record<string, unknown> | undefined
Extra options forwarded to the format renderer.
ViewerState
interface ViewerState
status
ViewerStatus
document
AperturaDocument | undefined
detection
DetectionResult | undefined
error
Error | undefined
progress
number
Parse progress, 0..1.
ViewOptionsfrom @apertura/render
interface ViewOptions
zoom?
number | undefined
Rendering scale, 1 means 100%.
fit?
"page" | "none" | "width" | undefined
How the page should be fitted into the container.
initialPage?
number | undefined
Initial page/sheet/slide, zero-based.
signal?
AbortSignal | undefined
ViewPluginfrom @apertura/render
interface ViewPlugin<TDocument extends AperturaDocument = AperturaDocument>

A renderer plugin: turns a parsed document into DOM.

format
FormatId
mount
(document: TDocument, container: HTMLElement, options?: ViewOptions) => Promise<DocumentView>

Type aliases

Blockfrom @apertura/extract
type Block = SectionBlock | HeadingBlock | ParagraphBlock | ListBlock | ListItemBlock | TableBlock | TableRowBlock | TableCellBlock | ImageBlock | ChartBlock | DiagramBlock | MathBlock | BlockquoteBlock | CodeBlock | BreakBlock
ByteSourceInputfrom @apertura/core
type ByteSourceInput = ByteSource | Blob | ArrayBuffer | Uint8Array | string

Everything Apertura can turn into a {@link ByteSource}.

DocumentKindfrom @apertura/core
type DocumentKind = 'text-document' /** A grid of cells: xlsx, ods, csv. */ | 'spreadsheet' /** A sequence of slides: pptx, odp. */ | 'presentation' /** Fixed page layout: pdf. */ | 'paged-document' /** A raster or vector image. */ | 'image'

Broad document category; determines which viewer applies.

FormatIdfrom @apertura/core
type FormatId = 'docx' | 'xlsx' | 'pptx' | 'doc' | 'xls' | 'ppt' | 'pdf' | 'odt' | 'ods' | 'odp' | 'txt' | 'md' | 'csv' | 'json' | 'xml' | 'html' | 'png' | 'jpeg' | 'gif' | 'webp' | 'bmp' | 'tiff' | 'svg' | 'unknown'

Identifier of a concrete file format. A string literal union rather than an enum: the values are part of the public API, get serialised to JSON, and are used as registry keys.

Locatorfrom @apertura/core
type Locator = string

The opaque wire form. Parse it with {@link parseLocator}.

Selectorfrom @apertura/core
type Selector = LocatorSelector | TextPositionSelector | TextQuoteSelector | SheetSelector | SlideSelector
ViewerStatus
type ViewerStatus = 'idle' | 'loading' | 'ready' | 'error'

Viewer state; UI wrappers render indicators from it.

Values

docxParserfrom @apertura/docx
docxParser: ParserPlugin<DocxDocument>

The docx parser plugin for {@link FormatRegistry }. `canOpen` looks inside the ZIP: the extension cannot be trusted, and every OOXML format shares one signature. Opening the package for the check is cheap — only the central directory and `[Content_Types].xml` are read — and the result is cached by the archive, so the subsequent `open` pays nothing twice.

docxViewfrom @apertura/docx-view
docxView: ViewPlugin<DocxDocument>

The docx renderer plugin for {@link FormatRegistry }.

HIGHLIGHT_CSSfrom @apertura/highlight
HIGHLIGHT_CSS: "\n.apertura-highlight {\n --apertura-highlight-fill: rgb(255 213 0 / 0.42);\n background: var(--apertura-highlight-fill);\n border-radius: 2px;\n}\n\n.apertura-highlight--active {\n --apertura-highlight-fill: rgb(255 145 0 / 0.55);\n outline: 1px solid rgb(255 145 0 / 0.9);\n}\n\n::highlight(apertura-find) {\n background-color: rgb(255 213 0 / 0.42);\n}\n\n::highlight(apertura-find-active) {\n background-color: rgb(255 145 0 / 0.6);\n}\n"

The default look, for a host that would rather not write any. Injected by the caller rather than by the registry: a viewer embedded in an application has a design system, and a package that put a stylesheet in the head without being asked would be fighting it. The colours are stated as custom properties so overriding one does not mean copying the rule. `::highlight()` accepts a short list of properties — colour, background, decoration and shadow — and nothing that affects layout, which is the point of it: a highlight cannot move the text it marks.

pptxParserfrom @apertura/pptx
pptxParser: ParserPlugin<PptxDocument>
pptxViewfrom @apertura/pptx-view
pptxView: ViewPlugin<PptxDocument>
xlsxParserfrom @apertura/xlsx
xlsxParser: ParserPlugin<XlsxDocument>
xlsxViewfrom @apertura/xlsx-view
xlsxView: ViewPlugin<XlsxDocument>