import { I as InlineAnnotation } from '../types-DnPOMbQV.js'; import { M as ManuscriptDialect } from '../manuscript-DeQQoLzm.js'; export { P as ParseManuscriptOptions, p as parseManuscript, a as parseManuscriptRuby } from '../manuscript-DeQQoLzm.js'; /** Represents a parsed EPUB book. */ interface EpubBook { /** Book title from OPF metadata. */ readonly title: string; /** Book author from OPF metadata. */ readonly author?: string; /** Ordered chapters from the spine. */ readonly chapters: readonly EpubChapter[]; /** Spine page progression direction from OPF, if declared. */ readonly pageProgressionDirection?: 'rtl' | 'ltr' | 'default'; } /** A single chapter extracted from an EPUB spine item. */ interface EpubChapter { /** Chapter title (from heading elements, if found). */ readonly title?: string; /** Paragraphs with extracted ruby annotations. */ readonly paragraphs: readonly AnnotatedParagraph[]; } /** * Paragraph kind shared by core, render, and EPUB modules. * * - `body`: normal `

` * - `heading`: `

`–`

` (`headingLevel` MUST be set) * - `blockquote`: indented quoted passage * - `sceneBreak`: a horizontal divider (e.g. `* * *`) * - `pre`: preformatted text (rarely used in vertical text) * - `figure`: image-with-caption block */ type ParagraphKind = 'body' | 'heading' | 'blockquote' | 'sceneBreak' | 'pre' | 'figure'; /** Editable paragraph block — text with inline annotations. */ interface EditableParagraphBlock { /** Discriminant of the {@link EditableBlock} union. */ kind: 'paragraph'; /** Stable identifier for incremental updates. */ id: string; /** Plain text (base text only, `` content stripped). */ text: string; /** Inline annotations (ruby, emphasis, tcy, em/strong, link, footnote). */ inlineAnnotations: readonly InlineAnnotation[]; /** Paragraph kind. Defaults to `'body'` when omitted. */ paragraphKind?: Exclude; /** Heading level (1–6); required when `paragraphKind: 'heading'`. */ headingLevel?: number; } /** Editable image block — a figure embedded in chapter flow. */ interface EditableImageBlock { /** Discriminant of the {@link EditableBlock} union. */ kind: 'image'; /** Stable identifier for incremental updates. */ id: string; /** Key into the chapter's `imageAssets` map. */ assetKey: string; /** Alternative text for the generated ``. */ alt?: string; /** Optional `
` text. */ caption?: string; /** Layout hint for the renderer. */ placement?: 'inline' | 'fullspread'; } /** * Block-level item in an editable chapter. Paragraphs (including headings, * blockquotes, scene breaks) and images are siblings rather than nesting. */ type EditableBlock = EditableParagraphBlock | EditableImageBlock; /** * Image asset attached to an editable chapter. Looked up by `assetKey` from * one or more {@link EditableImageBlock}s — multiple blocks may reference the * same asset (e.g. a recurring icon). */ interface EditableImageAsset { /** Filename used inside the EPUB ZIP (e.g. `figure-01.png`). */ filename: string; /** Existing ZIP path to preserve when the image came from the source EPUB. */ href?: string; /** @internal Original OPF manifest id for an existing image asset. */ manifestId?: string; /** @internal Original OPF-relative href, preserving percent encoding. */ manifestHref?: string; /** * Binary image data. Either this or {@link EditableImageAsset.url} must be * set. When both are present, `data` wins and `url` is ignored. */ data?: Uint8Array | ArrayBuffer; /** * External URL to fetch image bytes from at export time. Resolved by the * `assetResolver` provided to `EditableEpub.export()` (defaults to the * runtime `fetch`). Useful for keeping large image bytes off the client — * register only a URL during editing, then materialize the bytes once when * the EPUB is assembled. */ url?: string; /** Image media type. Defaults are inferred from the filename extension. */ mediaType?: string; } /** EPUB chapter with enough source metadata to be written back. */ interface EditableEpubChapter extends EpubChapter { /** ZIP path for the chapter XHTML document. */ href: string; /** Original XHTML source. Kept for inspection. */ originalXhtml: string; /** @internal Whether this chapter must be serialized instead of preserving `originalXhtml`. */ isDirty?: boolean; /** * Block-level chapter content. Paragraphs and images are siblings, ordered * by reading order. This is the canonical representation in v0.5+. */ blocks: EditableBlock[]; /** * Image assets used by this chapter. Keyed by `assetKey` (which is also the * preferred file basename inside the EPUB ZIP). */ imageAssets: Map; /** @internal Image ZIP paths discovered while parsing the source chapter. */ originalImageHrefs?: string[]; /** * @deprecated Mirror of `blocks` projected to {@link AnnotatedParagraph}s * for read-only compatibility with v0.4 callers. Regenerated on every * mutation. Editor APIs operate on `blocks`. */ paragraphs: AnnotatedParagraph[]; /** * @deprecated Replaced by `blocks`. Removal is deferred to a future major * release; no removal version is scheduled. */ paragraphRefs?: EditableParagraphRef[]; /** @deprecated Use {@link EditableEpubChapter.imageAssets} via `addImage`. */ images?: EditableEpubImage[]; } /** @deprecated Source element metadata is no longer used. */ interface EditableParagraphRef { index: number; tagName: string; } /** EPUB book with editable chapter metadata. */ interface EditableEpubBook extends Omit { /** Ordered editable chapters from the spine. */ chapters: EditableEpubChapter[]; /** @internal Original EPUB package data needed for export. */ packageData: { rootfilePath: string; opfDir: string; opfXml: string; files: Map; }; } /** * @deprecated v0.4 image-insertion shape. The v0.5 path is * `EditableEpub.addImage(chapterIndex, { filename, data, ... })`. Both * signatures are accepted by `addImage`. Removal of `EditableEpubImage` is * deferred to a future major release; no removal version is scheduled. */ interface EditableEpubImage { /** * Caller-supplied identifier carried along for bookkeeping. `addImage` * ignores it and derives the asset key from `href` instead, returning the key * it actually used. */ id?: string; /** ZIP path for the image file, relative to EPUB root. */ href: string; /** Image media type, e.g. `image/jpeg` or `image/png`. */ mediaType: string; /** Binary image data. */ data: Uint8Array | ArrayBuffer; /** Alternative text for the generated ``. */ alt?: string; /** Insert after this block index. Defaults to the end of the chapter. */ afterParagraph?: number; } /** A paragraph with its base text and inline annotations. */ interface AnnotatedParagraph { /** Plain text (base text only, `` content stripped). */ text: string; /** Inline annotations (ruby, emphasis, tcy, em/strong, link, footnote). */ inlineAnnotations: readonly InlineAnnotation[]; /** Heading level (1–6) if this paragraph originated from an h1–h6 element. */ headingLevel?: number; } /** * Paragraph an editor UI currently targets, addressed by chapter index and * paragraph index inside that chapter. */ interface EditableEpubSelection { /** Zero-based chapter index. */ chapter: number; /** Zero-based paragraph index inside that chapter. */ paragraph: number; } /** * Deep-copies an editable book so preview rendering and export-only transforms * (watermarking, for instance) can never reach the document the editor owns. * * This is the single clone implementation in the package family: the React and * Vue editors call it rather than carrying their own copy, so a chapter field * added to {@link EditableEpubChapter} reaches every surface at once. Each * chapter is rebuilt by spreading the source first and overriding only the * mutable containers, which is what makes a new field carried over without * touching this function. * * Every mutable field is copied — down to individual inline annotations — * matching the fidelity of the editor's own undo/redo snapshots. Binary payloads * (`imageAssets` entries and `packageData.files` buffers) are shared by * reference: they are treated as immutable blobs and copying them would double * the memory a loaded book occupies. * * @param book - Book to copy; never mutated. * @returns An independent book whose chapters can be edited freely. */ declare function cloneEditableEpubBook(book: EditableEpubBook): EditableEpubBook; /** * Confines a selection to the paragraphs a book actually has. * * Non-integer and non-finite indices are accepted so a UI can hand over raw * input: they are truncated toward zero, then clamped. A book with no chapters, * or a chapter with no paragraphs, resolves to index `0` so the selection stays * a valid pair rather than becoming `null`. * * @param book - Book the selection points into, or `null` before one is loaded. * @param selection - Requested selection. * @returns A selection that addresses an existing paragraph whenever one exists. */ declare function clampEditableEpubSelection(book: EditableEpubBook | null, selection: EditableEpubSelection): EditableEpubSelection; /** Resource limits applied while opening an untrusted EPUB archive. */ interface EpubParseLimits { /** Largest accepted compressed input, in bytes. @defaultValue 100 MiB */ maxInputBytes: number; /** Largest number of non-directory ZIP entries. @defaultValue 10,000 */ maxEntries: number; /** Largest allowed expanded entry, in bytes. @defaultValue 50 MiB */ maxEntryBytes: number; /** Largest allowed total expanded archive, in bytes. @defaultValue 200 MiB */ maxTotalBytes: number; /** Largest allowed per-entry expansion ratio. @defaultValue 1,000 */ maxCompressionRatio: number; } /** Defaults for safely opening user-provided EPUB archives. */ declare const DEFAULT_EPUB_PARSE_LIMITS: Readonly; /** Options shared by read-only and editable EPUB import APIs. */ interface EpubParseOptions { /** Override one or more archive resource limits for a trusted environment. */ limits?: Partial; } /** * EPUB 3 package metadata. Most fields map directly onto `` and * `` entries in `package.opf`. * * `author` is kept as a convenience shortcut: when present it is folded into * `creators[0]` with `role: 'aut'` during export. Prefer `creators` for new * code. */ interface EpubProjectMetadata { /** Book title. Required. */ title: string; /** Optional subtitle (``). */ subtitle?: string; /** Long-form description (``). */ description?: string; /** BCP-47 language tag (defaults to `'ja'`). */ language?: string; /** Unique identifier (``). Auto-generated UUID if omitted. */ identifier?: string; /** Publisher name (``). */ publisher?: string; /** Rights statement (``). */ rights?: string; /** Publication date (``). */ date?: Date; /** Last-modified date (``). Defaults to now. */ modified?: Date; /** * Primary creators. Folded into `` entries with optional * `opf:role` and `opf:file-as` refinements. */ creators?: EpubContributor[]; /** Additional contributors (``). */ contributors?: EpubContributor[]; /** Subject keywords / tags / genres (``). */ subjects?: string[]; /** calibre series metadata. */ series?: { name: string; index?: number; }; /** EPUB 3 collection metadata (``). */ collections?: EpubCollection[]; /** * Legacy single-author shortcut. Mapped to `creators[0]` with role `'aut'` * during export. Prefer `creators` in new code. */ author?: string; } /** Person responsible for the work — author, illustrator, translator, etc. */ interface EpubContributor { /** Display name. */ name: string; /** * MARC relator role code (`'aut' | 'trl' | 'ill' | 'edt' | 'ann' | …`) or a * free-form value preserved as-is. */ role?: string; /** Sort-by name (`opf:file-as`). */ fileAs?: string; } /** EPUB 3 collection (series or set). */ interface EpubCollection { /** Collection name, emitted as the `belongs-to-collection` meta value. */ name: string; /** Collection kind refinement (`collection-type`). @defaultValue 'series' */ type?: 'series' | 'set'; /** Position within the collection. */ index?: number; } /** A chapter authored as manuscript notation, as accepted by {@link EpubProject.addChapter}. */ interface ManuscriptChapterInput { /** * Preferred manifest / section id. Sanitized to an XML-safe id and suffixed * when it collides with a reserved or already-used id, so the value stored on * the project may differ from the one passed here. Defaults to * `chapter-`. */ id?: string; /** Chapter title. Used for the chapter `

`, its `` and its nav entry. */ title: string; /** * Manuscript notation source. Split into paragraphs on blank lines and parsed * with the project's {@link EpubProject.dialect} at export time, so ruby and * the other inline notations become real EPUB markup rather than literal text. */ body: string; } /** A binary file packaged alongside the chapters — cover, inline image, extra stylesheet. */ interface EpubProjectAsset { /** * Preferred manifest item id. Sanitized and de-duplicated like * {@link ManuscriptChapterInput.id}; defaults to an id derived from `href`. */ id?: string; /** * Destination path inside the EPUB ZIP, relative to the archive root * (e.g. `'OPS/Images/cover.jpg'`). Must be a clean relative file path: * {@link EpubProject.addAsset} and {@link EpubProject.setCover} throw on an * absolute path, a URI scheme, a `..` segment, a `#`/`?`/`\` character or a * trailing slash. A path that collides with another asset or with a document * `export()` generates is renamed, so read the stored href back from the value * `addAsset()` returns rather than assuming this one was kept. */ href: string; /** * OPF media type. Inferred from the `href` extension when omitted, falling * back to `application/octet-stream` for unknown extensions. */ mediaType?: string; /** * Binary asset data. Either this or {@link EpubProjectAsset.url} must be * set. When both are present, `data` wins. */ data?: Uint8Array | ArrayBuffer; /** * External URL fetched at export time via the * {@link EpubExportOptions.assetResolver} (or the runtime `fetch` when no * resolver is supplied). */ url?: string; /** * OPF manifest `properties` attribute. {@link EpubProject.setCover} sets * `'cover-image'`, which also marks the asset as the one the cover `<meta>` * entry points at and exempts it from unreferenced-asset cleanup. */ properties?: string; } /** Constructor options for {@link EpubProject}. */ interface EpubProjectOptions { /** Package metadata. Only `title` is required; the rest is defaulted at export. */ metadata: EpubProjectMetadata; /** * Initial chapters, appended in order through {@link EpubProject.addChapter} * — so their ids go through the same sanitizing and de-duplication. */ chapters?: ManuscriptChapterInput[]; /** Manuscript notation dialect used when serializing chapters. @defaultValue `'mejiro'` */ dialect?: ManuscriptDialect; /** * Cover image, registered through {@link EpubProject.setCover} after * `chapters`. Its href defaults to `'OPS/Images/cover.jpg'` when empty. */ cover?: EpubProjectAsset; /** * CSS written to `OPS/Styles/style.css` and linked from every generated * document. Defaults to a minimal vertical-writing stylesheet. */ stylesheet?: string; /** Spine page progression direction. @defaultValue 'rtl' for vertical Japanese books. */ pageProgressionDirection?: 'rtl' | 'ltr' | 'default'; /** Include a title page before the first manuscript chapter. @defaultValue true */ includeTitlePage?: boolean; /** Place the book title at the beginning of the first chapter. @defaultValue false */ includeTitleInFirstChapter?: boolean; } /** * A chapter as it is stored on a project — the resolved form of * {@link ManuscriptChapterInput}, with the manifest id already assigned and * de-duplicated. Element type of {@link EpubProject.chapters}. */ interface ProjectChapter { /** * Manifest / section id in effect, derived from the input id. Assigned once * at insert time and never rewritten, so reordering chapters does not * renumber them. */ id: string; /** Chapter title, as given. */ title: string; /** Manuscript notation source, as given. */ body: string; } /** Builds a new EPUB package from manuscript chapters and assets. */ declare class EpubProject { /** * Package metadata with the defaults already applied: `language` falls back to * `'ja'`, a blank or missing `identifier` is replaced by a fresh * `urn:uuid:` value, and `modified` defaults to construction time. The object * itself stays mutable, so metadata can be edited in place after construction. */ readonly metadata: EpubProjectMetadata; /** * Chapters in spine order, each carrying the manifest id assigned at insert * time. Edit through {@link EpubProject.addChapter}, * {@link EpubProject.updateChapter}, {@link EpubProject.removeChapter} and * {@link EpubProject.reorderChapters} so ids stay unique and inline image * assets stay in sync with the bodies that reference them. */ readonly chapters: ProjectChapter[]; /** * Manifest assets in insertion order, with the resolved id, href and media * type rather than the values originally passed in. A cover set through * {@link EpubProject.setCover} is always the last entry. */ readonly assets: EpubProjectAsset[]; /** Whether `export()` writes a generated title page ahead of the chapters. */ readonly includeTitlePage: boolean; /** * Whether the first chapter opens with the book title as its `<h1>`, keeping * its own title only as a hidden `chapter-title` span. */ readonly includeTitleInFirstChapter: boolean; /** Value of the spine's `page-progression-direction` attribute. */ readonly pageProgressionDirection: 'rtl' | 'ltr' | 'default'; /** Manuscript notation dialect chapter bodies are parsed with during export. */ readonly dialect: ManuscriptDialect; /** CSS written to `OPS/Styles/style.css`. Replaceable at any point before export. */ stylesheet: string; /** * Applies the {@link EpubProjectOptions} defaults, then registers `chapters` * and `cover` through {@link EpubProject.addChapter} and * {@link EpubProject.setCover} — so an invalid cover href throws here rather * than at export time. */ constructor(options: EpubProjectOptions); /** * Reads as a named constructor at call sites that build a book straight from * manuscript chapters. Equivalent to `new EpubProject(options)` in every * respect. */ static fromManuscript(options: EpubProjectOptions): EpubProject; /** * Appends a chapter to the end of the spine. Its id is sanitized to an * XML-safe manifest id and suffixed when it collides with a reserved id or one * already in use, so the stored id may differ from `chapter.id`. */ addChapter(chapter: ManuscriptChapterInput): void; /** * Updates a chapter's title and/or body. Pass a partial patch — omitted * fields keep their previous value. Inline image assets the new body no * longer references are dropped from the project, exactly as * {@link EpubProject.removeChapter} drops them. */ updateChapter(index: number, patch: Partial<Omit<ManuscriptChapterInput, 'id'>>): void; /** Removes a chapter by index. */ removeChapter(index: number): void; /** * Moves a chapter from `from` to `to`. An out-of-range `from` selects no * chapter and leaves the list untouched; `to` is clamped to the chapter list * bounds. Drag-and-drop reorder UIs routinely emit both, so neither is an * error. */ reorderChapters(from: number, to: number): void; /** * Inserts an inline image asset and embeds an internal manuscript reference * in the chapter body at `atParagraphIndex`, counted in the same paragraph * space the chapter XHTML pass and `manuscriptToEpubBook()` use. The marker is * rendered as a `<figure>` during the chapter XHTML pass. */ addInlineImage(chapterIndex: number, atParagraphIndex: number, asset: EpubProjectAsset & { alt?: string; }): void; /** * Registers `asset` as the cover image, replacing any previous one. The href * defaults to `'OPS/Images/cover.jpg'` when empty and is validated like every * other asset href, so an absolute path or one escaping the archive throws. * The stored asset is marked `properties: 'cover-image'` and moved to the end * of {@link EpubProject.assets}, which is what makes `export()` emit the cover * `<meta>` entry for it. */ setCover(asset: EpubProjectAsset): void; /** * Adds a manifest asset and returns the stored copy, which carries the * resolved id, href and media type. The href is renamed with a `-2`, `-3`, … * suffix when it collides with an existing asset or with a document * `export()` generates, so link the returned `href` rather than the one passed * in. * * @throws If `asset.href` is not a clean relative path inside the archive. */ addAsset(asset: EpubProjectAsset): EpubProjectAsset; private removeUnreferencedAssets; /** * Serializes the project into an EPUB 3 ZIP: `mimetype` first and * uncompressed, then the container, the OPF package, the nav document, the * stylesheet, the optional title page, one XHTML document per chapter, and * finally every asset. * * Asset bytes are taken from {@link EpubProjectAsset.data}, or fetched from * {@link EpubProjectAsset.url} through `options.assetResolver` (the runtime * `fetch` when no resolver is given). `options.signal` is checked between * chapters and assets as well as during compression, and `options.onProgress` * reports the `'serialize'` phase per chapter and the `'zip'` phase from JSZip. * * @throws If the project has no chapters, if an asset cannot be resolved, or * with an `AbortError` when `options.signal` is triggered. */ export(options?: EpubExportOptions): Promise<ArrayBuffer>; } /** Reusable EPUB editing session with read/modify/write-back support. */ declare class EditableEpub { /** * The live document model, including the package metadata needed to write the * EPUB back out. Exposed for reading and for handing to a renderer; mutating * it directly bypasses the undo history, so route edits through the session's * methods instead. */ readonly book: EditableEpubBook; private undoStack; private redoStack; private historyLimit; private txnDepth; private pendingEntry; private constructor(); /** * Groups a sequence of edits into one history entry. Nested calls are * folded into the outermost transaction. The callback is run synchronously. * Throws inside the callback rewind the buffered changes. */ transaction<T>(fn: () => T): T; /** Reverts the last committed change (or transaction). */ undo(): boolean; /** Re-applies the change most recently reverted by `undo`. */ redo(): boolean; /** Snapshot of the current undo/redo state. */ get history(): { canUndo: boolean; canRedo: boolean; depth: number; redoDepth: number; }; /** * Records the current state of `chapterIndex` into the active history * entry. Called by every mutating method before it changes a chapter. */ private recordChapterChange; private commitHistoryEntry; /** Builds an entry mirroring `template` but capturing the *current* state. */ private captureEntry; /** Writes an entry's chapter state back onto the live book. */ private restoreEntry; /** * Parses an EPUB and starts an editing session. * * Requires host DOM globals (`DOMParser`, `XMLSerializer`, `Node`). Node and * SSR runtimes must register a DOM implementation (happy-dom, jsdom) first. */ static load(data: ArrayBuffer, options?: EpubParseOptions): Promise<EditableEpub>; /** Book title read from the package metadata. */ get title(): string; /** Primary creator from the package metadata, or undefined when absent. */ get author(): string | undefined; /** * Chapters in spine order. The live array, not a copy — it reflects * subsequent edits, and splicing it directly skips the undo history. */ get chapters(): EditableEpubChapter[]; /** * Updates one paragraph's text and optional inline annotations. * * `paragraphIndex` is the position in the chapter's paragraph projection * (excluding image blocks). Image blocks remain untouched. * * When `text` changes without new `inlineAnnotations`, the existing * annotations are re-anchored onto the new text: each one either keeps * covering exactly the same base characters or is dropped. Annotations * passed in explicitly are indexed into the new text, and any that fall * outside it are dropped. Either way the block is left with annotations * that the layout engine can consume. */ updateParagraph(chapterIndex: number, paragraphIndex: number, next: Partial<AnnotatedParagraph>): void; /** * Adds or replaces inline annotations for one paragraph. Annotations that * do not fall inside the paragraph's current text are dropped. */ setInlineAnnotations(chapterIndex: number, paragraphIndex: number, inlineAnnotations: readonly InlineAnnotation[]): void; /** * Inserts a new paragraph block. Returns the generated `blockId`. * * `atIndex` is the position in the chapter's `blocks` array. Pass * `chapter.blocks.length` to append. */ insertParagraph(chapterIndex: number, atIndex: number, paragraph: Omit<EditableParagraphBlock, 'kind' | 'id'>): string; /** Removes a block (paragraph or image) by id. */ deleteBlock(chapterIndex: number, blockId: string): void; /** * Splits a paragraph block at `charIndex` (codepoint index in `text`). * Inline annotations that straddle the split are dropped. */ splitParagraph(chapterIndex: number, blockId: string, charIndex: number): [string, string]; /** * Merges two adjacent paragraph blocks. `leftId` must immediately precede * `rightId`. Returns the surviving (left) block's id. */ mergeParagraphs(chapterIndex: number, leftId: string, rightId: string): string; /** Moves a block to a new index. */ moveBlock(chapterIndex: number, blockId: string, toIndex: number): void; /** * Adds an image asset and inserts an image block referencing it. Accepts * both the new v0.5 shape (`{ filename, data, ... }`) and the v0.4 shape * (`{ href, mediaType, ... }`). * * Returns the generated `assetKey`. */ addImage(chapterIndex: number, image: AddImageInput | EditableEpubImage): string; /** Removes an image block (and its asset, if no other block references it). */ removeImage(chapterIndex: number, blockIdOrAssetKey: string): void; /** Updates an image block's alt text, caption, or placement. */ updateImage(chapterIndex: number, blockId: string, patch: Partial<Omit<EditableImageBlock, 'kind' | 'id' | 'assetKey'>>): void; /** Shortcut for {@link EditableEpub.updateImage} that only sets the caption. */ setImageCaption(chapterIndex: number, blockId: string, caption: string | undefined): void; /** * Exports the current edited EPUB as an ArrayBuffer. * * Book state is captured synchronously on entry, so an edit made while the * export is still awaiting asset bytes lands in the next export, never * part-way through this one. */ export(options?: EpubExportOptions): Promise<ArrayBuffer>; } /** * Asset handed to an {@link AssetResolver}. * * Both export paths route through the same resolver, so the value is either a * chapter image asset from `EditableEpub.export()` or a packaged project asset * from `EpubProject.export()`. The fields a resolver normally reads — `url`, * `mediaType` and `data` — are common to both and need no narrowing; the naming * fields differ, so narrow with `'filename' in asset` (an * {@link EditableImageAsset}) versus `'href' in asset` (an * {@link EpubProjectAsset}) when the source path matters. */ type AssetResolverAsset = EditableImageAsset | EpubProjectAsset; /** * Request passed to {@link EpubExportOptions.assetResolver}. The resolver * returns the bytes that should be embedded for `asset` inside the exported * EPUB ZIP. */ interface AssetResolverRequest { /** * Identifier of the asset being resolved: the key inside the chapter's * `imageAssets` map on the {@link EditableEpub} path, and the ZIP href on the * `EpubProject` path. */ assetKey: string; /** The asset to resolve. */ asset: AssetResolverAsset; /** External URL declared on the asset (mirrors `asset.url`). */ url: string; /** Mirror of the export `AbortSignal`, when one was passed. */ signal?: AbortSignal; } /** * Resolves an asset to its bytes at export time. Called once per * {@link AssetResolverAsset} that declares a `url` and has no inline `data`. * Throw to abort export; return a `Uint8Array` or `ArrayBuffer` containing * the asset bytes. */ type AssetResolver = (request: AssetResolverRequest) => Promise<Uint8Array | ArrayBuffer> | Uint8Array | ArrayBuffer; /** Options shared by EPUB export entry points. */ interface EpubExportOptions { /** * Notifies progress during export. * * - `phase: 'serialize'` — chapter XHTML rebuild and asset staging (including * any asset URL resolution). * - `phase: 'zip'` — DEFLATE compression. `ratio` mirrors JSZip's * `metadata.percent / 100`. */ onProgress?: (phase: 'serialize' | 'zip', ratio: number) => void; /** AbortSignal — when triggered, export rejects with `AbortError`. */ signal?: AbortSignal; /** * Resolves URL-only image assets ({@link EditableImageAsset.url} set, * `data` unset) into bytes at export time. When omitted, a default resolver * uses the runtime `fetch` with the export `signal`. Override to inject * auth headers, pull from non-HTTP sources (IndexedDB, S3 SDK), or short- * circuit with a cached buffer. */ assetResolver?: AssetResolver; } /** Common fields of the {@link AddImageInput} variants. */ interface AddImageInputCommon { /** * Filename used inside the EPUB ZIP (e.g. `figure-01.png`). The returned * `assetKey` starts from this basename and is uniqued when needed. The image * is written to `OPS/Images/<assetKey>` by default. */ filename: string; /** * OPF media type for the manifest entry. Inferred from the `filename` * extension when omitted. */ mediaType?: string; /** Alternative text for the generated `<img>`. */ alt?: string; /** Text for the generated `<figcaption>`. Omitted produces no caption element. */ caption?: string; /** * Layout hint stored verbatim on the resulting block for renderers to act on; * it does not change the exported markup. Left unset when omitted, so the * renderer's own default applies. */ placement?: 'inline' | 'fullspread'; /** * Insert the block immediately after this block id. Defaults to the end of * the chapter; an id no block carries throws. */ afterBlockId?: string; } /** v0.5 shape for {@link EditableEpub.addImage} — inline bytes variant. */ interface AddImageInputBytes extends AddImageInputCommon { /** Binary image data. */ data: Uint8Array | ArrayBuffer; /** Never set on this variant — it is what makes the union discriminate. */ url?: never; } /** v0.5 shape for {@link EditableEpub.addImage} — external URL variant. */ interface AddImageInputUrl extends AddImageInputCommon { /** * External URL. Bytes are fetched at export time via the * {@link EpubExportOptions.assetResolver} (or the runtime `fetch`). */ url: string; /** Never set on this variant — it is what makes the union discriminate. */ data?: never; } /** * v0.5 input shape for {@link EditableEpub.addImage}. Pick the `data` variant * to embed bytes immediately, or the `url` variant to defer fetching until * export. */ type AddImageInput = AddImageInputBytes | AddImageInputUrl; /** * Parses an EPUB while retaining enough package metadata to export edits back * into an EPUB file. * * Requires host DOM globals (`DOMParser`, `XMLSerializer`, `Node`). Node and * SSR runtimes must register a DOM implementation (happy-dom, jsdom) first. */ declare function parseEditableEpub(data: ArrayBuffer, options?: EpubParseOptions): Promise<EditableEpub>; /** * Updates one paragraph's text and optional inline annotations. * * Mirrors {@link EditableEpub.updateParagraph}, including its re-anchoring of * existing annotations across a text-only update. */ declare function updateEpubParagraph(book: EditableEpubBook, chapterIndex: number, paragraphIndex: number, next: Partial<AnnotatedParagraph>): void; /** * Adds or replaces inline annotations for one paragraph. Annotations that do * not fall inside the paragraph's current text are dropped. */ declare function setEpubInlineAnnotations(book: EditableEpubBook, chapterIndex: number, paragraphIndex: number, inlineAnnotations: readonly InlineAnnotation[]): void; /** * Queues an image asset and inserts a corresponding image block. * * Accepts both the v0.5 `{ filename, ... }` shape and the v0.4 * `{ href, mediaType, afterParagraph }` shape (deprecated). Returns the * `assetKey` used to reference the asset. */ declare function addEpubChapterImage(book: EditableEpubBook, chapterIndex: number, image: AddImageInput | EditableEpubImage): string; /** * Exports an edited EPUB. Existing files are preserved; edited chapter XHTML, * added image assets, and OPF manifest entries are written back. * * Book state is captured synchronously on entry, so one call always * serializes one consistent snapshot of the book. */ declare function exportEditableEpub(book: EditableEpub | EditableEpubBook, options?: EpubExportOptions): Promise<ArrayBuffer>; /** Input shape for {@link manuscriptToEpubBook}. */ interface ManuscriptSourceChapter { /** Optional source id for callers; the synthesized `EpubBook` shape does not expose it. */ id?: string; /** Chapter title. Emitted as an `h1` paragraph at the top of the chapter. */ title: string; /** Raw manuscript body. Blank lines separate paragraphs. */ body: string; } /** Options for {@link manuscriptToEpubBook}. */ interface ManuscriptToEpubBookOptions { /** Manuscript notation dialect. @defaultValue `'mejiro'` */ dialect?: ManuscriptDialect; /** Book title surfaced via {@link EpubBook.title}. @defaultValue `''` */ title?: string; /** Book author surfaced via {@link EpubBook.author}. */ author?: string; } /** * Synthesizes an {@link EpubBook} from manuscript chapters, skipping the EPUB * ZIP round-trip entirely. Designed for live preview surfaces and custom * manuscript editors that want to feed `MejiroReader` (or any code that * consumes `EpubBook`) without exporting to a real EPUB file first. * * Each chapter body is split into paragraphs on blank lines and run through * {@link parseManuscript}, so ruby / emphasis / TCY / em / strong / link / * footnote annotations are resolved exactly as `EpubProject.export()` would * resolve them. Internal `[[mejiro-image:...]]` blocks are recognized and * skipped, matching the current read-only `EpubBook` parser surface where * figures do not appear as text paragraphs. * * @example * ```ts * const book = manuscriptToEpubBook(draft.chapters, { dialect: 'mejiro' }); * <MejiroReader epub={book} /> * ``` */ declare function manuscriptToEpubBook(chapters: readonly ManuscriptSourceChapter[], options?: ManuscriptToEpubBookOptions): EpubBook; /** * Parses an EPUB file from an ArrayBuffer. * * Reads the ZIP structure, extracts OPF metadata (title, author), * follows the spine order, and extracts ruby-annotated paragraphs * from each XHTML content document. * * Requires host DOM globals (`DOMParser`, `XMLSerializer`, `Node`). Node and * SSR runtimes must register a DOM implementation (happy-dom, jsdom) first. * * @param data - EPUB file contents as ArrayBuffer. * @param options - Resource limits applied while reading the archive. * @returns Parsed book with chapters and ruby annotations. * @throws When the host has no DOM implementation, or the archive is not a readable EPUB. */ declare function parseEpub(data: ArrayBuffer, options?: EpubParseOptions): Promise<EpubBook>; /** * Extracts paragraphs with ruby annotations from an XHTML string. * * Walks the DOM tree, collecting base text and recording ruby annotations * with character-level indices. `<rt>` content is captured as ruby text * but excluded from the base text. `<rp>` elements are ignored. * * Paragraph text is returned in NFC, and every annotation index is a code * point offset into that NFC text. * * @param xhtml - XHTML content string. * @returns Array of annotated paragraphs. */ declare function extractRubyContent(xhtml: string): AnnotatedParagraph[]; export { type AddImageInput, type AddImageInputBytes, type AddImageInputCommon, type AddImageInputUrl, type AnnotatedParagraph, type AssetResolver, type AssetResolverAsset, type AssetResolverRequest, DEFAULT_EPUB_PARSE_LIMITS, type EditableBlock, EditableEpub, type EditableEpubBook, type EditableEpubChapter, type EditableEpubImage, type EditableEpubSelection, type EditableImageAsset, type EditableImageBlock, type EditableParagraphBlock, type EpubBook, type EpubChapter, type EpubCollection, type EpubContributor, type EpubExportOptions, type EpubParseLimits, type EpubParseOptions, EpubProject, type EpubProjectAsset, type EpubProjectMetadata, type EpubProjectOptions, type ManuscriptChapterInput, ManuscriptDialect, type ManuscriptSourceChapter, type ManuscriptToEpubBookOptions, type ParagraphKind, type ProjectChapter, addEpubChapterImage, clampEditableEpubSelection, cloneEditableEpubBook, exportEditableEpub, extractRubyContent, manuscriptToEpubBook, parseEditableEpub, parseEpub, setEpubInlineAnnotations, updateEpubParagraph };