@quillmark/wasm 0.98.0 → 0.100.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.
@@ -32,19 +32,18 @@ export type PayloadItem =
32
32
  *
33
33
  * `$` system entries are hoisted to named fields: `kind` (the `$kind`, empty
34
34
  * string when none), optional `quill` (the `$quill` `name@version`, main card
35
- * only), optional `id` (`$id`), optional `ext` (`$ext`), and optional `seed`
35
+ * only), optional `ext` (`$ext`), and optional `seed`
36
36
  * (the `$seed` per-kind overlay map, main card only). `payloadItems` carries
37
37
  * user fields and comments in order.
38
38
  */
39
39
  export interface Card {
40
40
  kind: string;
41
41
  quill?: string;
42
- id?: string;
43
42
  ext?: Record<string, unknown>;
44
43
  seed?: Record<string, unknown>;
45
44
  payloadItems: PayloadItem[];
46
45
  /**
47
- * The card body as canonical `Content` the source-of-truth content model.
46
+ * The card body as canonical `Content`: the source-of-truth content model.
48
47
  * Always this content shape on read, never a markdown string. For the markdown
49
48
  * projection call the codec `exportMarkdown(card.body)`. Write a body back
50
49
  * with `doc.install(addr, rt)` / `doc.revise(addr, md)`, or via `CardInput.body`.
@@ -53,17 +52,16 @@ export interface Card {
53
52
  }
54
53
 
55
54
  /**
56
- * A card written *into* a document the input twin of `Card`, accepted by
55
+ * A card written *into* a document: the input twin of `Card`, accepted by
57
56
  * `Document.insertCard`. Like `Card` but `body` also
58
57
  * takes a markdown `string` (imported to the content, so a markdown / LLM writer
59
- * needn't build the `Content` shape), and every field but `kind` is optional
58
+ * needn't build the `Content` shape), and every field but `kind` is optional:
60
59
  * an absent field defaults (no payload items, an empty body). Write one inline
61
60
  * (`{ kind, body }`) or build it with `Document.makeCard`.
62
61
  */
63
62
  export interface CardInput {
64
63
  kind: string;
65
64
  quill?: string;
66
- id?: string;
67
65
  ext?: Record<string, unknown>;
68
66
  seed?: Record<string, unknown>;
69
67
  payloadItems?: PayloadItem[];
@@ -71,7 +69,7 @@ export interface CardInput {
71
69
  }
72
70
 
73
71
  /**
74
- * Canonical richtext content the content model for a card body (and richtext
72
+ * Canonical richtext content: the content model for a card body (and richtext
75
73
  * fields). One text sequence over a single coordinate space (Unicode scalar
76
74
  * values): `text` plus line attributes, anchored `marks`, and embedded
77
75
  * `islands`. Every edit is a splice; markdown is a projection, not the model.
@@ -95,7 +93,7 @@ export type ContentLine = {
95
93
  continues?: boolean;
96
94
  } & ContentLineKind;
97
95
 
98
- /** A line's block role, declared once for `ContentLine` and the `setKind` op
96
+ /** A line's block role, declared once for `ContentLine` and the `setKind` op:
99
97
  * a new role is one edit here, as for `ContentContainer`. */
100
98
  export type ContentLineKind =
101
99
  | { kind: "para" }
@@ -115,7 +113,7 @@ export type ContentContainer =
115
113
 
116
114
  /** A mark over char range `[start, end)` into `Content.text`. The open `type`
117
115
  * arm blocks discriminant narrowing (as on `ContentIsland`), so read a
118
- * payload-carrying arm behind its guard `isLinkMark` (`url`) / `isAnchorMark`
116
+ * payload-carrying arm behind its guard: `isLinkMark` (`url`) / `isAnchorMark`
119
117
  * (`id`), from `@quillmark/wasm/runtime`; the bare arms carry no payload. An
120
118
  * `anchor`'s `id` is a caller-supplied, opaque handle, unique per `Content` and
121
119
  * invariant while the mark lives (positions rebase, the id never does); it has no
@@ -128,7 +126,7 @@ export type ContentMark = { start: number; end: number } & (
128
126
  | { type: string; attrs: unknown }
129
127
  );
130
128
 
131
- /** A cell in a `TableProps` its plain `text` plus the `marks` over it. `marks`
129
+ /** A cell in a `TableProps`: its plain `text` plus the `marks` over it. `marks`
132
130
  * rides the same wire shape as prose `ContentMark`, but each mark's `start`/`end`
133
131
  * are USV offsets into this cell's `text` (`0..text.length`), not into
134
132
  * `Content.text`. */
@@ -156,12 +154,16 @@ export interface ImageProps {
156
154
  * open set: the engine pins `props` as `TableProps` for `table` and `ImageProps`
157
155
  * for `image`; an island of any other type round-trips with opaque `props`. Like
158
156
  * `ContentMark`, the open `type` arm means a discriminant check does not itself
159
- * narrow `props` read `props` as the matching shape behind the `isTableIsland` /
157
+ * narrow `props`: read `props` as the matching shape behind the `isTableIsland` /
160
158
  * `isImageIsland` guards (from `@quillmark/wasm/runtime`), which narrow it. */
159
+ /** How faithfully the markdown projection can carry an island. Open like an
160
+ * island `type`: a class this build does not know round-trips verbatim, and
161
+ * reads as `unrepresentable`. */
162
+ export type ContentLossClass = "lossless" | "degraded" | "unrepresentable" | (string & {});
163
+
161
164
  export type ContentIsland = {
162
165
  id: string;
163
- /** How faithfully the markdown projection can carry this island. */
164
- loss: "lossless" | "degraded" | "unrepresentable";
166
+ loss: ContentLossClass;
165
167
  } & (
166
168
  | { type: "table"; props: TableProps }
167
169
  | { type: "image"; props: ImageProps }
@@ -169,14 +171,14 @@ export type ContentIsland = {
169
171
  );
170
172
 
171
173
  /**
172
- * A write address one navigation concept for the whole `Document` surface. An
174
+ * A write address: one navigation concept for the whole `Document` surface. An
173
175
  * absent `field` targets the card body; an absent `card` targets the main card.
174
176
  * `{}` is the main-card body; `{ card: 2 }` the body of the composable card at
175
177
  * index 2; `{ field: "intro" }` the main card's `intro` field; `{ card: 2,
176
178
  * field: "intro" }` a card field.
177
179
  *
178
180
  * On the `Addr`-taking verbs a **bare string** is shorthand for `{ field: name }`
179
- * `doc.storeField("qty", 3)`, `doc.revise("intro", md)` the one coercion
181
+ * (`doc.storeField("qty", 3)`, `doc.revise("intro", md)`) the one coercion
180
182
  * rule. A bare number is *not* an addr (`{ card: 2 }` is the self-documenting
181
183
  * spelling), so no third navigation idiom re-fragments the surface.
182
184
  */
@@ -186,7 +188,7 @@ export interface Addr {
186
188
  }
187
189
 
188
190
  /**
189
- * A card-only address the axis the card-scoped verbs (`storeFields`,
191
+ * A card-only address: the axis the card-scoped verbs (`storeFields`,
190
192
  * `storeExt`, `getExt`, `commitFields`, …) take. An absent `card` targets the
191
193
  * main card. A present `field` throws: a card address takes only `card`, and a
192
194
  * would-be nested write is a bug the error names rather than silently ignores.
@@ -197,7 +199,7 @@ export interface CardAddr {
197
199
 
198
200
  /**
199
201
  * A text-splice change set over the USV content (CodeMirror `ChangeSet`
200
- * semantics) plain, structured-clone-able data. Returned by `revise` and by
202
+ * semantics): plain, structured-clone-able data. Returned by `revise` and by
201
203
  * the `rebase` codec; map a stored position through it with `mapPos`.
202
204
  */
203
205
  export interface Delta {
@@ -211,7 +213,7 @@ export type Assoc = "before" | "after";
211
213
  * A mark edit in final-text coordinates (post-delta, post-line-op). `add` /
212
214
  * `remove` carry the `ContentMark` vocabulary (`{ type, … }`); `removeAnchor`
213
215
  * drops one identity anchor by id. An `add` of an `anchor` requires a non-empty
214
- * `id` not already live in the field a collision or the empty id throws
216
+ * `id` not already live in the field: a collision or the empty id throws
215
217
  * (ids are caller-supplied and unique per `Content`; DOCUMENT_STORAGE
216
218
  * § Anchor-id identity).
217
219
  */
@@ -227,7 +229,7 @@ export type MarkOp =
227
229
  /**
228
230
  * A line/block edit. `split`/`join` splice `\n`; `setKind`/`setContainers`/
229
231
  * `setContinues` touch metadata. `setContinues` sets/clears a line's within-block
230
- * hard-break flag (`ContentLine.continues`) the op-grained way to lower a
232
+ * hard-break flag (`ContentLine.continues`): the op-grained way to lower a
231
233
  * Shift+Enter hard break or a new code-fence interior line; `continues: true` on
232
234
  * line 0 is rejected (nothing precedes it to continue).
233
235
  */
@@ -253,7 +255,7 @@ export interface ChangeBundle {
253
255
 
254
256
  /**
255
257
  * One segment of a parsed `Diagnostic.path` (see `parseDocPath`). The head
256
- * carries the document-model root `main` (only before `body`), a `card`
258
+ * carries the document-model root: `main` (only before `body`), a `card`
257
259
  * (`kind: null` is the unknown-kind `cards[i]` form), or a `field`; the tail is
258
260
  * `field` / `index` / a terminal `body`.
259
261
  */
@@ -268,7 +270,7 @@ export type DocPathSeg =
268
270
 
269
271
  /**
270
272
  * Page dimensions in points (1 pt = 1/72 inch). Typst measures in Typst
271
- * points; pdfform measures in PDF points the same unit.
273
+ * points; pdfform measures in PDF points: the same unit.
272
274
  *
273
275
  * Report-only: the painter sizes the canvas itself based on
274
276
  * `PaintOptions`. `pageSize` is exposed for callers that need page
@@ -284,16 +286,16 @@ export interface PageSize {
284
286
  * Inputs to `LiveSession.paint`. Both fields are optional and default
285
287
  * to `1`.
286
288
  *
287
- * - `layoutScale` layout-space pixels per point (Typst point / PDF
288
- * point the same 1/72″ unit). For on-screen
289
+ * - `layoutScale` (layout-space pixels per point (Typst point / PDF
290
+ * point) the same 1/72″ unit). For on-screen
289
291
  * canvases this is CSS pixels per pt; the page's layout-pixel size is
290
292
  * `widthPt * layoutScale × heightPt * layoutScale`. The painter
291
293
  * surfaces these dimensions as `layoutWidth` / `layoutHeight` so
292
294
  * consumers can drive `canvas.style.*` (or any layout system).
293
- * - `densityScale` backing-store density multiplier. Fold
295
+ * - `densityScale`: backing-store density multiplier. Fold
294
296
  * `window.devicePixelRatio`, in-app zoom, and `visualViewport.scale`
295
297
  * (pinch-zoom) into a single value here. Defaults to `1`, which
296
- * produces a non-retina backing store pass `window.devicePixelRatio`
298
+ * produces a non-retina backing store: pass `window.devicePixelRatio`
297
299
  * for crisp output on high-DPI displays.
298
300
  *
299
301
  * The effective rasterization scale is `layoutScale * densityScale`.
@@ -309,22 +311,22 @@ export interface PaintOptions {
309
311
  /**
310
312
  * Returned by `LiveSession.paint`.
311
313
  *
312
- * - `layoutWidth` / `layoutHeight` layout-pixel dimensions of the
314
+ * - `layoutWidth` / `layoutHeight`: layout-pixel dimensions of the
313
315
  * canvas's display box. For on-screen canvases this is CSS pixels:
314
316
  * set `canvas.style.width = layoutWidth + "px"` and
315
317
  * `canvas.style.height = layoutHeight + "px"` (or feed these into
316
318
  * your layout system). Independent of `densityScale`.
317
- * - `pixelWidth` / `pixelHeight` integer backing-store pixel
319
+ * - `pixelWidth` / `pixelHeight`: integer backing-store pixel
318
320
  * dimensions the painter wrote to `canvas.width` / `canvas.height`.
319
321
  * Equal to `round(layoutWidth * densityScale)` ×
320
322
  * `round(layoutHeight * densityScale)` *unless* the requested backing
321
323
  * exceeded the painter's safe maximum (16384 px per side), in which
322
324
  * case `densityScale` was clamped to fit.
323
- * - `clamped` `true` when that 16384-px clamp fired, so the page is
325
+ * - `clamped`: `true` when that 16384-px clamp fired, so the page is
324
326
  * painted at fewer device pixels than requested and renders soft at the
325
327
  * same `canvas.style` size. Reads the clamp off the return value instead
326
328
  * of the `pixelWidth < round(layoutWidth * densityScale)` derivation.
327
- * - `effectiveDensityScale` the `densityScale` actually applied: the
329
+ * - `effectiveDensityScale`, the `densityScale` actually applied: the
328
330
  * requested value unless `clamped`, then reduced proportionally.
329
331
  * `layoutScale * effectiveDensityScale` is the scale the backing store
330
332
  * was rasterized at.
@@ -333,11 +335,11 @@ export interface PaintOptions {
333
335
  * write to them. The painter does **not** touch `canvas.style.*`;
334
336
  * consumers own layout. The write is a whole-backing-store `putImageData`,
335
337
  * which bypasses the 2D context transform, `globalAlpha`, and clip: give
336
- * each visible page its own `` you cannot composite two pages, a
338
+ * each visible page its own `<canvas>`; you cannot composite two pages, a
337
339
  * sub-rect, or a context transform through `paint`.
338
340
  *
339
341
  * For `OffscreenCanvasRenderingContext2D` (Worker rasterization, no
340
- * DOM), `layoutWidth` / `layoutHeight` are informational there's no
342
+ * DOM), `layoutWidth` / `layoutHeight` are informational: there's no
341
343
  * CSS layout box to apply them to.
342
344
  */
343
345
  export interface PaintResult {
@@ -356,7 +358,7 @@ export type FieldSource = "authored" | "default" | "zero";
356
358
 
357
359
  /**
358
360
  * One resolved row: its `name`, the value the render projection would use, and
359
- * the `FieldSource` rung it came from. Rows are an ordered array declaration
361
+ * the `FieldSource` rung it came from. Rows are an ordered array: declaration
360
362
  * order is structural, not object-key order. The card body is a `body` sibling
361
363
  * on its card, never a row in `fields`. Diagnostics stay `Quill.validate`'s;
362
364
  * schema guidance (`example:`, labels) reads from `Quill.schema`.
@@ -368,7 +370,7 @@ export interface ResolvedField {
368
370
  }
369
371
 
370
372
  /**
371
- * The main card's resolved rows in declaration order, plus its body row
373
+ * The main card's resolved rows in declaration order, plus its body row:
372
374
  * `null` when the main enables no body.
373
375
  */
374
376
  export interface ResolvedMain {
@@ -379,7 +381,7 @@ export interface ResolvedMain {
379
381
  /**
380
382
  * One composable card's resolved rows in declaration order, with its authored
381
383
  * `kind` (`null` for an unknown-kind card), its document-array `index`, and its
382
- * body row `null` when the kind enables no body.
384
+ * body row: `null` when the kind enables no body.
383
385
  */
384
386
  export interface ResolvedCard {
385
387
  kind: string | null;
@@ -390,7 +392,7 @@ export interface ResolvedCard {
390
392
 
391
393
  /**
392
394
  * The resolved-value view (`Quill.resolve`): the main card and every
393
- * composable card. Value and provenance only completeness and errors stay
395
+ * composable card. Value and provenance only: completeness and errors stay
394
396
  * `Quill.validate`.
395
397
  */
396
398
  export interface Resolved {
@@ -411,7 +413,7 @@ export interface QuillFieldUi {
411
413
  }
412
414
 
413
415
  /** One entry in a card's `ui.groups` registry: a display-label override for the
414
- * group id (the map key). An empty object carries no override the consumer
416
+ * group id (the map key). An empty object carries no override: the consumer
415
417
  * derives the label from the id (`memo_for` → "Memo For"), as it does a field
416
418
  * label from its key. */
417
419
  export interface QuillGroupUi {
@@ -423,7 +425,7 @@ export interface QuillCardUi {
423
425
  title?: string;
424
426
  /** The card's group registry: the ordered table of contents naming every
425
427
  * group a field's `ui.group` may reference. The map key is the group id, and
426
- * key order is declaration order the display-order contract, the same one
428
+ * key order is declaration order: the display-order contract, the same one
427
429
  * `fields` key order carries. Absent when the card declares no groups (or
428
430
  * uses the deprecated implicit-group form). */
429
431
  groups?: Record<string, QuillGroupUi>;
@@ -461,7 +463,7 @@ export interface QuillFieldSchema {
461
463
  properties?: Record<string, QuillFieldSchema>;
462
464
  items?: QuillFieldSchema;
463
465
  /** Present (and `true`) on a `richtext` or `plaintext` field declared
464
- * `inline` the single-paragraph, container-free, island-free constraint.
466
+ * `inline`: the single-paragraph, container-free, island-free constraint.
465
467
  * Core serializes `inline: true` into the schema JSON; absent otherwise. */
466
468
  inline?: boolean;
467
469
  }
@@ -502,67 +504,215 @@ export interface QuillMetadata {
502
504
  }
503
505
 
504
506
 
505
- export interface Artifact {
506
- format: OutputFormat;
507
- bytes: Uint8Array;
508
- mimeType: string;
509
- }
510
-
511
- export interface ChangeSet {
512
- pageCount: number;
513
- dirtyPages: number[];
507
+ /**
508
+ * A rendered field region: the quill schema field address plus its geometry on
509
+ * the page. Emitted for schema-bound fields: span-tracked content (richtext
510
+ * bodies, `richtext[]` elements, card content fields, direct scalar
511
+ * references) and form-field widgets (pdfform AcroForm, Typst `form-field`).
512
+ * Consumers use it to scroll to / highlight the focused field; for the
513
+ * reverse click direction use `LiveSession.fieldAt`, which answers over any
514
+ * placement. Geometry only: the raster is already complete, so a region is
515
+ * never a compositing input.
516
+ *
517
+ * `field` is **not** unique: content fields surface one region **per segment**
518
+ * (paragraph, heading, whole code fence) and per page each touches, a scalar
519
+ * referenced at several plate sites surfaces each site, and tracked content
520
+ * plus a `field:`-bound widget yields both. Group by `field`: every entry
521
+ * routes to that field. The whole-field highlight is the **union of a page\'s
522
+ * `span`-bearing segment rects**, so inter-paragraph whitespace stays
523
+ * uncovered; `LiveSession.fieldBoxes(field)` owns that union so
524
+ * consumers need not derive it. Later placements of one content value are not
525
+ * enumerated; `fieldAt` / `positionAt` still resolve clicks on them.
526
+ */
527
+ export interface FieldRegion {
528
+ /**
529
+ * Canonical `DocPath` field address (e.g. `\"signature_block\"`,
530
+ * `\"cards.indorsement[1].from\"`, `\"main.body\"`): the same grammar
531
+ * `parseDocPath` reads and `Diagnostic.path` carries. The session resolves
532
+ * the backend\'s plate-space per-kind ordinal to this absolute-index form,
533
+ * so one parser routes every address. Feed it back to `fieldBoxes` /
534
+ * `locate`; hit-test the click direction with `fieldAt` / `positionAt`.
535
+ */
536
+ field: string;
537
+ /**
538
+ * 0-based page index.
539
+ */
540
+ page: number;
541
+ /**
542
+ * `[x0, y0, x1, y1]` in PDF points (1/72″), bottom-left origin.
543
+ */
544
+ rect: [number, number, number, number];
545
+ /**
546
+ * The content slice this box covers: USV `[start, end)` into the field\'s
547
+ * `Content` for content ink (one segment), `undefined` for a scalar
548
+ * reference site or widget. Consumers key segment highlights on it;
549
+ * `fieldBoxes(field)` unions same-page segments for the whole-field box.
550
+ */
551
+ span?: [number, number];
514
552
  }
515
553
 
554
+ /**
555
+ * A resolved point → content position: the field a click landed in and the USV
556
+ * offset into its `Content`. The `LiveSession.positionAt` result, paired with
557
+ * `locate` (content position → caret rect). `pos` is cluster-exact and degrades
558
+ * to the containing segment\'s start on origin-less ink; `granularity` reports
559
+ * which happened so a caret UI need not guess.
560
+ */
516
561
  export interface ContentHit {
562
+ /**
563
+ * Canonical `DocPath` field address (same grammar as `FieldRegion.field`).
564
+ */
517
565
  field: string;
566
+ /**
567
+ * USV offset into the field\'s `Content`.
568
+ */
518
569
  pos: number;
570
+ /**
571
+ * Whether `pos` is cluster-exact or floored to the segment start
572
+ * (`HitGranularity`). `undefined` when the backend does not report it.
573
+ * Additive-optional.
574
+ */
519
575
  granularity?: HitGranularity;
520
576
  }
521
577
 
578
+ /**
579
+ * Diagnostic message (error or warning)
580
+ */
522
581
  export interface Diagnostic {
523
582
  severity: Severity;
524
583
  code?: string;
525
584
  message: string;
526
585
  location?: Location;
586
+ /**
587
+ * Document-model path anchor (e.g. `\"cards.indorsement[0].signature_block\"`).
588
+ *
589
+ * Set on schema validation diagnostics; `undefined` otherwise. See the
590
+ * Rust `quillmark_core::error` module docs for the path grammar.
591
+ */
527
592
  path?: string;
528
593
  hint?: string;
594
+ /**
595
+ * The facts `message` interpolates, keyed by name. With `code`, the
596
+ * substitution unit needed to word this diagnostic in another language;
597
+ * `prose/canon/ERROR.md` § \"Diagnostic args\" tabulates the keys per code.
598
+ *
599
+ * Declared optional explicitly because `tsify` does not read
600
+ * `skip_serializing_if`: without this, a field the runtime omits is
601
+ * declared required. `sourceChain` carries that mismatch.
602
+ */
603
+ args?: Record<string, unknown>;
529
604
  sourceChain?: string[];
530
605
  }
531
606
 
532
- export interface FieldRegion {
533
- field: string;
534
- page: number;
535
- rect: [number, number, number, number];
536
- span?: [number, number];
537
- }
538
-
539
- export interface Location {
540
- file: string;
541
- line: number;
542
- column: number;
543
- }
607
+ /**
608
+ * How precisely a `ContentHit.pos` resolved: the marker a caret UI reads to
609
+ * decide whether to trust the offset. Never sub-cluster: `cluster` is the
610
+ * finest this API offers, `segment` the floor it degrades to on origin-less
611
+ * ink.
612
+ */
613
+ export type HitGranularity = "cluster" | "segment";
544
614
 
615
+ /**
616
+ * Options for rendering.
617
+ */
545
618
  export interface RenderOptions {
546
619
  format?: OutputFormat;
620
+ /**
621
+ * Pixels per inch for raster output formats (PNG).
622
+ * Ignored for vector/document formats (PDF, SVG).
623
+ * Defaults to 144.0 (2x at 72pt/inch) when omitted.
624
+ */
547
625
  ppi?: number;
626
+ /**
627
+ * Optional 0-based page indices to render (e.g., `[0, 2]` for the
628
+ * first and third pages). `undefined` renders all pages. Any index
629
+ * `>= pageCount` throws with the `typst::page_index_out_of_bounds`
630
+ * code: read `LiveSession.pageCount` first if validation is needed.
631
+ * **Not supported for PDF output**: passing `pages` with
632
+ * `format: \"pdf\"` throws with the
633
+ * `typst::pdf_page_selection_not_supported` code.
634
+ */
548
635
  pages?: number[];
636
+ /**
637
+ * Override for the PDF `/Info` `/Producer` metadata string. Omit to use
638
+ * the default (`Quillmark <version>`). Applies to PDF output only.
639
+ */
549
640
  producer?: string;
641
+ /**
642
+ * Populate `RenderResult.regions` with the schema-field geometry sidecar
643
+ * (the same entries `LiveSession.regions()` serves), for consumers
644
+ * without a live session; e.g. overlays over a one-shot SVG export.
645
+ * Defaults to `false`: exports pay no introspection cost. The sidecar
646
+ * always describes the whole document: page indices are document-space
647
+ * even when `pages` selects a subset.
648
+ */
550
649
  regions?: boolean;
551
650
  }
552
651
 
652
+ /**
653
+ * Output formats supported by backends.
654
+ *
655
+ * Gated behind the engine surface (`typst` or `pdfform`) so tsify omits
656
+ * its `.d.ts` interface from the core bundle (`pkg/core/wasm.d.ts`), which
657
+ * has no rendering surface.
658
+ */
659
+ export type OutputFormat = "pdf" | "svg" | "png";
660
+
661
+ /**
662
+ * Rendered artifact (PDF, SVG, etc.).
663
+ */
664
+ export interface Artifact {
665
+ format: OutputFormat;
666
+ /**
667
+ * Serialized via `serde_bytes` so `serde_wasm_bindgen` emits a real
668
+ * `Uint8Array` at the boundary instead of a `number[]`. Without this
669
+ * annotation, the declared `Uint8Array` type would silently lie.
670
+ */
671
+ bytes: Uint8Array;
672
+ mimeType: string;
673
+ }
674
+
675
+ /**
676
+ * Result of a render operation.
677
+ */
553
678
  export interface RenderResult {
554
679
  artifacts: Artifact[];
555
680
  warnings: Diagnostic[];
556
681
  outputFormat: OutputFormat;
557
682
  renderTimeMs: number;
683
+ /**
684
+ * Schema-field geometry sidecar: populated only when
685
+ * `RenderOptions.regions` requested it; empty otherwise. The same entries
686
+ * `LiveSession.regions()` serves, for consumers without a live session.
687
+ * Page indices are document-space even under a `pages` subset render.
688
+ */
558
689
  regions: FieldRegion[];
559
690
  }
560
691
 
561
- export type HitGranularity = "cluster" | "segment";
692
+ /**
693
+ * Severity levels for diagnostics
694
+ */
695
+ export type Severity = "error" | "warning";
562
696
 
563
- export type OutputFormat = "pdf" | "svg" | "png";
697
+ /**
698
+ * Source location for errors and warnings
699
+ */
700
+ export interface Location {
701
+ file: string;
702
+ line: number;
703
+ column: number;
704
+ }
564
705
 
565
- export type Severity = "error" | "warning";
706
+ /**
707
+ * What a committed `LiveSession.apply` changed. `dirtyPages` lists the pages
708
+ * whose rendered content differs from the previous compile, including pages
709
+ * the edit added; removed pages are implied by `pageCount`. A preview
710
+ * repaints `dirty ∩ visible` and nothing else.
711
+ */
712
+ export interface ChangeSet {
713
+ pageCount: number;
714
+ dirtyPages: number[];
715
+ }
566
716
 
567
717
 
568
718
  /**
@@ -573,7 +723,7 @@ export class Document {
573
723
  [Symbol.dispose](): void;
574
724
  /**
575
725
  * **Apply** a committed content edit `bundle` (`{ delta?, lineOps?, markOps? }`)
576
- * at `addr` the editor splice: text delta first, then line ops, then mark
726
+ * at `addr`, the editor splice: text delta first, then line ops, then mark
577
727
  * ops (mark ranges in final-text coordinates), each all-or-nothing. An absent
578
728
  * `addr.field` targets the body, an absent `addr.card` the main card.
579
729
  *
@@ -590,20 +740,13 @@ export class Document {
590
740
  */
591
741
  static blueprintInstruction(quill_name: string): string;
592
742
  /**
593
- * A single composable card by index the whole `Card`, the card-indexed
743
+ * A single composable card by index: the whole `Card`, the card-indexed
594
744
  * twin of the [`main`](Self::main) getter, so reading one card need not
595
745
  * materialize every card via [`cards`](Self::cards). An out-of-range
596
746
  * `index` throws `edit::index_out_of_range`, matching the card write
597
747
  * verbs.
598
748
  */
599
749
  card(index: number): Card;
600
- /**
601
- * The index of the composable card whose `$id` equals `id`, or
602
- * `undefined` when none carries it. Resolves the durable card handle
603
- * without a hand-rolled scan over [`cards`](Self::cards); `$id` is
604
- * unique per document, so at most one card matches.
605
- */
606
- cardIndexById(id: string): number | undefined;
607
750
  clone(): Document;
608
751
  /**
609
752
  * Schema version this build writes via [`toJson`](Document::to_json).
@@ -645,54 +788,63 @@ export class Document {
645
788
  static fromMarkdown(markdown: string): Document;
646
789
  /**
647
790
  * The whole `$ext` map at `addr` (a card address, absent `card` = main), or
648
- * `undefined` when the card carries none. The fine-grained `$ext` read
791
+ * `undefined` when the card carries none. The fine-grained `$ext` read:
649
792
  * your own state without serializing the whole card. Throws on a present
650
793
  * `field` (a card address takes only `card`) or an out-of-range card.
651
794
  */
652
795
  getExt(addr?: CardAddr): Record<string, unknown> | undefined;
653
796
  /**
654
797
  * The value stored under `$ext[ns]` at `addr` (a card address, absent `card`
655
- * = main), or `undefined`. The namespace-scoped `$ext` read your own slot
798
+ * = main), or `undefined`. The namespace-scoped `$ext` read: your own slot
656
799
  * without a whole-card serialize, and non-destructive (unlike
657
800
  * `removeExtNamespace`). Throws on a present `field` or an out-of-range card.
658
801
  */
659
802
  getExtNamespace(addr: CardAddr, ns: string): unknown;
660
803
  /**
661
- * The **body** markdown projection the main body, or a composable card's
662
- * body (`{ card }`) the on-demand, lossy export (content-only marks do not
804
+ * The **body** markdown projection (the main body, or a composable card's
805
+ * body (`{ card }`)) the on-demand, lossy export (content-only marks do not
663
806
  * survive markdown). A body's type is a format fact, not a schema fact, so
664
807
  * this read stays quill-free; a body is never absent.
665
808
  *
666
809
  * `addr` is an optional **card address** (`{ card }`, absent = main). A
667
- * present `field` throws a field's markdown is read through the
810
+ * present `field` throws: a field's markdown is read through the
668
811
  * schema-plane `quill.reader(doc).get(field)`, which interprets by declared
669
- * type (#978). An out-of-range `addr.card` throws.
812
+ * type. An out-of-range `addr.card` throws.
670
813
  */
671
814
  getMarkdown(addr?: CardAddr): string;
672
815
  /**
673
- * Read the **verbatim stored value** at `addr` the raw payload value of a
674
- * field (a content object for a richtext field, a scalar/array/object
675
- * otherwise), or the **body content** when `addr.field` is absent. A bare
816
+ * Read the **verbatim stored value** at `addr`: the raw payload value of a
817
+ * field, or the **body content** when `addr.field` is absent. A bare
676
818
  * string is `Addr` shorthand for `{ field }`. Reads are total over the field
677
819
  * axis: an absent field is `undefined`; only an out-of-range `addr.card`
678
820
  * throws `edit::index_out_of_range`. Needs no schema, so it lives on
679
- * `Document` the read echo of the verbatim `store*` write, distinct from
821
+ * `Document`: the read echo of the verbatim `store*` write, distinct from
680
822
  * the interpreted schema-plane [`reader.get`](Self::reader_get). For the
681
823
  * markdown projection use [`getMarkdown`](Self::get_markdown) (body) or
682
824
  * `reader.get` (a field's declared type).
825
+ *
826
+ * **A content field at rest has one stored form per codec**: a `richtext`
827
+ * field holds the canonical content object, a `plaintext` field its literal
828
+ * string. A document that came through the bound door (`quill.parse` /
829
+ * `quill.conform`) is at rest, so this read no longer depends on which lane
830
+ * built it. A document that came through the transport door
831
+ * (`Document.fromMarkdown`, a legacy stored row) may rest as authored until
832
+ * it is conformed, and this read reports what is there. For the corpus
833
+ * either way, use the schema-plane `reader.getContent`, which decodes
834
+ * through the codec the field's declared type names.
683
835
  */
684
836
  getStored(addr: Addr | string): unknown;
685
837
  /**
686
- * Insert a card the single insertion verb: `at` absent appends, a number
838
+ * Insert a card, the single insertion verb: `at` absent appends, a number
687
839
  * inserts at that index (must be in `0..=cards.length`). Accepts a
688
- * `CardInput` a card read back (`cards` / `removeCard` / `quill.seedCard`),
840
+ * `CardInput`: a card read back (`cards` / `removeCard` / `quill.seedCard`),
689
841
  * a [`makeCard`](Document::make_card) result, or a bare `{ kind, body }`
690
842
  * (every returned `Card` is a valid `CardInput`). Throws if `card.kind` is
691
843
  * not a valid kind name, or if `at` is out of range.
692
844
  */
693
845
  insertCard(card: CardInput, at?: number): void;
694
846
  /**
695
- * **Install** a richtext value at `addr` **value semantics**, content only.
847
+ * **Install** a richtext value at `addr`: **value semantics**, content only.
696
848
  * Stores exactly `rt` (a canonical `Content` content object); the identity
697
849
  * anchors of any previous value are gone. An absent `addr.field` targets the
698
850
  * body, an absent `addr.card` the main card. For "here's new markdown," use
@@ -706,25 +858,25 @@ export class Document {
706
858
  install(addr: Addr | string, rt: Content): void;
707
859
  /**
708
860
  * Whether the field at `addr` is marked `!must_fill`. A bare string is `Addr`
709
- * shorthand for `{ field }`. `false` for an absent field (truthful it isn't
861
+ * shorthand for `{ field }`. `false` for an absent field (truthful: it isn't
710
862
  * marked) and for a body address (a body is never a fill). Only an
711
863
  * out-of-range `addr.card` throws.
712
864
  */
713
865
  isFill(addr: Addr | string): boolean;
714
866
  /**
715
867
  * Replace this document's contents **in place** from a versioned storage
716
- * DTO string the mutating twin of the static
868
+ * DTO string: the mutating twin of the static
717
869
  * [`fromJson`](Document::from_json) constructor. Parse-time `warnings` are
718
870
  * cleared. Throws (leaving the document unchanged) on an invalid DTO.
719
871
  *
720
872
  * The cross-WASM-memory `Document` bridge: mutate a document on a
721
873
  * backend-memory clone, then write the mutated state back into the caller's
722
- * canonical document with this the one way to update a live handle across
874
+ * canonical document with this, the one way to update a live handle across
723
875
  * the linear-memory seam without the caller re-binding its variable.
724
876
  */
725
877
  loadJson(json: string): void;
726
878
  /**
727
- * Build a fresh `Card` from a kind and a flat field map the ergonomic
879
+ * Build a fresh `Card` from a kind and a flat field map: the ergonomic
728
880
  * constructor for `insertCard`. `fields` is an optional
729
881
  * `Record<string, unknown>` (each entry becomes a card field, in
730
882
  * insertion order); `body` defaults to `""`.
@@ -734,8 +886,8 @@ export class Document {
734
886
  * here.
735
887
  *
736
888
  * Checks only what a detached card can decide alone: field-name grammar
737
- * and value depth. Kind validity is positional `main` is right for the
738
- * root, reserved for a composable card so `insertCard` is its gate, and
889
+ * and value depth. Kind validity is positional (`main` is right for the
890
+ * root, reserved for a composable card) so `insertCard` is its gate, and
739
891
  * any kind string is accepted here.
740
892
  */
741
893
  static makeCard(kind: string, fields?: Record<string, unknown>, body?: string): Card;
@@ -744,7 +896,7 @@ export class Document {
744
896
  */
745
897
  moveCard(from: number, to: number): void;
746
898
  /**
747
- * `new Document(quillRef)` a blank document: a main card carrying only
899
+ * `new Document(quillRef)`, a blank document: a main card carrying only
748
900
  * `$quill`, an empty body, and no composable cards. The programmatic
749
901
  * blank canvas: absent fields resolve at render time (`default`, else
750
902
  * type-empty zero), so nothing the caller did not set reaches the
@@ -755,7 +907,7 @@ export class Document {
755
907
  /**
756
908
  * The canonical `$quill` reference grammar as author-facing text. Core is
757
909
  * the single source of truth: drive schema `describe` and validation
758
- * messages from this instead of re-stating the rule it matches the
910
+ * messages from this instead of re-stating the rule; it matches the
759
911
  * `hint` on `parse::invalid_quill_reference`. Cache it; the value never
760
912
  * changes.
761
913
  */
@@ -763,7 +915,7 @@ export class Document {
763
915
  removeCard(index: number): Card | undefined;
764
916
  /**
765
917
  * Remove the `$ext` map on the card `addr` targets *entirely*, returning the
766
- * previous map or `undefined` a blunt escape hatch that discards every
918
+ * previous map or `undefined`: a blunt escape hatch that discards every
767
919
  * namespace at once (prefer `removeExtNamespace`). `addr` is a card address
768
920
  * (absent = main). Throws on a present `field` or an out-of-range card.
769
921
  */
@@ -789,7 +941,7 @@ export class Document {
789
941
  */
790
942
  removeSeedNamespace(card_kind: string): any;
791
943
  /**
792
- * **Revise** the richtext value at `addr` from a markdown string **edit
944
+ * **Revise** the richtext value at `addr` from a markdown string: **edit
793
945
  * semantics**, the default write path, returning the text `Delta`. Imports
794
946
  * the markdown, diffs it against the current value, rebases surviving
795
947
  * identity anchors, and returns the change an editor bridge maps its own
@@ -802,7 +954,7 @@ export class Document {
802
954
  revise(addr: Addr | string, markdown: string): Delta;
803
955
  /**
804
956
  * Read the `schema` version tag from a raw storage DTO string without a
805
- * full parse, or `undefined`. Returns unknown future versions as-is
957
+ * full parse, or `undefined`. Returns unknown future versions as-is:
806
958
  * useful to distinguish "build too old" from "payload corrupt" when
807
959
  * `fromJson` throws.
808
960
  */
@@ -811,7 +963,7 @@ export class Document {
811
963
  * The main card's `$seed` overlay object for `kind` (the `$seed[kind]`
812
964
  * entry), or `undefined` when absent. The cheap read that feeds
813
965
  * `quill.seedCard(kind, overlay)` without serializing the whole main card
814
- * via [`main`](Self::main) to fish out one key and it keeps `seedCard`
966
+ * via [`main`](Self::main) to fish out one key, and it keeps `seedCard`
815
967
  * pure: the quill still never reads the document.
816
968
  */
817
969
  seedOverlay(kind: string): Record<string, unknown> | undefined;
@@ -829,41 +981,41 @@ export class Document {
829
981
  * Replace the opaque `$ext` map on the card `addr` targets (a card address,
830
982
  * absent `card` = main). `value` must be a plain object. `$ext` carries
831
983
  * out-of-band consumer state and never reaches the rendered output; pass
832
- * `{}` for an explicit empty `$ext`. Quill-free and verbatim an opaque
984
+ * `{}` for an explicit empty `$ext`. Quill-free and verbatim: an opaque
833
985
  * `store` verb. Throws on a present `field` or an out-of-range card.
834
986
  */
835
987
  storeExt(addr: CardAddr, value: any): void;
836
988
  /**
837
989
  * Merge `value` into `$ext[ns]` on the card `addr` targets, preserving
838
- * sibling namespaces the recommended `$ext` write. `addr` is a card
839
- * address (absent = main). Quill-free and verbatim an opaque `store` verb.
990
+ * sibling namespaces: the recommended `$ext` write. `addr` is a card
991
+ * address (absent = main). Quill-free and verbatim: an opaque `store` verb.
840
992
  * Throws on a present `field` or an out-of-range card.
841
993
  */
842
994
  storeExtNamespace(addr: CardAddr, ns: string, value: any): void;
843
995
  /**
844
- * Store a field verbatim at `addr` the opaque store (**store** = verbatim,
996
+ * Store a field verbatim at `addr`: the opaque store (**store** = verbatim,
845
997
  * coercion deferred to render; the typed write is
846
998
  * [`commitField`](Document::commit_field)). A bare string is `Addr`
847
999
  * shorthand for `{ field }`, so `doc.storeField("qty", 3)` reads as written;
848
1000
  * `{ card: 2, field: "qty" }` targets a composable card. Clears any
849
- * `!must_fill` marker. A body address (no `field`) throws a body is never
1001
+ * `!must_fill` marker. A body address (no `field`) throws: a body is never
850
1002
  * opaque; write it with `revise` / `install` / `writer.setBody`. Throws on
851
1003
  * an out-of-range card or a malformed name.
852
1004
  */
853
1005
  storeField(addr: Addr | string, value: any): void;
854
1006
  /**
855
- * Store several fields verbatim and atomically on the card `addr` targets
1007
+ * Store several fields verbatim and atomically on the card `addr` targets:
856
1008
  * the opaque store's batch. `addr` is a **card address** (`{ card }`, absent
857
1009
  * = main); a present `field` throws. The batch verb takes the address first
858
1010
  * and is never shape-overloaded, because `card` is a legal field name:
859
1011
  * `storeFields({}, fields)` is the main card, `storeFields({ card: 2 },
860
- * fields)` a composable one never ambiguous with "set field `card`".
1012
+ * fields)` a composable one, never ambiguous with "set field `card`".
861
1013
  * Nothing is applied on error; the thrown error's `diagnostics` carry one
862
1014
  * entry per offending field. Throws on an out-of-range card.
863
1015
  */
864
1016
  storeFields(addr: CardAddr, fields: Record<string, unknown>): void;
865
1017
  /**
866
- * Store a field verbatim at `addr` and mark it `!must_fill` the opaque
1018
+ * Store a field verbatim at `addr` and mark it `!must_fill`: the opaque
867
1019
  * store's fill variant, card-capable (a bare string or `{ field }` for main,
868
1020
  * `{ card, field }` for a composable card). A body address throws. Same
869
1021
  * validation as [`storeField`](Document::store_field).
@@ -871,9 +1023,9 @@ export class Document {
871
1023
  storeFill(addr: Addr | string, value: any): void;
872
1024
  /**
873
1025
  * Merge a card-kind's seed `overlay` into the **main** card's `$seed` map
874
- * under `cardKind`, preserving sibling kinds `$seed` lives on the main
1026
+ * under `cardKind`, preserving sibling kinds: `$seed` lives on the main
875
1027
  * card by model, so this takes no address. Sets the starting values new
876
- * cards of that kind spawn with. Quill-free and verbatim an opaque `store`
1028
+ * cards of that kind spawn with. Quill-free and verbatim: an opaque `store`
877
1029
  * verb. Throws if `overlay` cannot be serialized or nests too deep.
878
1030
  */
879
1031
  storeSeedNamespace(card_kind: string, overlay: any): void;
@@ -881,7 +1033,7 @@ export class Document {
881
1033
  * Serialize this document to a versioned storage DTO string.
882
1034
  *
883
1035
  * Prefer this over `toMarkdown` for persistence across restarts or crate
884
- * upgrades the wire format is frozen per `schema` version. Parse-time
1036
+ * upgrades: the wire format is frozen per `schema` version. Parse-time
885
1037
  * `warnings` are excluded from the DTO.
886
1038
  *
887
1039
  * Output is **byte-deterministic** within a `schema` version: equal
@@ -895,7 +1047,7 @@ export class Document {
895
1047
  toMarkdown(): string;
896
1048
  /**
897
1049
  * Like [`fromJson`](Document::from_json) but returns `undefined` instead
898
- * of throwing when `json` is not a valid storage DTO use to
1050
+ * of throwing when `json` is not a valid storage DTO: use to
899
1051
  * discriminate format without exceptions as control flow.
900
1052
  * `undefined` means "not a storage DTO"; `fromMarkdown` still throws on
901
1053
  * genuinely malformed markdown.
@@ -908,10 +1060,16 @@ export class Document {
908
1060
  readonly cards: Card[];
909
1061
  /**
910
1062
  * The document's main (entry) card. Allocates and serializes on each
911
- * call cache locally if read in a hot loop.
1063
+ * call: cache locally if read in a hot loop.
912
1064
  */
913
1065
  readonly main: Card;
914
1066
  readonly quillRef: string;
1067
+ /**
1068
+ * The non-fatal diagnostics of the load that produced this document: parse
1069
+ * warnings, plus the `conform::*` warnings when it came through
1070
+ * `quill.parse`. Session state, not document value: `equals` and the
1071
+ * storage DTO exclude it, and `fromJson` / `loadJson` clear it.
1072
+ */
915
1073
  readonly warnings: Diagnostic[];
916
1074
  }
917
1075
 
@@ -920,7 +1078,7 @@ export class Document {
920
1078
  * `fieldAt`, `positionAt`, `locate`) serve the current compile. `apply(doc)`
921
1079
  * recompiles a whole document in place, transactionally (on throw every read
922
1080
  * keeps serving the last-good compile). Geometry reads reflect the current
923
- * compile; anchoring a caret across edits is the editor's job re-read
1081
+ * compile; anchoring a caret across edits is the editor's job: re-read
924
1082
  * geometry after each committed `apply`.
925
1083
  *
926
1084
  * **Empty documents.** A zero-page document yields a valid session
@@ -933,7 +1091,7 @@ export class LiveSession {
933
1091
  free(): void;
934
1092
  [Symbol.dispose](): void;
935
1093
  /**
936
- * Recompile the session against `doc` the edit verb of a live preview.
1094
+ * Recompile the session against `doc`: the edit verb of a live preview.
937
1095
  * The document is compiled through the same schema pipeline as `open`
938
1096
  * (same quill), then applied transactionally: on throw every read
939
1097
  * (`render`, `paint`, `pageSize`, `regions`, `fieldAt`) keeps serving the last-good
@@ -942,11 +1100,11 @@ export class LiveSession {
942
1100
  */
943
1101
  apply(doc: Document): ChangeSet;
944
1102
  /**
945
- * The schema field whose content is under a point on `page` the
1103
+ * The schema field whose content is under a point on `page`, the
946
1104
  * forward (click → field) direction: hit-test a click against the
947
1105
  * compiled document and get back the `DocPath` field address to focus in
948
1106
  * the editor, or `undefined` off any field's ink. `x`/`y` are PDF points
949
- * with a **bottom-left** origin, the same space as `FieldRegion.rect` —
1107
+ * with a **bottom-left** origin, the same space as `FieldRegion.rect`,
950
1108
  * from a canvas click, invert the overlay transform documented on
951
1109
  * `FieldRegion`: `x = clickPx.x / renderScale`,
952
1110
  * `y = pageHeightPt - clickPx.y / renderScale`. Unlike `regions()`,
@@ -954,19 +1112,19 @@ export class LiveSession {
954
1112
  */
955
1113
  fieldAt(page: number, x: number, y: number): string | undefined;
956
1114
  /**
957
- * The whole-field highlight boxes for `field` one union rect per page,
1115
+ * The whole-field highlight boxes for `field`: one union rect per page,
958
1116
  * over the field's `span`-bearing content segments. The convenience that
959
1117
  * owns the union `regions()` leaves derived: it keeps `regions()` the
960
- * low-level disjoint truth (#829) and folds the span-filter + per-page
1118
+ * low-level disjoint truth and folds the span-filter + per-page
961
1119
  * union here, so a "highlight the focused field" consumer stops
962
- * reimplementing it. **Content only** a field placed solely as a scalar
1120
+ * reimplementing it. **Content only**: a field placed solely as a scalar
963
1121
  * reference or a bound widget carries no `span` and returns `[]`; its box
964
1122
  * is a single `regions()` rect. Reflects the current compile, like
965
1123
  * `regions()`.
966
1124
  */
967
1125
  fieldBoxes(field: string): FieldRegion[];
968
1126
  /**
969
- * A content position → **caret rect** the reverse of `positionAt`: given
1127
+ * A content position → **caret rect**, the reverse of `positionAt`: given
970
1128
  * a field and a USV offset into its `Content`, return the box (in the
971
1129
  * same bottom-left PDF-point space as `FieldRegion.rect`) to draw a caret
972
1130
  * at, its `span` collapsed to `[pos, pos]`; `undefined` when the field
@@ -983,12 +1141,12 @@ export class LiveSession {
983
1141
  * `OffscreenCanvasRenderingContext2D`. The painter owns
984
1142
  * `canvas.width`/`height` (no `clearRect` needed); consumers own
985
1143
  * `canvas.style.*`. If `layoutScale * densityScale` exceeds 16384 px
986
- * per side, `densityScale` is clamped `PaintResult.clamped` reports it and
1144
+ * per side, `densityScale` is clamped: `PaintResult.clamped` reports it and
987
1145
  * `PaintResult.effectiveDensityScale` carries the density actually applied.
988
1146
  *
989
1147
  * `put_image_data` writes the whole backing store, bypassing the 2D
990
1148
  * context's transform, `globalAlpha`, and clip: the painter owns the entire
991
- * canvas, so each visible page needs its own `` you cannot composite
1149
+ * canvas, so each visible page needs its own `<canvas>`; you cannot composite
992
1150
  * two pages, a sub-rect, or a context transform through this call.
993
1151
  *
994
1152
  * Throws if the backend has no canvas painter, `page` is out of range,
@@ -996,18 +1154,18 @@ export class LiveSession {
996
1154
  */
997
1155
  paint(ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, page: number, opts: PaintOptions | undefined): PaintResult;
998
1156
  /**
999
- * A point → **content position** the fine-grained click direction:
1157
+ * A point → **content position**, the fine-grained click direction:
1000
1158
  * hit-test a point and get back the field *and* a USV offset into its
1001
1159
  * `Content` (for placing a caret or mapping a selection into the content
1002
1160
  * model), or `undefined` off all content ink. `x`/`y` are PDF points,
1003
- * bottom-left origin the same space as `fieldAt`. The offset is
1161
+ * bottom-left origin: the same space as `fieldAt`. The offset is
1004
1162
  * cluster-exact and degrades to the containing segment's start on
1005
1163
  * origin-less ink (list markers, a code fence's interior). See
1006
1164
  * `ContentHit`.
1007
1165
  */
1008
1166
  positionAt(page: number, x: number, y: number): ContentHit | undefined;
1009
1167
  /**
1010
- * Schema-field geometry for this compiled session each content field's
1168
+ * Schema-field geometry for this compiled session: each content field's
1011
1169
  * **first placement** (one region per page it touches) plus widget and
1012
1170
  * scalar-reference-site regions, keyed on the canonical `DocPath` address
1013
1171
  * (`parseDocPath`-routable; the session resolves the backend's plate-space
@@ -1027,12 +1185,12 @@ export class LiveSession {
1027
1185
  /**
1028
1186
  * `true` iff `paint` and `pageSize` will succeed for this session. Derived
1029
1187
  * from the session's canvas seam, so it reflects exactly what `paint` will
1030
- * do no separately captured flag.
1188
+ * do: no separately captured flag.
1031
1189
  */
1032
1190
  readonly supportsCanvas: boolean;
1033
1191
  /**
1034
1192
  * Non-fatal diagnostics of the session's **current compile** (e.g. Typst
1035
- * font fallback) set at open and refreshed by each committed `apply`;
1193
+ * font fallback): set at open and refreshed by each committed `apply`;
1036
1194
  * a failed apply keeps the last-good compile's warnings. Also appended
1037
1195
  * to `RenderResult.warnings` on each `render()` call.
1038
1196
  */
@@ -1044,7 +1202,24 @@ export class Quill {
1044
1202
  free(): void;
1045
1203
  [Symbol.dispose](): void;
1046
1204
  /**
1047
- * Build a quill from a file tree. Pure no backend, no engine; the
1205
+ * Land `doc`'s declared content fields at their canonical rest **in
1206
+ * place**, returning the `conform::*` diagnostics for the values that would
1207
+ * not commit (an empty array when everything rested).
1208
+ *
1209
+ * The read-repair verb: a document that arrived through the transport door
1210
+ * (`fromMarkdown`, `fromJson`, a stored row) converges here, and is then
1211
+ * eligible for rewrite under its current schema tag. Idempotent, and a
1212
+ * no-op on an already-canonical document: an equal value is not rewritten,
1213
+ * so YAML comments and stored bytes survive.
1214
+ *
1215
+ * A `!must_fill` marker anywhere in a field's value skips that field (the
1216
+ * marker is the state), and a value the strict write refuses stays as
1217
+ * authored with a diagnostic. Throws when `doc` declares a different
1218
+ * `$quill`, before any mutation.
1219
+ */
1220
+ conform(doc: Document): Diagnostic[];
1221
+ /**
1222
+ * Build a quill from a file tree. Pure: no backend, no engine; the
1048
1223
  * declared backend is resolved later, at render time.
1049
1224
  *
1050
1225
  * Accepts either a `Map<string, Uint8Array>` or a plain object
@@ -1054,11 +1229,26 @@ export class Quill {
1054
1229
  */
1055
1230
  static fromTree(tree: Map<string, Uint8Array>): Quill;
1056
1231
  /**
1057
- * The resolved-value view of `doc` against this quill's schema — for every
1232
+ * Parse `markdown` and conform it against this quill: the **primary
1233
+ * ingestion path**, and the bound twin of the schema-free
1234
+ * `Document.fromMarkdown`. The returned document rests at its canonical
1235
+ * form (a `richtext` field as a content object, a `plaintext` field as its
1236
+ * literal string), so `getStored` no longer answers "corpus or string?"
1237
+ * with "depends how this document was built".
1238
+ *
1239
+ * Parse warnings and the `conform::*` diagnostics both land on
1240
+ * `doc.warnings`. Throws on a parse failure, or when `markdown` declares a
1241
+ * `$quill` this quill does not answer to: nothing conforms under the wrong
1242
+ * schema. To open a document whose `$quill` is stale, use the transport
1243
+ * door (`Document.fromMarkdown`, `setQuillRef`, then `quill.conform`).
1244
+ */
1245
+ parse(markdown: string): Document;
1246
+ /**
1247
+ * The resolved-value view of `doc` against this quill's schema: for every
1058
1248
  * declared field the value the render projection would use and the
1059
1249
  * `FieldSource` rung it came from (`"authored" | "default" | "zero"`), in
1060
1250
  * one call. The card body is a `body` sibling on its card (row `name`
1061
- * `"body"`), never a row in `fields` `null` when the kind enables no body.
1251
+ * `"body"`), never a row in `fields`: `null` when the kind enables no body.
1062
1252
  *
1063
1253
  * Value and provenance only: completeness and errors stay `validate`'s
1064
1254
  * (a consumer merges it with its own diagnostic producers regardless), and
@@ -1075,11 +1265,11 @@ export class Quill {
1075
1265
  * Pass `document.seedOverlay(cardKind)` as `overlay` so a card added to a
1076
1266
  * template-derived document inherits its curated starting values; omit it
1077
1267
  * (or pass `undefined` / `null`) for the bare schema seed. `overlay` is a
1078
- * plain object this reads the document, it does not mutate it.
1268
+ * plain object: this reads the document, it does not mutate it.
1079
1269
  */
1080
1270
  seedCard(card_kind: string, overlay: Record<string, unknown> | undefined): Card | undefined;
1081
1271
  /**
1082
- * Seed a starter `Document` from the schema the main card plus one
1272
+ * Seed a starter `Document` from the schema, the main card plus one
1083
1273
  * instance of each composable card kind, each committing its fields'
1084
1274
  * `example:` values and leaving every other field absent (interpolated at
1085
1275
  * render: `default:`, else type-empty zero). Illustration-first: a field
@@ -1088,14 +1278,14 @@ export class Quill {
1088
1278
  */
1089
1279
  seedDocument(): Document;
1090
1280
  /**
1091
- * Seed a starter main `Card` (carries `$quill`) from the schema the
1281
+ * Seed a starter main `Card` (carries `$quill`) from the schema: the
1092
1282
  * `$kind: main` card of [`seedDocument`](Self::seed_document) in
1093
1283
  * isolation, committing each field's `example:` value. Returns the same
1094
1284
  * `Card` shape as the `Document.main` getter.
1095
1285
  */
1096
1286
  seedMain(): Card;
1097
1287
  /**
1098
- * Flatten this quill back into its canonical file tree the inverse of
1288
+ * Flatten this quill back into its canonical file tree: the inverse of
1099
1289
  * [`fromTree`](Self::from_tree). Round-trips: `Quill.fromTree(q.toTree())`
1100
1290
  * reproduces an equivalent quill.
1101
1291
  *
@@ -1111,8 +1301,8 @@ export class Quill {
1111
1301
  * Validate `doc` against this quill's schema, returning every diagnostic
1112
1302
  * (an empty array when the document is valid).
1113
1303
  *
1114
- * Forwards the canonical `validation::*` diagnostics same `code`,
1115
- * `path`, and `hint` the engine emits including the non-fatal
1304
+ * Forwards the canonical `validation::*` diagnostics (same `code`,
1305
+ * `path`, and `hint` the engine emits) including the non-fatal
1116
1306
  * `validation::must_fill` warning for each `!must_fill` marker left in
1117
1307
  * the document. Field values, defaults, and order are not part of this
1118
1308
  * surface: read them from the `Document` payload and `Quill.schema`
@@ -1121,14 +1311,14 @@ export class Quill {
1121
1311
  validate(doc: Document): Diagnostic[];
1122
1312
  /**
1123
1313
  * The *declared* backend identifier (`config.backend`, e.g. `"typst"`).
1124
- * Intent, not a resolved capability capability (`supportedFormats` /
1314
+ * Intent, not a resolved capability: capability (`supportedFormats` /
1125
1315
  * `supportsCanvas`) is read from the engine.
1126
1316
  */
1127
1317
  readonly backendId: string;
1128
1318
  readonly blueprint: string;
1129
1319
  /**
1130
1320
  * Identity snapshot of the `quill:` section of `Quill.yaml` plus any extra
1131
- * `quill:` keys. Pure config the backend's output formats are a
1321
+ * `quill:` keys. Pure config: the backend's output formats are a
1132
1322
  * resolved-backend capability read from the engine
1133
1323
  * (`Quillmark.supportedFormats`), not part of this snapshot.
1134
1324
  */
@@ -1136,15 +1326,15 @@ export class Quill {
1136
1326
  /**
1137
1327
  * Document schema for the quill: the user-fillable fields plus their
1138
1328
  * `ui` hints (title / group / compact / multiline). The single
1139
- * field-metadata surface drives form editors and LLM/MCP consumers
1140
- * alike. Key order in `fields`/`properties` is declaration order the
1329
+ * field-metadata surface: drives form editors and LLM/MCP consumers
1330
+ * alike. Key order in `fields`/`properties` is declaration order: the
1141
1331
  * ordering contract. Returns the `QuillSchema` shape.
1142
1332
  */
1143
1333
  readonly schema: QuillSchema;
1144
1334
  }
1145
1335
 
1146
1336
  /**
1147
- * Render engine: a backend registry and render dispatcher. Render build only
1337
+ * Render engine: a backend registry and render dispatcher. Render build only:
1148
1338
  * the core build constructs and validates quills without it.
1149
1339
  */
1150
1340
  export class Quillmark {
@@ -1162,7 +1352,7 @@ export class Quillmark {
1162
1352
  */
1163
1353
  render(quill: Quill, doc: Document, opts?: RenderOptions | null): RenderResult;
1164
1354
  /**
1165
- * The output formats `quill`'s backend can emit. Static capability
1355
+ * The output formats `quill`'s backend can emit. Static capability:
1166
1356
  * resolves the backend but compiles nothing. Throws `engine::backend_not_found`
1167
1357
  * if no registered backend matches the quill's declared backend.
1168
1358
  */
@@ -1178,7 +1368,7 @@ export class Quillmark {
1178
1368
  }
1179
1369
 
1180
1370
  /**
1181
- * Export a canonical `Content` content to its markdown projection the pure
1371
+ * Export a canonical `Content` content to its markdown projection: the pure
1182
1372
  * on-demand codec behind `exportMarkdown(card.body)`. Throws if `rt` is not a
1183
1373
  * canonical content.
1184
1374
  */
@@ -1186,7 +1376,7 @@ export function exportMarkdown(rt: Content): string;
1186
1376
 
1187
1377
  /**
1188
1378
  * Serialize structured [`DocPathSeg`] segments back to the canonical path
1189
- * string the inverse of `parseDocPath`, for a consumer that builds a path
1379
+ * string: the inverse of `parseDocPath`, for a consumer that builds a path
1190
1380
  * rather than reads one. Throws on a segment array the deserializer rejects,
1191
1381
  * and on an empty segment array (symmetric with `parseDocPath("")`, which
1192
1382
  * throws "empty path").
@@ -1194,7 +1384,7 @@ export function exportMarkdown(rt: Content): string;
1194
1384
  export function formatDocPath(segs: DocPathSeg[]): string;
1195
1385
 
1196
1386
  /**
1197
- * Import a markdown string to a canonical `Content` content the pure,
1387
+ * Import a markdown string to a canonical `Content` content: the pure,
1198
1388
  * document-free codec. Pair with `install(addr, importMarkdown(md))` to spell
1199
1389
  * the cold (anchor-losing) write at the call site; prefer `revise` for edit
1200
1390
  * semantics. Throws on an over-nested input.
@@ -1207,8 +1397,8 @@ export function importMarkdown(markdown: string): Content;
1207
1397
  export function init(): void;
1208
1398
 
1209
1399
  /**
1210
- * Map a base content position a USV index into `Content.text`, not a UTF-16
1211
- * offset through a `delta` to its new USV position: the pure position-mapping
1400
+ * Map a base content position (a USV index into `Content.text`, not a UTF-16
1401
+ * offset) through a `delta` to its new USV position: the pure position-mapping
1212
1402
  * codec an editor bridge composes to hold a caret stable across a `revise`.
1213
1403
  * `assoc` decides the side of a same-position insertion (`"after"` moves past
1214
1404
  * it). Throws on a malformed `delta`.
@@ -1218,14 +1408,14 @@ export function mapPos(delta: Delta, pos: number, assoc: Assoc): number;
1218
1408
  /**
1219
1409
  * Parse a canonical document-model `Diagnostic.path`
1220
1410
  * (`cards.<kind>[<i>].<field>`, `main.body`, `recipients[0].name`) into its
1221
- * structured [`DocPathSeg`] segments the exported inverse of the engine's
1411
+ * structured [`DocPathSeg`] segments: the exported inverse of the engine's
1222
1412
  * one path serializer, so a consumer routes on segments instead of regexing
1223
1413
  * the string. Throws on a malformed path.
1224
1414
  */
1225
1415
  export function parseDocPath(path: string): DocPathSeg[];
1226
1416
 
1227
1417
  /**
1228
- * Rebase `markdown` onto a `base` content the pure, document-free twin of
1418
+ * Rebase `markdown` onto a `base` content, the pure, document-free twin of
1229
1419
  * `revise`: cold-import + `diff_import`, returning the new `content` and the
1230
1420
  * text `delta` (its offsets USV indices into `Content.text`, surviving anchors
1231
1421
  * rebased). Use it to compute a revise without a document in hand; `revise(addr,