@quillmark/wasm 0.92.1 → 0.94.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1099 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /**
5
+ * A path to a value nested inside a field `value`: `string` keys and
6
+ * `number` array indices, e.g. `["addr", "street"]` or `["recipients", 0, "name"]`.
7
+ */
8
+ export type PathStep = string | number;
9
+
10
+ /** A field or comment entry in a `Card.payloadItems` list. */
11
+ export type PayloadItem =
12
+ | {
13
+ type: "field";
14
+ key: string;
15
+ value: unknown;
16
+ fill?: boolean;
17
+ /**
18
+ * Paths to `!must_fill` markers nested *inside* `value` (the `value`
19
+ * projection itself is fill-free). Absent when the field has no nested
20
+ * placeholders. Preserved across `pushCard` / `makeCard`.
21
+ */
22
+ nestedFills?: PathStep[][];
23
+ }
24
+ | { type: "comment"; text: string; inline?: boolean };
25
+
26
+ /**
27
+ * A single card block, as read back from a document: returned by
28
+ * `Document.main` / `Document.cards` / `Document.removeCard` / `Quill.seedCard`
29
+ * / `Document.makeCard`. To feed a card *into* a document use `CardInput`
30
+ * (which `pushCard` / `insertCard` accept); every `Card` is a valid `CardInput`,
31
+ * so a card read from one document pushes straight into another.
32
+ *
33
+ * `$` system entries are hoisted to named fields: `kind` (the `$kind`, empty
34
+ * string when none), optional `quill` (the `$quill` `name@version`, main card
35
+ * only), optional `id` (`$id`), optional `ext` (`$ext`), and optional `seed`
36
+ * (the `$seed` per-kind overlay map, main card only). `payloadItems` carries
37
+ * user fields and comments in order.
38
+ */
39
+ export interface Card {
40
+ kind: string;
41
+ quill?: string;
42
+ id?: string;
43
+ ext?: Record<string, unknown>;
44
+ seed?: Record<string, unknown>;
45
+ payloadItems: PayloadItem[];
46
+ /**
47
+ * The card body as canonical `RichText` — the source-of-truth content model.
48
+ * Always this corpus shape on read, never a markdown string. For the markdown
49
+ * projection call the codec `exportMarkdown(card.body)`. Write a body back
50
+ * with `doc.install(addr, rt)` / `doc.revise(addr, md)`, or via `CardInput.body`.
51
+ */
52
+ body: RichText;
53
+ }
54
+
55
+ /**
56
+ * A card written *into* a document — the input twin of `Card`, accepted by
57
+ * `Document.pushCard` / `Document.insertCard`. Like `Card` but `body` also
58
+ * takes a markdown `string` (imported to the corpus, so a markdown / LLM writer
59
+ * needn't build the `RichText` shape), and every field but `kind` is optional —
60
+ * an absent field defaults (no payload items, an empty body). Write one inline
61
+ * (`{ kind, body }`) or build it with `Document.makeCard`.
62
+ */
63
+ export interface CardInput {
64
+ kind: string;
65
+ quill?: string;
66
+ id?: string;
67
+ ext?: Record<string, unknown>;
68
+ seed?: Record<string, unknown>;
69
+ payloadItems?: PayloadItem[];
70
+ body?: RichText | string;
71
+ }
72
+
73
+ /**
74
+ * Canonical richtext corpus — the content model for a card body (and richtext
75
+ * fields). One text sequence over a single coordinate space (Unicode scalar
76
+ * values): `text` plus line attributes, anchored `marks`, and embedded
77
+ * `islands`. Every edit is a splice; markdown is a projection, not the model.
78
+ * Mirrors `quillmark_richtext::serial`'s canonical JSON encoding.
79
+ */
80
+ export interface RichText {
81
+ text: string;
82
+ lines: RichTextLine[];
83
+ marks: RichTextMark[];
84
+ islands: RichTextIsland[];
85
+ }
86
+
87
+ /** One `\n`-separated segment of `RichText.text`, in order. */
88
+ export type RichTextLine = {
89
+ containers: RichTextContainer[];
90
+ /** A within-block hard line break rather than a new block. Omitted (false) in the common case. */
91
+ continues?: boolean;
92
+ } & (
93
+ | { kind: "para" }
94
+ | { kind: "heading"; level: number }
95
+ | { kind: "code"; lang?: string }
96
+ | { kind: "island" }
97
+ | { kind: "rule" }
98
+ );
99
+
100
+ /** An ancestor block a line nests inside, outermost first. */
101
+ export type RichTextContainer =
102
+ | { container: "list_item"; ordered: boolean; start: number; ordinal: number }
103
+ | { container: "quote" };
104
+
105
+ /** A mark over char range `[start, end)` into `RichText.text`. */
106
+ export type RichTextMark = { start: number; end: number } & (
107
+ | { type: "strong" | "emph" | "underline" | "strike" | "code" }
108
+ | { type: "link"; url: string }
109
+ | { type: "anchor"; id: string }
110
+ | { type: string; attrs: unknown }
111
+ );
112
+
113
+ /** A structured object (table, figure, …) occupying one island slot in `RichText.text`. */
114
+ export interface RichTextIsland {
115
+ id: string;
116
+ type: string;
117
+ props: unknown;
118
+ /** How faithfully the markdown projection can carry this island. */
119
+ loss: "lossless" | "degraded" | "unrepresentable";
120
+ }
121
+
122
+ /**
123
+ * A richtext write address. An absent `field` targets the card body; an absent
124
+ * `card` targets the main card. `{}` is the main-card body; `{ card: 2 }` the
125
+ * body of the composable card at index 2; `{ field: "intro" }` the main card's
126
+ * `intro` richtext field; `{ card: 2, field: "intro" }` a card field.
127
+ */
128
+ export interface Addr {
129
+ card?: number;
130
+ field?: string;
131
+ }
132
+
133
+ /**
134
+ * A text-splice change set over the USV corpus (CodeMirror `ChangeSet`
135
+ * semantics) — plain, structured-clone-able data. Returned by `revise` and by
136
+ * the `rebase` codec; map a stored position through it with `mapPos`.
137
+ */
138
+ export interface Delta {
139
+ ops: ({ retain: number } | { insert: string } | { delete: number })[];
140
+ }
141
+
142
+ /** Which side of a same-position insertion `mapPos` lands a point on. */
143
+ export type Assoc = "before" | "after";
144
+
145
+ /**
146
+ * A mark edit in post-text-delta coordinates. `add` / `remove` carry the
147
+ * `RichTextMark` vocabulary (`{ type, … }`); `removeAnchor` drops one identity
148
+ * anchor by id.
149
+ */
150
+ export type MarkOp =
151
+ | ({ op: "add" | "remove"; start: number; end: number } & (
152
+ | { type: "strong" | "emph" | "underline" | "strike" | "code" }
153
+ | { type: "link"; url: string }
154
+ | { type: "anchor"; id: string }
155
+ | { type: string; attrs: unknown }
156
+ ))
157
+ | { op: "removeAnchor"; id: string };
158
+
159
+ /** A line/block edit. `split`/`join` splice `\n`; `setKind`/`setContainers` touch metadata. */
160
+ export type LineOp =
161
+ | { op: "split"; at: number }
162
+ | { op: "join"; line: number }
163
+ | ({ op: "setKind"; line: number } & (
164
+ | { kind: "para" | "island" | "rule" }
165
+ | { kind: "heading"; level: number }
166
+ | { kind: "code"; lang?: string }
167
+ ))
168
+ | { op: "setContainers"; line: number; containers: RichTextContainer[] };
169
+
170
+ /**
171
+ * A committed corpus edit bundle for `applyChange`: a text `delta` (default no
172
+ * text change), then `lineOps`, then `markOps` (mark ranges are in post-delta
173
+ * coordinates). Every field is optional.
174
+ */
175
+ export interface ChangeBundle {
176
+ delta?: Delta;
177
+ lineOps?: LineOp[];
178
+ markOps?: MarkOp[];
179
+ }
180
+
181
+
182
+
183
+ /**
184
+ * Page dimensions in points (1 pt = 1/72 inch). Typst measures in Typst
185
+ * points; pdfform measures in PDF points — the same unit.
186
+ *
187
+ * Report-only: the painter sizes the canvas itself based on
188
+ * `PaintOptions`. `pageSize` is exposed for callers that need page
189
+ * geometry up-front (e.g. to lay out a scrollable list of canvases
190
+ * before any pixels are rendered).
191
+ */
192
+ export interface PageSize {
193
+ widthPt: number;
194
+ heightPt: number;
195
+ }
196
+
197
+ /**
198
+ * Inputs to `LiveSession.paint`. Both fields are optional and default
199
+ * to `1`.
200
+ *
201
+ * - `layoutScale` — layout-space pixels per point (Typst point / PDF
202
+ * point — the same 1/72″ unit). For on-screen
203
+ * canvases this is CSS pixels per pt; the page's layout-pixel size is
204
+ * `widthPt * layoutScale × heightPt * layoutScale`. The painter
205
+ * surfaces these dimensions as `layoutWidth` / `layoutHeight` so
206
+ * consumers can drive `canvas.style.*` (or any layout system).
207
+ * - `densityScale` — backing-store density multiplier. Fold
208
+ * `window.devicePixelRatio`, in-app zoom, and `visualViewport.scale`
209
+ * (pinch-zoom) into a single value here. Defaults to `1`, which
210
+ * produces a non-retina backing store — pass `window.devicePixelRatio`
211
+ * for crisp output on high-DPI displays.
212
+ *
213
+ * The effective rasterization scale is `layoutScale * densityScale`.
214
+ * Both must be finite and `> 0`. For `OffscreenCanvasRenderingContext2D`
215
+ * the two collapse to a single scalar; folding everything into
216
+ * `densityScale` is the simplest convention.
217
+ */
218
+ export interface PaintOptions {
219
+ layoutScale?: number;
220
+ densityScale?: number;
221
+ }
222
+
223
+ /**
224
+ * Returned by `LiveSession.paint`.
225
+ *
226
+ * - `layoutWidth` / `layoutHeight` — layout-pixel dimensions of the
227
+ * canvas's display box. For on-screen canvases this is CSS pixels:
228
+ * set `canvas.style.width = layoutWidth + "px"` and
229
+ * `canvas.style.height = layoutHeight + "px"` (or feed these into
230
+ * your layout system). Independent of `densityScale`.
231
+ * - `pixelWidth` / `pixelHeight` — integer backing-store pixel
232
+ * dimensions the painter wrote to `canvas.width` / `canvas.height`.
233
+ * Equal to `round(layoutWidth * densityScale)` ×
234
+ * `round(layoutHeight * densityScale)` *unless* the requested backing
235
+ * exceeded the painter's safe maximum (16384 px per side), in which
236
+ * case `densityScale` was clamped to fit.
237
+ * - `clamped` — `true` when that 16384-px clamp fired, so the page is
238
+ * painted at fewer device pixels than requested and renders soft at the
239
+ * same `canvas.style` size. Reads the clamp off the return value instead
240
+ * of the `pixelWidth < round(layoutWidth * densityScale)` derivation.
241
+ * - `effectiveDensityScale` — the `densityScale` actually applied: the
242
+ * requested value unless `clamped`, then reduced proportionally.
243
+ * `layoutScale * effectiveDensityScale` is the scale the backing store
244
+ * was rasterized at.
245
+ *
246
+ * The painter owns `canvas.width` / `canvas.height`; consumers must not
247
+ * write to them. The painter does **not** touch `canvas.style.*`;
248
+ * consumers own layout. The write is a whole-backing-store `putImageData`,
249
+ * which bypasses the 2D context transform, `globalAlpha`, and clip: give
250
+ * each visible page its own `` — you cannot composite two pages, a
251
+ * sub-rect, or a context transform through `paint`.
252
+ *
253
+ * For `OffscreenCanvasRenderingContext2D` (Worker rasterization, no
254
+ * DOM), `layoutWidth` / `layoutHeight` are informational — there's no
255
+ * CSS layout box to apply them to.
256
+ */
257
+ export interface PaintResult {
258
+ layoutWidth: number;
259
+ layoutHeight: number;
260
+ pixelWidth: number;
261
+ pixelHeight: number;
262
+ clamped: boolean;
263
+ effectiveDensityScale: number;
264
+ }
265
+
266
+
267
+
268
+ /** UI layout hints for a single field. Field display order is not a hint:
269
+ * key order in the schema's `fields`/`properties` objects is declaration
270
+ * order, the ordering contract. */
271
+ export interface QuillFieldUi {
272
+ title?: string;
273
+ group?: string;
274
+ compact?: boolean;
275
+ multiline?: boolean;
276
+ }
277
+
278
+ /** UI layout hints for a card (main or named card kind). */
279
+ export interface QuillCardUi {
280
+ title?: string;
281
+ }
282
+
283
+ /** Body namespace for a card (main or named card kind). */
284
+ export interface QuillCardBody {
285
+ /** When false, consumers must not accept or store body content for this card kind. Defaults to true. */
286
+ enabled?: boolean;
287
+ /** Example body content embedded verbatim in the blueprint body region. Fallback is "Write <card> body here." */
288
+ example?: string;
289
+ }
290
+
291
+ /** Schema entry for a single field declared in a quill's `Quill.yaml`.
292
+ *
293
+ * A field's *cell* is determined by `default`: a field with a `default`
294
+ * is **Endorsed** (the rendered value is shippable as-is), while a field
295
+ * without a `default` is **Unendorsed** (the blueprint carries a
296
+ * `!must_fill` marker; a marker left in the document yields the non-fatal
297
+ * `validation::must_fill` warning from validate, and the render path
298
+ * zero-fills the field). There is no separate `required` axis.
299
+ */
300
+ export interface QuillFieldSchema {
301
+ type: "string" | "number" | "integer" | "boolean" | "array" | "object" | "datetime" | "richtext" | "plaintext" | "enum";
302
+ description?: string;
303
+ default?: unknown;
304
+ example?: unknown;
305
+ /** Closed value domain. On `type: "enum"` declared as `values`; the
306
+ * deprecated `enum` modifier on `type: "string"` is accepted for one
307
+ * release. Both round-trip through this field. */
308
+ enum?: string[];
309
+ /** Required on `type: "enum"`: the closed set of allowed string values. */
310
+ values?: string[];
311
+ ui?: QuillFieldUi;
312
+ properties?: Record<string, QuillFieldSchema>;
313
+ items?: QuillFieldSchema;
314
+ /** Present (and `true`) on a `richtext` or `plaintext` field declared
315
+ * `inline` — the single-paragraph, container-free, island-free constraint.
316
+ * Core serializes `inline: true` into the schema JSON; absent otherwise. */
317
+ inline?: boolean;
318
+ }
319
+
320
+ /** Schema entry for the main card or a named card kind. */
321
+ export interface QuillCardSchema {
322
+ description?: string;
323
+ fields: Record<string, QuillFieldSchema>;
324
+ ui?: QuillCardUi;
325
+ body?: QuillCardBody;
326
+ }
327
+
328
+ /**
329
+ * Document schema returned by `Quill.schema`. Includes optional `ui` keys.
330
+ *
331
+ * Describes only the user-fillable fields. The quill reference
332
+ * (constructed as `${metadata.name}@${metadata.version}`) and card-kind
333
+ * discriminators are document-level metadata, not schema fields.
334
+ */
335
+ export interface QuillSchema {
336
+ main: QuillCardSchema;
337
+ /** Present only when the quill declares at least one named card kind. */
338
+ card_kinds?: Record<string, QuillCardSchema>;
339
+ }
340
+
341
+ /**
342
+ * Identity snapshot mirroring the `quill:` section of `Quill.yaml`.
343
+ * The schema lives on `Quill.schema`; the backend's output formats are a
344
+ * resolved-backend capability read from the engine (`Quillmark.supportedFormats`),
345
+ * not part of this pure-config snapshot.
346
+ */
347
+ export interface QuillMetadata {
348
+ name: string;
349
+ version: string;
350
+ backend: string;
351
+ author: string;
352
+ description: string;
353
+ }
354
+
355
+
356
+ export interface Artifact {
357
+ format: OutputFormat;
358
+ bytes: Uint8Array;
359
+ mimeType: string;
360
+ }
361
+
362
+ export interface ChangeSet {
363
+ pageCount: number;
364
+ dirtyPages: number[];
365
+ }
366
+
367
+ export interface CorpusHit {
368
+ field: string;
369
+ pos: number;
370
+ granularity?: HitGranularity;
371
+ }
372
+
373
+ export interface Diagnostic {
374
+ severity: Severity;
375
+ code?: string;
376
+ message: string;
377
+ location?: Location;
378
+ path?: string;
379
+ hint?: string;
380
+ sourceChain?: string[];
381
+ }
382
+
383
+ export interface FieldRegion {
384
+ field: string;
385
+ page: number;
386
+ rect: [number, number, number, number];
387
+ span?: [number, number];
388
+ }
389
+
390
+ export interface Location {
391
+ file: string;
392
+ line: number;
393
+ column: number;
394
+ }
395
+
396
+ export interface RenderOptions {
397
+ format?: OutputFormat;
398
+ ppi?: number;
399
+ pages?: number[];
400
+ producer?: string;
401
+ regions?: boolean;
402
+ }
403
+
404
+ export interface RenderResult {
405
+ artifacts: Artifact[];
406
+ warnings: Diagnostic[];
407
+ outputFormat: OutputFormat;
408
+ renderTimeMs: number;
409
+ regions: FieldRegion[];
410
+ }
411
+
412
+ export type HitGranularity = "cluster" | "segment";
413
+
414
+ export type OutputFormat = "pdf" | "svg" | "txt" | "png";
415
+
416
+ export type Severity = "error" | "warning";
417
+
418
+
419
+ /**
420
+ * Typed in-memory Quillmark document.
421
+ */
422
+ export class Document {
423
+ free(): void;
424
+ [Symbol.dispose](): void;
425
+ /**
426
+ * Build a composable card of `kind`, typed-commit `fields` onto it, set its
427
+ * body from optional markdown, and append it — the ABI under
428
+ * `writer.addCard`. Fuses `makeCard` + typed commit + `pushCard`
429
+ * transactionally: the card is committed in full before it joins the
430
+ * document, so a rejected field (or an invalid kind or body) leaves the
431
+ * document untouched. Field errors throw the same per-field diagnostic
432
+ * bundle as [`commitFields`](Self::commit_fields), including an
433
+ * `[EditError::UnknownField]` per undeclared name; an invalid kind or body
434
+ * throws a single-entry bundle keyed `$kind` / `$body`.
435
+ */
436
+ addCard(quill: Quill, kind: string, fields?: Record<string, unknown>, body?: string): void;
437
+ /**
438
+ * **Apply** a committed corpus edit `bundle` (`{ delta?, lineOps?, markOps? }`)
439
+ * at `addr` — the editor splice: text delta first, then line ops, then mark
440
+ * ops (mark ranges in post-delta coordinates), each all-or-nothing. An absent
441
+ * `addr.field` targets the body, an absent `addr.card` the main card.
442
+ *
443
+ * Throws on an out-of-range card, a field that is not richtext, a malformed
444
+ * bundle, or an op that applies out of bounds (the value is unchanged on a
445
+ * failed apply).
446
+ */
447
+ applyChange(addr: Addr, bundle: ChangeBundle): void;
448
+ /**
449
+ * Authoring-ergonomics header introducing a blueprint to an LLM/MCP
450
+ * consumer for the given `quillName`. Re-exposes core's canonical text for
451
+ * JS consumers; any surface that draws from the same core source stays
452
+ * uniform.
453
+ */
454
+ static blueprintInstruction(quill_name: string): string;
455
+ clone(): Document;
456
+ /**
457
+ * Typed field write on the composable card at `index` — the card-indexed
458
+ * twin of [`commitField`](Document::commit_field). Resolves the field's
459
+ * type from the card's `$kind` schema in `quill` and strict-commits it.
460
+ *
461
+ * Throws `[EditError::IndexOutOfRange]` when `index` is out of range, and
462
+ * the same typed-mismatch / name errors as `commitField` — including
463
+ * `[EditError::UnknownField]` for a field the card-kind schema does not
464
+ * declare (an unknown `$kind` has no schema, so every field is undeclared).
465
+ */
466
+ commitCardField(quill: Quill, index: number, name: string, value: any): void;
467
+ /**
468
+ * Batched twin of [`commitCardField`](Document::commit_card_field):
469
+ * typed-commit several fields on the card at `index` atomically, resolving
470
+ * each field's type from the card's `$kind` schema in `quill`. All-or-nothing
471
+ * with the same per-field-diagnostic contract as
472
+ * [`commitFields`](Document::commit_fields), including an
473
+ * `[EditError::UnknownField]` diagnostic per undeclared name. Throws
474
+ * `[EditError::IndexOutOfRange]` when `index` is out of range.
475
+ */
476
+ commitCardFields(quill: Quill, index: number, fields: Record<string, unknown>): void;
477
+ /**
478
+ * Typed field write on the main card, resolving the field's schema `type`
479
+ * from `quill` — the one write verb for **every** field type (richtext,
480
+ * scalar, array, object). The schema carries the `inline` constraint, so no
481
+ * type token or flag is passed. A richtext-typed field stores the canonical
482
+ * corpus, so identity marks (anchors, island ids) and corpus-only marks
483
+ * (e.g. `underline`) live on it and survive compiles and the storage DTO.
484
+ * Values use the encoding the seam already speaks: a corpus object
485
+ * or markdown string for richtext, a scalar/array/object otherwise.
486
+ *
487
+ * A field declared in the schema is strict-committed — a mismatch throws
488
+ * now, not at render. A name the schema does not declare throws
489
+ * `[EditError::UnknownField]` rather than falling to the opaque store: on
490
+ * the typed path it is a typo. Use [`setField`](Document::set_field) when
491
+ * opaque storage is the intent. Also throws `[EditError::FieldConform]` /
492
+ * `[EditError::FieldRichtextDecode]` / `[EditError::FieldRichtextNotInline]`
493
+ * on a typed mismatch and `[EditError::InvalidFieldName]` on a malformed
494
+ * name.
495
+ *
496
+ * The `quill` handle is passed per call because a `Document` carries only a
497
+ * `$quill` reference, not the resolved schema.
498
+ */
499
+ commitField(quill: Quill, name: string, value: any): void;
500
+ /**
501
+ * Batched twin of [`commitField`](Document::commit_field): typed-commit
502
+ * several main-card fields atomically, resolving each field's schema `type`
503
+ * from `quill`. All-or-nothing with the same per-field-diagnostic error
504
+ * contract as [`setFields`](Document::set_fields) — nothing is applied on
505
+ * error and the thrown error's `diagnostics` carry one entry per offending
506
+ * field, including an `[EditError::UnknownField]` for any name the schema
507
+ * does not declare, so a whole-form submit sees every typo in one pass.
508
+ */
509
+ commitFields(quill: Quill, fields: Record<string, unknown>): void;
510
+ /**
511
+ * Schema version this build writes via [`toJson`](Document::to_json).
512
+ * Tracks the `Document` model version (not the running crate version):
513
+ * the tag advances only when the wire format changes, not on every release.
514
+ */
515
+ static currentSchemaVersion(): string;
516
+ /**
517
+ * Structural equality (parse-time `warnings` excluded). Use to debounce
518
+ * upstream prop updates instead of re-parsing on every keystroke.
519
+ */
520
+ equals(other: Document): boolean;
521
+ /**
522
+ * Render a Diagnostic as the canonical pretty-printed text (core's
523
+ * `Diagnostic::fmt_pretty`). Single source of truth so a Diagnostic looks
524
+ * identical no matter which consumer surfaces it.
525
+ */
526
+ static formatDiagnostic(diag: Diagnostic): string;
527
+ /**
528
+ * Authoring-format rules for the card-yaml markdown surface. The canonical
529
+ * text is core's (`quillmark_core::document::FORMAT_RULES`), re-exposed
530
+ * here for JS consumers so it matches any other surface that draws from the
531
+ * same source. Read once at startup and cache; the value never changes
532
+ * between calls.
533
+ */
534
+ static formatRules(): string;
535
+ /**
536
+ * Reconstruct a `Document` from a versioned storage DTO string produced
537
+ * by [`toJson`](Document::to_json). Unknown `schema` tags are rejected.
538
+ * The result carries no parse-time warnings (`.warnings` is always empty).
539
+ *
540
+ * Throws if `json` is not a valid storage DTO (malformed JSON, unknown
541
+ * `schema`, missing fields, or unparseable quill reference).
542
+ */
543
+ static fromJson(json: string): Document;
544
+ /**
545
+ * Parse markdown into a typed Document. Throws on parse errors.
546
+ */
547
+ static fromMarkdown(markdown: string): Document;
548
+ /**
549
+ * Read a main-card field's stored value — the raw payload value (a corpus
550
+ * object for a richtext field, a scalar/array/object otherwise), or
551
+ * `undefined` when the field is absent. The quill-free read: reads need no
552
+ * schema, so they live on `Document`, not the typed writer. For the markdown
553
+ * projection of a richtext value use [`getMarkdown`](Self::get_markdown).
554
+ */
555
+ get(name: string): any;
556
+ /**
557
+ * The markdown projection of a main-card field (`name` given) or the main
558
+ * body (`name` omitted) — the on-demand, lossy export (corpus-only marks do
559
+ * not survive markdown), returning `""` for an absent field. Re-coins,
560
+ * lazily and by name, the projection the eager `fieldMarkdown` /
561
+ * `bodyMarkdown` getters dropped in #925; call it only when markdown is what
562
+ * you need out.
563
+ */
564
+ getMarkdown(name?: string): string;
565
+ /**
566
+ * Insert a card at `index` (must be in `0..=cards.length`). Accepts a
567
+ * `CardInput` (see [`pushCard`](Self::push_card)).
568
+ */
569
+ insertCard(index: number, card: CardInput): void;
570
+ /**
571
+ * **Install** a richtext value at `addr` — **value semantics**, corpus only.
572
+ * Stores exactly `rt` (a canonical `RichText` corpus object); the identity
573
+ * anchors of any previous value are gone. An absent `addr.field` targets the
574
+ * body, an absent `addr.card` the main card. For "here's new markdown," use
575
+ * [`revise`](Document::revise); the cold-import path is spelled at the call
576
+ * site as `install(addr, importMarkdown(md))`, so anchor loss is visible in
577
+ * source.
578
+ *
579
+ * Throws on an out-of-range card, a malformed field name, or an `rt` that is
580
+ * not a canonical corpus object.
581
+ */
582
+ install(addr: Addr, rt: RichText): void;
583
+ /**
584
+ * Replace this document's contents **in place** from a versioned storage
585
+ * DTO string — the mutating twin of the static
586
+ * [`fromJson`](Document::from_json) constructor. Parse-time `warnings` are
587
+ * cleared. Throws (leaving the document unchanged) on an invalid DTO.
588
+ *
589
+ * The cross-WASM-memory `Document` bridge: mutate a document on a
590
+ * backend-memory clone, then write the mutated state back into the caller's
591
+ * canonical document with this — the one way to update a live handle across
592
+ * the linear-memory seam without the caller re-binding its variable.
593
+ */
594
+ loadJson(json: string): void;
595
+ /**
596
+ * Build a fresh `Card` from a kind and a flat field map — the ergonomic
597
+ * constructor for `pushCard` / `insertCard`. `fields` is an optional
598
+ * `Record<string, unknown>` (each entry becomes a card field, in
599
+ * insertion order); `body` defaults to `""`. Kind validity is checked by
600
+ * `pushCard` / `insertCard`, not here.
601
+ */
602
+ static makeCard(kind: string, fields?: Record<string, unknown>, body?: string): Card;
603
+ /**
604
+ * Move the card at `from` to position `to`. `from == to` is a no-op.
605
+ */
606
+ moveCard(from: number, to: number): void;
607
+ /**
608
+ * `new Document(quillRef)` — a blank document: a main card carrying only
609
+ * `$quill`, an empty body, and no composable cards. The programmatic
610
+ * blank canvas: absent fields resolve at render time (`default`, else
611
+ * type-empty zero), so nothing the caller did not set reaches the
612
+ * output. For an example-filled starter use `Quill.seedDocument()`.
613
+ * Throws on an invalid quill reference. Mirrors Python `Document(quill_ref)`.
614
+ */
615
+ constructor(quill_ref: string);
616
+ /**
617
+ * Append a card to the end of the card list. Accepts a `CardInput` — a card
618
+ * read back (`cards` / `removeCard` / `quill.seedCard`), a
619
+ * [`makeCard`](Document::make_card) result, or a bare `{ kind, body }`
620
+ * (every returned `Card` is a valid `CardInput`). Throws if `card.kind` is
621
+ * not a valid kind name.
622
+ */
623
+ pushCard(card: CardInput): void;
624
+ /**
625
+ * The canonical `$quill` reference grammar as author-facing text. Core is
626
+ * the single source of truth: drive schema `describe` and validation
627
+ * messages from this instead of re-stating the rule — it matches the
628
+ * `hint` on `parse::invalid_quill_reference`. Cache it; the value never
629
+ * changes.
630
+ */
631
+ static quillRefHint(): string;
632
+ removeCard(index: number): Card | undefined;
633
+ /**
634
+ * Remove the `$ext` map from the composable card at `index` *entirely*,
635
+ * returning the previous map or `undefined`. Throws if out of range.
636
+ * Prefer `removeCardExtNamespace` to clear only one consumer's slot.
637
+ */
638
+ removeCardExt(index: number): Record<string, unknown> | undefined;
639
+ /**
640
+ * Remove `namespace` from the composable card's `$ext` map, returning the
641
+ * value stored there or `undefined`; clears `$ext` entirely once empty.
642
+ * The card-indexed twin of `removeExtNamespace`. Throws if out of range.
643
+ */
644
+ removeCardExtNamespace(index: number, namespace: string): any;
645
+ /**
646
+ * Remove a field on the card at `index`. Returns the removed value or
647
+ * `undefined`. Throws if `index` is out of range or `name` is invalid.
648
+ */
649
+ removeCardField(index: number, name: string): any;
650
+ /**
651
+ * Remove the `$ext` map from the main card *entirely*, returning the
652
+ * previous map or `undefined`. This is a blunt escape hatch that discards
653
+ * every namespace at once — prefer `removeExtNamespace` to clear only your
654
+ * own slot while leaving sibling consumers' state intact.
655
+ */
656
+ removeExt(): Record<string, unknown> | undefined;
657
+ /**
658
+ * Remove `namespace` from the main card's `$ext` map, returning the value
659
+ * stored there or `undefined`. This is the recommended way to clear `$ext`
660
+ * state: sibling namespaces survive, and when the last namespace is removed
661
+ * the `$ext` entry is dropped entirely (not left as `$ext: {}`).
662
+ */
663
+ removeExtNamespace(namespace: string): any;
664
+ /**
665
+ * Remove a payload field on the main card, returning the removed value or
666
+ * `undefined`. Throws if `name` does not match `[A-Za-z_][A-Za-z0-9_]*`.
667
+ */
668
+ removeField(name: string): any;
669
+ /**
670
+ * Remove `cardKind` from the main card's `$seed` map, returning its
671
+ * overlay or `undefined`; drops `$seed` entirely once empty. Sibling
672
+ * kinds survive.
673
+ */
674
+ removeSeedNamespace(card_kind: string): any;
675
+ /**
676
+ * **Deprecated** — alias for `revise({}, markdown)`, kept one release cycle.
677
+ * Revise the main card's body from a markdown string (edit semantics: a
678
+ * `diff_import` that rebases surviving anchors). Discards the text delta;
679
+ * call [`revise`](Document::revise) to receive it.
680
+ */
681
+ replaceBody(body: string): void;
682
+ /**
683
+ * **Revise** the richtext value at `addr` from a markdown string — **edit
684
+ * semantics**, the default write path, returning the text [`Delta`]. Imports
685
+ * the markdown, diffs it against the current value, rebases surviving
686
+ * identity anchors, and returns the change an editor bridge maps its own
687
+ * positions through (`mapPos`). An absent `addr.field` targets the body, an
688
+ * absent `addr.card` the main card; an absent field cold-imports from empty.
689
+ *
690
+ * Throws on an out-of-range card, a malformed field name, a present
691
+ * non-corpus field value, or an over-nested markdown input.
692
+ */
693
+ revise(addr: Addr, markdown: string): Delta;
694
+ /**
695
+ * Read the `schema` version tag from a raw storage DTO string without a
696
+ * full parse, or `undefined`. Returns unknown future versions as-is —
697
+ * useful to distinguish "build too old" from "payload corrupt" when
698
+ * `fromJson` throws.
699
+ */
700
+ static schemaVersionOf(json: string): string | undefined;
701
+ /**
702
+ * Replace the `$ext` map on the composable card at `index`. Throws if out
703
+ * of range or `value` is not a plain object. Named to mirror `setExt` on
704
+ * the main card; `setCardExtNamespace` is the sibling-safe alternative.
705
+ */
706
+ setCardExt(index: number, value: any): void;
707
+ /**
708
+ * Merge `value` into the composable card's `$ext` map under `namespace`,
709
+ * preserving sibling namespaces. The card-indexed twin of `setExtNamespace`.
710
+ * Throws if out of range or `value` cannot be serialized.
711
+ */
712
+ setCardExtNamespace(index: number, namespace: string, value: any): void;
713
+ /**
714
+ * Set a field on the card at `index` — the card-indexed twin of
715
+ * [`setField`](Document::set_field). Stores the value opaquely.
716
+ * Throws if `index` is out of range, `name` is reserved or invalid.
717
+ */
718
+ setCardField(index: number, name: string, value: any): void;
719
+ /**
720
+ * Batched twin of [`setCardField`](Document::set_card_field): set
721
+ * several fields on the card at `index` atomically. Same all-or-nothing,
722
+ * one-diagnostic-per-field contract as [`setFields`](Document::set_fields).
723
+ * Throws if `index` is out of range.
724
+ */
725
+ setCardFields(index: number, fields: Record<string, unknown>): void;
726
+ /**
727
+ * Replace the kind of the card at `index`. Payload and body are untouched;
728
+ * schema-aware migration is the caller's responsibility.
729
+ * Throws if `index` is out of range or `newKind` is invalid.
730
+ */
731
+ setCardKind(index: number, new_kind: string): void;
732
+ /**
733
+ * Replace the opaque `$ext` map on the main card. `value` must be a plain
734
+ * object; throws otherwise. `$ext` carries out-of-band consumer state and
735
+ * never reaches the rendered output. Pass `{}` to record an explicit
736
+ * empty `$ext`.
737
+ */
738
+ setExt(value: any): void;
739
+ /**
740
+ * Merge `value` into the main card's `$ext` map under `namespace`, creating
741
+ * the map when absent and replacing any existing value at that key. Sibling
742
+ * namespaces are preserved, so independent consumers (`$ext.editor`,
743
+ * `$ext.agent`, …) don't clobber each other.
744
+ */
745
+ setExtNamespace(namespace: string, value: any): void;
746
+ /**
747
+ * Update a payload field on the main card. Clears any existing `!must_fill` marker.
748
+ *
749
+ * Throws if `name` does not match `[A-Za-z_][A-Za-z0-9_]*`.
750
+ */
751
+ setField(name: string, value: any): void;
752
+ /**
753
+ * Set several main-card payload fields atomically from a plain object,
754
+ * clearing any `!must_fill` marker on each key. Nothing is applied on
755
+ * error; the thrown error's `diagnostics` array carries one entry per
756
+ * offending field (`path` = field name), so externally-sourced names
757
+ * (database columns, form keys) surface every violation in one pass.
758
+ * Mirrors Python `set_fields`.
759
+ */
760
+ setFields(fields: Record<string, unknown>): void;
761
+ /**
762
+ * Update a payload field on the main card and mark it as `!must_fill`.
763
+ * Throws on invalid name (see [`setField`](Document::set_field)).
764
+ */
765
+ setFill(name: string, value: any): void;
766
+ /**
767
+ * Replace the QUILL reference string. Throws if `ref_str` is invalid.
768
+ */
769
+ setQuillRef(ref_str: string): void;
770
+ /**
771
+ * Merge a card-kind's seed `overlay` into the main card's `$seed` map
772
+ * under `cardKind`, preserving sibling kinds. Sets the starting values
773
+ * new cards of that kind spawn with. Throws if `overlay` cannot be
774
+ * serialized or nests too deep.
775
+ */
776
+ setSeedNamespace(card_kind: string, overlay: any): void;
777
+ /**
778
+ * Serialize this document to a versioned storage DTO string.
779
+ *
780
+ * Prefer this over `toMarkdown` for persistence across restarts or crate
781
+ * upgrades — the wire format is frozen per `schema` version. Parse-time
782
+ * `warnings` are excluded from the DTO.
783
+ *
784
+ * Output is **byte-deterministic** within a `schema` version: equal
785
+ * documents produce byte-equal output, safe for content-hash use cases.
786
+ */
787
+ toJson(): string;
788
+ /**
789
+ * Emit canonical Quillmark Markdown. Round-trip safe: re-parsing the
790
+ * result produces a `Document` equal to `self` by value and by type.
791
+ */
792
+ toMarkdown(): string;
793
+ /**
794
+ * Like [`fromJson`](Document::from_json) but returns `undefined` instead
795
+ * of throwing when `json` is not a valid storage DTO — use to
796
+ * discriminate format without exceptions as control flow.
797
+ * `undefined` means "not a storage DTO"; `fromMarkdown` still throws on
798
+ * genuinely malformed markdown.
799
+ */
800
+ static tryFromJson(json: string): Document | undefined;
801
+ /**
802
+ * Number of composable cards (excludes the main card). O(1).
803
+ */
804
+ readonly cardCount: number;
805
+ readonly cards: Card[];
806
+ /**
807
+ * The document's main (entry) card. Allocates and serializes on each
808
+ * call — cache locally if read in a hot loop.
809
+ */
810
+ readonly main: Card;
811
+ readonly quillRef: string;
812
+ readonly warnings: Diagnostic[];
813
+ }
814
+
815
+ /**
816
+ * Live render session: reads (`render`, `paint`, `pageSize`, `regions`,
817
+ * `fieldAt`, `positionAt`, `locate`) serve the current compile. `apply(doc)`
818
+ * recompiles a whole document in place, transactionally (on throw every read
819
+ * keeps serving the last-good compile). Geometry reads reflect the current
820
+ * compile; anchoring a caret across edits is the editor's job — re-read
821
+ * geometry after each committed `apply`.
822
+ *
823
+ * **Empty documents.** A zero-page document yields a valid session
824
+ * (`pageCount === 0`); `paint(ctx, 0)` or `pageSize(0)` throws with
825
+ * `"page index 0 out of range (pageCount=0)"`. Branch on `pageCount === 0`
826
+ * rather than catching the error.
827
+ */
828
+ export class LiveSession {
829
+ private constructor();
830
+ free(): void;
831
+ [Symbol.dispose](): void;
832
+ /**
833
+ * Recompile the session against `doc` — the edit verb of a live preview.
834
+ * The document is compiled through the same schema pipeline as `open`
835
+ * (same quill), then applied transactionally: on throw every read
836
+ * (`render`, `paint`, `pageSize`, `regions`, `fieldAt`) keeps serving the last-good
837
+ * compile, and the session recovers on the next successful `apply`. On
838
+ * success reads serve the new compile; repaint `dirtyPages ∩ visible`.
839
+ */
840
+ apply(doc: Document): ChangeSet;
841
+ /**
842
+ * The schema field whose content is under a point on `page` — the
843
+ * forward (click → field) direction: hit-test a click against the
844
+ * compiled document and get back the field address to focus in the
845
+ * editor, or `undefined` off any field's ink. `x`/`y` are PDF points
846
+ * with a **bottom-left** origin, the same space as `FieldRegion.rect` —
847
+ * from a canvas click, invert the overlay transform documented on
848
+ * `FieldRegion`: `x = clickPx.x / renderScale`,
849
+ * `y = pageHeightPt - clickPx.y / renderScale`. Unlike `regions()`,
850
+ * *every* placement answers, not just the first.
851
+ */
852
+ fieldAt(page: number, x: number, y: number): string | undefined;
853
+ /**
854
+ * The whole-field highlight boxes for `field` — one union rect per page,
855
+ * over the field's `span`-bearing content segments. The convenience that
856
+ * owns the union `regions()` leaves derived: it keeps `regions()` the
857
+ * low-level disjoint truth (#829) and folds the span-filter + per-page
858
+ * union here, so a "highlight the focused field" consumer stops
859
+ * reimplementing it. **Content only** — a field placed solely as a scalar
860
+ * reference or a bound widget carries no `span` and returns `[]`; its box
861
+ * is a single `regions()` rect. Reflects the current compile, like
862
+ * `regions()`.
863
+ */
864
+ fieldBoxes(field: string): FieldRegion[];
865
+ /**
866
+ * A corpus position → **caret rect** — the reverse of `positionAt`: given
867
+ * a field and a USV offset into its `RichText`, return the box (in the
868
+ * same bottom-left PDF-point space as `FieldRegion.rect`) to draw a caret
869
+ * at, its `span` collapsed to `[pos, pos]`; `undefined` when the field
870
+ * places no tracked content or the offset maps to no drawn glyph.
871
+ */
872
+ locate(field: string, pos: number): FieldRegion | undefined;
873
+ /**
874
+ * Page dimensions in points (1 pt = 1/72 inch).
875
+ * Throws if the backend has no canvas painter or `page` is out of range.
876
+ */
877
+ pageSize(page: number): PageSize;
878
+ /**
879
+ * Paint `page` into a `CanvasRenderingContext2D` or
880
+ * `OffscreenCanvasRenderingContext2D`. The painter owns
881
+ * `canvas.width`/`height` (no `clearRect` needed); consumers own
882
+ * `canvas.style.*`. If `layoutScale * densityScale` exceeds 16384 px
883
+ * per side, `densityScale` is clamped — `PaintResult.clamped` reports it and
884
+ * `PaintResult.effectiveDensityScale` carries the density actually applied.
885
+ *
886
+ * `put_image_data` writes the whole backing store, bypassing the 2D
887
+ * context's transform, `globalAlpha`, and clip: the painter owns the entire
888
+ * canvas, so each visible page needs its own `` — you cannot composite
889
+ * two pages, a sub-rect, or a context transform through this call.
890
+ *
891
+ * Throws if the backend has no canvas painter, `page` is out of range,
892
+ * `ctx` is the wrong type, or either scale is non-finite or `<= 0`.
893
+ */
894
+ paint(ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, page: number, opts: PaintOptions | undefined): PaintResult;
895
+ /**
896
+ * A point → **corpus position** — the fine-grained click direction:
897
+ * hit-test a point and get back the field *and* a USV offset into its
898
+ * `RichText` (for placing a caret or mapping a selection into the content
899
+ * model), or `undefined` off all content ink. `x`/`y` are PDF points,
900
+ * bottom-left origin — the same space as `fieldAt`. The offset is
901
+ * cluster-exact and degrades to the containing segment's start on
902
+ * origin-less ink (list markers, a code fence's interior). See
903
+ * `CorpusHit`.
904
+ */
905
+ positionAt(page: number, x: number, y: number): CorpusHit | undefined;
906
+ /**
907
+ * Schema-field geometry for this compiled session — each content field's
908
+ * **first placement** (one region per page it touches) plus widget and
909
+ * scalar-reference-site regions, keyed on the quill schema field path; a
910
+ * field may still appear more than once (group by `field`, see
911
+ * `FieldRegion`). A session-level query: no render, no byte artifact. An
912
+ * interactive preview reads it to scroll to / highlight the focused
913
+ * field over a `paint`-ed canvas; the click direction is `fieldAt`.
914
+ * Empty for backends that place no schema fields.
915
+ */
916
+ regions(): FieldRegion[];
917
+ render(opts?: RenderOptions | null): RenderResult;
918
+ /**
919
+ * The backend that produced this session (e.g. `"typst"`).
920
+ */
921
+ readonly backendId: string;
922
+ readonly pageCount: number;
923
+ /**
924
+ * `true` iff `paint` and `pageSize` will succeed for this session. Derived
925
+ * from the session's canvas seam, so it reflects exactly what `paint` will
926
+ * do — no separately captured flag.
927
+ */
928
+ readonly supportsCanvas: boolean;
929
+ /**
930
+ * Non-fatal diagnostics of the session's **current compile** (e.g. Typst
931
+ * font fallback) — set at open and refreshed by each committed `apply`;
932
+ * a failed apply keeps the last-good compile's warnings. Also appended
933
+ * to `RenderResult.warnings` on each `render()` call.
934
+ */
935
+ readonly warnings: Diagnostic[];
936
+ }
937
+
938
+ export class Quill {
939
+ private constructor();
940
+ free(): void;
941
+ [Symbol.dispose](): void;
942
+ /**
943
+ * Build a quill from a file tree. Pure — no backend, no engine; the
944
+ * declared backend is resolved later, at render time.
945
+ *
946
+ * Accepts either a `Map<string, Uint8Array>` or a plain object
947
+ * (`Record<string, Uint8Array>`). Plain objects are walked via
948
+ * `Object.entries` at the boundary; the Rust side sees a single
949
+ * canonical shape.
950
+ */
951
+ static fromTree(tree: Map<string, Uint8Array>): Quill;
952
+ /**
953
+ * Seed a starter composable `Card` of the given kind (carries `$kind`),
954
+ * layering an optional per-kind seed `overlay` over the schema-example
955
+ * base (`overlay › example › absent`). Returns `undefined` if `cardKind`
956
+ * is not declared in this quill's schema, else a `Card` that feeds
957
+ * straight into `Document.pushCard` / `insertCard`.
958
+ *
959
+ * Pass `document.main.seed?.[cardKind]` as `overlay` so a card added to a
960
+ * template-derived document inherits its curated starting values; omit it
961
+ * (or pass `undefined` / `null`) for the bare schema seed. `overlay` is a
962
+ * plain object — this reads the document, it does not mutate it.
963
+ */
964
+ seedCard(card_kind: string, overlay: Record<string, unknown> | undefined): Card | undefined;
965
+ /**
966
+ * Seed a starter `Document` from the schema — the main card plus one
967
+ * instance of each composable card kind, each committing its fields'
968
+ * `example:` values and leaving every other field absent (interpolated at
969
+ * render: `default:`, else type-empty zero). Illustration-first: a field
970
+ * with both an `example` and a `default` renders its example. See
971
+ * `prose/canon/SCHEMAS.md` § "Document seeding".
972
+ */
973
+ seedDocument(): Document;
974
+ /**
975
+ * Seed a starter main `Card` (carries `$quill`) from the schema — the
976
+ * `$kind: main` card of [`seedDocument`](Self::seed_document) in
977
+ * isolation, committing each field's `example:` value. Returns the same
978
+ * `Card` shape as the `Document.main` getter.
979
+ */
980
+ seedMain(): Card;
981
+ /**
982
+ * Flatten this quill back into its canonical file tree — the inverse of
983
+ * [`fromTree`](Self::from_tree). Round-trips: `Quill.fromTree(q.toTree())`
984
+ * reproduces an equivalent quill.
985
+ *
986
+ * This is how a quill crosses a WASM linear-memory boundary as data: a
987
+ * `Quill` built in one build (e.g. the Typst-less `@quillmark/wasm/core`)
988
+ * cannot be passed to an engine in another (separate linear memories), so
989
+ * `@quillmark/wasm/runtime` re-feeds this tree to the backend build's
990
+ * `Quill.fromTree` on demand. Keys are `"/"`-joined relative paths,
991
+ * matching what `fromTree` accepts.
992
+ */
993
+ toTree(): Map<string, Uint8Array>;
994
+ /**
995
+ * Validate `doc` against this quill's schema, returning every diagnostic
996
+ * (an empty array when the document is valid).
997
+ *
998
+ * Forwards the canonical `validation::*` diagnostics — same `code`,
999
+ * `path`, and `hint` the engine emits — including the non-fatal
1000
+ * `validation::must_fill` warning for each `!must_fill` marker left in
1001
+ * the document. Field values, defaults, and order are not part of this
1002
+ * surface: read them from the `Document` payload and `Quill.schema`
1003
+ * (schema key order is display order).
1004
+ */
1005
+ validate(doc: Document): Diagnostic[];
1006
+ /**
1007
+ * The *declared* backend identifier (`config.backend`, e.g. `"typst"`).
1008
+ * Intent, not a resolved capability — capability (`supportedFormats` /
1009
+ * `supportsCanvas`) is read from the engine.
1010
+ */
1011
+ readonly backendId: string;
1012
+ readonly blueprint: string;
1013
+ /**
1014
+ * Identity snapshot of the `quill:` section of `Quill.yaml` plus any extra
1015
+ * `quill:` keys. Pure config — the backend's output formats are a
1016
+ * resolved-backend capability read from the engine
1017
+ * (`Quillmark.supportedFormats`), not part of this snapshot.
1018
+ */
1019
+ readonly metadata: QuillMetadata;
1020
+ /**
1021
+ * Document schema for the quill: the user-fillable fields plus their
1022
+ * `ui` hints (title / group / compact / multiline). The single
1023
+ * field-metadata surface — drives form editors and LLM/MCP consumers
1024
+ * alike. Key order in `fields`/`properties` is declaration order — the
1025
+ * ordering contract. Returns the `QuillSchema` shape.
1026
+ */
1027
+ readonly schema: QuillSchema;
1028
+ }
1029
+
1030
+ /**
1031
+ * Render engine: a backend registry and render dispatcher. Render build only —
1032
+ * the core build constructs and validates quills without it.
1033
+ */
1034
+ export class Quillmark {
1035
+ free(): void;
1036
+ [Symbol.dispose](): void;
1037
+ constructor();
1038
+ /**
1039
+ * Open a live render session for `doc` against `quill`'s backend.
1040
+ */
1041
+ open(quill: Quill, doc: Document): LiveSession;
1042
+ /**
1043
+ * Render `doc` against `quill` in one shot. Convenience over `open` +
1044
+ * `LiveSession.render`: an unset `output_format` falls back to the
1045
+ * backend's first supported format.
1046
+ */
1047
+ render(quill: Quill, doc: Document, opts?: RenderOptions | null): RenderResult;
1048
+ /**
1049
+ * The output formats `quill`'s backend can emit. Static capability —
1050
+ * resolves the backend but compiles nothing. Throws `engine::backend_not_found`
1051
+ * if no registered backend matches the quill's declared backend.
1052
+ */
1053
+ supportedFormats(quill: Quill): OutputFormat[];
1054
+ /**
1055
+ * Pre-session hint: `true` iff `quill`'s backend can paint sessions to a
1056
+ * canvas, derived from the backend's output formats; `false` when the
1057
+ * backend is unsupported. Use as a cheap precondition probe before mounting
1058
+ * a canvas-based preview UI; the authoritative answer is the session's
1059
+ * `supportsCanvas` getter once `open()` has been called.
1060
+ */
1061
+ supportsCanvas(quill: Quill): boolean;
1062
+ }
1063
+
1064
+ /**
1065
+ * Export a canonical `RichText` corpus to its markdown projection — the pure
1066
+ * codec that replaces the eager `bodyMarkdown` / `fieldMarkdown` precomputes
1067
+ * (`exportMarkdown(card.body)`). Throws if `rt` is not a canonical corpus.
1068
+ */
1069
+ export function exportMarkdown(rt: RichText): string;
1070
+
1071
+ /**
1072
+ * Import a markdown string to a canonical `RichText` corpus — the pure,
1073
+ * document-free codec. Pair with `install(addr, importMarkdown(md))` to spell
1074
+ * the cold (anchor-losing) write at the call site; prefer `revise` for edit
1075
+ * semantics. Throws on an over-nested input.
1076
+ */
1077
+ export function importMarkdown(markdown: string): RichText;
1078
+
1079
+ /**
1080
+ * Initialize the WASM module with panic hooks for better error messages
1081
+ */
1082
+ export function init(): void;
1083
+
1084
+ /**
1085
+ * Map a base corpus position through a `delta` to its new position — the pure
1086
+ * position-mapping codec an editor bridge composes to hold a caret stable
1087
+ * across a `revise`. `assoc` decides the side of a same-position insertion
1088
+ * (`"after"` moves past it). Throws on a malformed `delta`.
1089
+ */
1090
+ export function mapPos(delta: Delta, pos: number, assoc: Assoc): number;
1091
+
1092
+ /**
1093
+ * Rebase `markdown` onto a `base` corpus — the pure, document-free twin of
1094
+ * `revise`: cold-import + `diff_import`, returning the new `corpus` and the
1095
+ * text `delta` (surviving anchors rebased). Use it to compute a revise without
1096
+ * a document in hand; `revise(addr, md)` fuses this with the store for
1097
+ * atomicity. Throws on an over-nested markdown input or a non-corpus `base`.
1098
+ */
1099
+ export function rebase(base: RichText, markdown: string): { corpus: RichText; delta: Delta };