@quillmark/wasm 0.111.0 → 0.113.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.
@@ -17,7 +17,7 @@ export type PayloadItem =
17
17
  /**
18
18
  * Paths to `!must_fill` markers nested *inside* `value` (the `value`
19
19
  * projection itself is fill-free). Absent when the field has no nested
20
- * placeholders. Preserved across `insertCard` / `makeCard`.
20
+ * placeholders. Preserved across `insertCard`.
21
21
  */
22
22
  nestedFills?: PathStep[][];
23
23
  }
@@ -72,10 +72,10 @@ export interface Content {
72
72
  islands: ContentIsland[];
73
73
  }
74
74
 
75
- /** One `\n`-separated segment of `Content.text`, in order. `kind` is an open set:
76
- * an unknown role round-trips with opaque `attrs` and renders as a paragraph.
77
- * The open arm blocks discriminant narrowing, so read `level`/`lang` behind a
78
- * check of the arm you want. */
75
+ /** One `\n`-separated segment of `Content.text`, in order. `kind` is a closed
76
+ * set: a role outside it is refused wherever content is decoded. Every role
77
+ * spells its payload in `attrs`, so `kind === "heading"` narrows `attrs` to
78
+ * `{ level: number }` with no guard. */
79
79
  export type ContentLine = {
80
80
  containers: ContentContainer[];
81
81
  /** A within-block hard line break rather than a new block. Omitted (false) in the common case. */
@@ -85,56 +85,53 @@ export type ContentLine = {
85
85
  /** A line's block role, shared by `ContentLine` and the `setKind` op. */
86
86
  export type ContentLineKind =
87
87
  | { kind: "para" }
88
- | { kind: "heading"; level: number }
89
- | { kind: "code"; lang?: string }
88
+ | { kind: "heading"; attrs: { level: number } }
89
+ | { kind: "code"; attrs?: { lang?: string } }
90
90
  | { kind: "island" }
91
- | { kind: "rule" }
92
- | { kind: string; attrs: unknown };
91
+ | { kind: "rule" };
93
92
 
94
- /** An ancestor block a line nests inside, outermost first. Open like
95
- * `ContentLine.kind`: an unrecognized container round-trips with opaque `attrs`
96
- * and renders transparently (its lines sit at the enclosing level).
93
+ /** An ancestor block a line nests inside, outermost first. Closed like
94
+ * `ContentLine.kind`.
97
95
  *
98
96
  * Two adjacent lines sit in the same container iff their whole path matches, so
99
97
  * `instance` is what tells one container from an adjacent sibling of identical
100
98
  * shape — two consecutive quotes, two consecutive lists — which contiguity
101
99
  * alone reads as one.
102
100
  *
103
- * **A writer owes a distinct value per adjacent sibling run**, not merely a
104
- * value. Runs of one shape sharing one arrive as one: a second list's items come
105
- * back as continuation paragraphs of the first, markers gone. The field is
106
- * required, so a checker reports the omission; it cannot report a `0` stamped on
107
- * both, which is the same write. A codec flattening a tree takes them from
108
- * `assignInstances` in `@quillmark/wasm/runtime` rather than by hand. Any
109
- * distinct pair works; a write is canonicalized to `0`/`1`.
101
+ * **A writer owes a distinct value per adjacent sibling run.** Runs of one shape
102
+ * sharing one arrive as one: a second list's items come back as continuation
103
+ * paragraphs of the first, markers gone. Nothing reports that — an omitted field
104
+ * and a `0` stamped on both are the same write so a codec flattening a tree
105
+ * takes them from `assignInstances` in `@quillmark/wasm` rather than by hand.
106
+ * Any distinct pair works; a write is canonicalized to `0`/`1`.
110
107
  *
111
- * Reading is not the mirror of writing. Every read spells the field, the `0` on
112
- * a container with nothing to be told apart from included. A read also carries a
113
- * discriminator on pairs no writer had to spell: `1.` beside a list starting at
114
- * `3` differs by `start`, so those runs arrive apart with nothing written, and
115
- * the canonical form spends one anyway because Markdown reads only a list's
116
- * first number.
117
- *
118
- * Content parsed from a stored document is the one shape that arrives without
119
- * it — storage omits a zero — and needs a cast. */
108
+ * Absent is `0`, and a read omits it there, so a container with nothing adjacent
109
+ * to be told apart from carries no key. A read does spell one on pairs no writer
110
+ * had to: `1.` beside a list starting at `3` differs by `start`, so those runs
111
+ * arrive apart with nothing written, and the canonical form spends a
112
+ * discriminator anyway because Markdown reads only a list's first number. */
120
113
  export type ContentContainer =
121
- | { container: "list_item"; ordered: boolean; start: number; ordinal: number; instance: number }
122
- | { container: "quote"; instance: number }
123
- | { container: string; attrs: unknown; instance: number };
124
-
125
- /** A mark over char range `[start, end)` into `Content.text`. The open `type`
126
- * arm blocks discriminant narrowing, so read a payload-carrying arm behind its
127
- * guard: `isLinkMark` (`url`) / `isAnchorMark` (`id`), from
128
- * `@quillmark/wasm/runtime`. An `anchor`'s `id` is a caller-supplied opaque
114
+ | {
115
+ container: "list_item";
116
+ attrs: { ordered: boolean; start: number; ordinal: number };
117
+ instance?: number;
118
+ }
119
+ | { container: "quote"; instance?: number };
120
+
121
+ /** A mark over char range `[start, end)` into `Content.text`. `type` is a
122
+ * closed set, so `type === "link"` narrows `attrs` to `{ url: string }` with no
123
+ * guard. An `anchor`'s `id` is a caller-supplied opaque
129
124
  * handle, unique per `Content` and invariant while the mark lives (positions
130
125
  * rebase, the id never does); it has no markdown projection and survives only
131
126
  * through the edit lane. */
132
- export type ContentMark = { start: number; end: number } & (
127
+ export type ContentMark = { start: number; end: number } & ContentMarkKind;
128
+
129
+ /** A mark's type with its payload, shared by `ContentMark` and a `MarkOp`'s
130
+ * `add` / `remove`. */
131
+ export type ContentMarkKind =
133
132
  | { type: "strong" | "emph" | "underline" | "strike" | "code" }
134
- | { type: "link"; url: string }
135
- | { type: "anchor"; id: string }
136
- | { type: string; attrs: unknown }
137
- );
133
+ | { type: "link"; attrs: { url: string } }
134
+ | { type: "anchor"; attrs: { id: string } };
138
135
 
139
136
  /** A cell in a `TableProps`. `marks` rides the prose `ContentMark` shape, but
140
137
  * each mark's `start`/`end` are USV offsets into this cell's `text`, not into
@@ -153,28 +150,25 @@ export interface TableProps {
153
150
  aligns: ("none" | "left" | "center" | "right")[];
154
151
  }
155
152
 
156
- /** `props` of a `type: "image"` island. */
153
+ /** `props` of a `type: "image"` island. Stores and round-trips; no backend
154
+ * typesets one, and a render that holds one warns `backend::declined_construct`,
155
+ * because what `url` names is undecided. */
157
156
  export interface ImageProps {
158
157
  url: string;
159
158
  alt: string;
160
159
  }
161
160
 
162
- /** How faithfully the markdown projection can carry an island. Open: an unknown
163
- * class round-trips verbatim and reads as `unrepresentable`. */
164
- export type ContentLossClass = "lossless" | "degraded" | "unrepresentable" | (string & {});
161
+ /** How faithfully the markdown projection can carry an island. */
162
+ export type ContentLossClass = "lossless" | "degraded" | "unrepresentable";
165
163
 
166
- /** A structured object occupying one island slot in `Content.text`. `type` is an
167
- * open set: `props` is `TableProps` for `table` and `ImageProps` for `image`,
168
- * and any other type round-trips with opaque `props`. The open arm blocks
169
- * narrowing, so read `props` behind the `isTableIsland` / `isImageIsland`
170
- * guards (from `@quillmark/wasm/runtime`). */
164
+ /** A structured object occupying one island slot in `Content.text`. `type` is a
165
+ * closed set, so `type === "table"` narrows `props` to `TableProps`. */
171
166
  export type ContentIsland = {
172
167
  id: string;
173
168
  loss: ContentLossClass;
174
169
  } & (
175
170
  | { type: "table"; props: TableProps }
176
171
  | { type: "image"; props: ImageProps }
177
- | { type: string; props: unknown }
178
172
  );
179
173
 
180
174
  /**
@@ -214,6 +208,10 @@ export interface CardAddr {
214
208
  * A text-splice change set over the USV content (CodeMirror `ChangeSet`
215
209
  * semantics), returned by `revise` and by the `rebase` codec. Map a stored
216
210
  * position through it with `mapPos`.
211
+ *
212
+ * Applying one admits an `insert` string rather than storing it verbatim: `\r`
213
+ * and the Unicode bidi controls drop, and a line separator — VT, FF, NEL,
214
+ * U+2028, U+2029 — becomes a space. Nothing reports the substitution.
217
215
  */
218
216
  export interface Delta {
219
217
  ops: ({ retain: number } | { insert: string } | { delete: number })[];
@@ -224,24 +222,25 @@ export type Assoc = "before" | "after";
224
222
 
225
223
  /**
226
224
  * A mark edit in final-text coordinates (post-delta, post-line-op). `add` /
227
- * `remove` carry the `ContentMark` vocabulary; `removeAnchor` drops one identity
228
- * anchor by id. An `add` of an `anchor` requires a non-empty `id` not already
229
- * live in the field; a collision or the empty id throws.
225
+ * `remove` are a `ContentMark` under an op, so a held mark spreads in whole;
226
+ * `removeAnchor` drops one identity anchor by id. An `add` of an `anchor`
227
+ * requires a non-empty `id` not already live in the field; a collision or the
228
+ * empty id throws.
230
229
  */
231
230
  export type MarkOp =
232
- | ({ op: "add" | "remove"; start: number; end: number } & (
233
- | { type: "strong" | "emph" | "underline" | "strike" | "code" }
234
- | { type: "link"; url: string }
235
- | { type: "anchor"; id: string }
236
- | { type: string; attrs: unknown }
237
- ))
231
+ | ({ op: "add" | "remove" } & ContentMark)
238
232
  | { op: "removeAnchor"; id: string };
239
233
 
240
234
  /**
241
235
  * A line/block edit. `split`/`join` splice `\n` in post-`delta`,
242
236
  * post-`islandOps` coordinates; `setKind`/`setContainers`/`setContinues` touch
243
237
  * metadata. `setContinues` sets or clears a line's within-block hard-break flag
244
- * (`ContentLine.continues`); `continues: true` on line 0 is rejected.
238
+ * (`ContentLine.continues`); `continues: true` lands as `false` on line 0, which
239
+ * nothing precedes, on a line whose containers differ from the line above, and
240
+ * on one following a heading, island or rule, each a block of one line.
241
+ * `setKind` lands a kind the line's text contradicts — `island` or `rule` over
242
+ * prose, `code` over a slot — as `para`, which is what re-importing the line's
243
+ * own markdown yields. Read the content back to see where an op settled.
245
244
  */
246
245
  export type LineOp =
247
246
  | { op: "split"; at: number }
@@ -272,11 +271,19 @@ export type LineOp =
272
271
  * A `set` stores the `loss` it is given; nothing re-derives the class from the
273
272
  * new `props`.
274
273
  *
275
- * An island is *inline* (a slot inside a paragraph) unless its line says
276
- * otherwise. A **block** island is one bundle of all three channels, in the
277
- * order they apply: `delta` inserts the `\n` that opens the line, `islandOps`
278
- * inserts the slot, `lineOps` tags the line `{ op: "setKind", kind: "island" }`.
279
- * `{ op: "split" }` cannot open that line, since line ops run after island ops.
274
+ * An island is *inline* (a slot inside a paragraph) or a **block** (that slot
275
+ * alone on a line under `kind: "island"`), and for a slot alone on a line the
276
+ * type settles which: markdown writes a `table` as a block and an image inline,
277
+ * so the line's `kind` is read off the type and a `setKind` spelling it
278
+ * otherwise does not survive. Landing a block island is one bundle of all three
279
+ * channels, in the order they apply: `delta` inserts the `\n` that opens the
280
+ * line, `islandOps` inserts the slot, `lineOps` tags the line
281
+ * `{ op: "setKind", kind: "island" }`. `{ op: "split" }` cannot open that line,
282
+ * since line ops run after island ops.
283
+ *
284
+ * A `table` has no inline placement: markdown writes it as a block, so an
285
+ * `insert` whose `at` is not an empty line throws, as does a `set` retyping an
286
+ * inline island into one.
280
287
  */
281
288
  export type IslandOp =
282
289
  | ({ op: "set" } & ContentIsland)
@@ -560,7 +567,7 @@ export interface ContentHit {
560
567
  */
561
568
  field: string;
562
569
  /**
563
- * USV offset into the field\'s `Content`.
570
+ * USV offset into the field's `Content`.
564
571
  */
565
572
  pos: number;
566
573
  /**
@@ -570,19 +577,13 @@ export interface ContentHit {
570
577
  }
571
578
 
572
579
  /**
573
- * A schema field address plus its geometry on the page, for scrolling to or
574
- * highlighting a field; use `LiveSession.fieldAt` for the click direction.
575
- *
576
- * `field` is **not** unique: content fields surface one region per segment
577
- * (paragraph, heading, whole code fence) and per page each touches, a scalar
578
- * referenced at several plate sites surfaces each site, and tracked content
579
- * plus a `field:`-bound widget yields both. Group by `field`. The whole-field
580
- * highlight is the union of a page\'s `span`-bearing rects, so inter-paragraph
581
- * whitespace stays uncovered; `LiveSession.fieldBoxes(field)` owns that union.
580
+ * A schema field address plus its geometry on the page. `field` is **not**
581
+ * unique, and the whole-field highlight is a union `LiveSession.fieldBoxes`
582
+ * owns: the consumer's copy of this contract is `runtime/runtime.d.ts`.
582
583
  */
583
584
  export interface FieldRegion {
584
585
  /**
585
- * Canonical `DocPath` field address (e.g. `\"cards.indorsement[1].from\"`):
586
+ * Canonical `DocPath` field address (e.g. `"cards.indorsement[1].from"`):
586
587
  * the grammar `parseDocPath` reads and `Diagnostic.path` carries. Feed it
587
588
  * back to `fieldBoxes` / `locate`.
588
589
  */
@@ -596,22 +597,50 @@ export interface FieldRegion {
596
597
  */
597
598
  rect: [number, number, number, number];
598
599
  /**
599
- * The slice this box covers: USV `[start, end)` into the field\'s `Content`
600
+ * The slice this box covers: USV `[start, end)` into the field's `Content`
600
601
  * for one content segment, `undefined` for a scalar site or widget.
601
602
  */
602
603
  span?: [number, number];
603
604
  }
604
605
 
605
606
  /**
606
- * Diagnostic message (error or warning)
607
+ * How precisely a `ContentHit.pos` resolved. Never sub-cluster: `cluster` is
608
+ * the finest this API offers, `segment` the floor it degrades to.
609
+ */
610
+ export type HitGranularity = "cluster" | "segment";
611
+
612
+ /**
613
+ * Output formats supported by backends. Gated behind the engine surface so
614
+ * tsify omits it from the core bundle, which has no rendering surface.
615
+ */
616
+ export type OutputFormat = "pdf" | "svg" | "png";
617
+
618
+ /**
619
+ * What a committed `LiveSession.update` changed. `dirtyPages` lists pages whose
620
+ * content differs from the previous compile, including pages the edit added;
621
+ * removed pages are implied by `pageCount`.
607
622
  */
623
+ export interface ChangeSet {
624
+ pageCount: number;
625
+ dirtyPages: number[];
626
+ }
627
+
628
+ export interface Artifact {
629
+ format: OutputFormat;
630
+ /**
631
+ * `serde_bytes` so the boundary emits a real `Uint8Array`, not `number[]`.
632
+ */
633
+ bytes: Uint8Array;
634
+ mimeType: string;
635
+ }
636
+
608
637
  export interface Diagnostic {
609
638
  severity: Severity;
610
639
  code?: string;
611
640
  message: string;
612
641
  location?: Location;
613
642
  /**
614
- * Document-model path anchor (e.g. `\"cards.indorsement[0].signature_block\"`),
643
+ * Document-model path anchor (e.g. `"cards.indorsement[0].signature_block"`),
615
644
  * set on schema validation diagnostics and `undefined` otherwise.
616
645
  */
617
646
  path?: string;
@@ -624,18 +653,14 @@ export interface Diagnostic {
624
653
  * `skip_serializing_if`, so an omitted field would be declared required.
625
654
  */
626
655
  args?: Record<string, unknown>;
627
- sourceChain?: string[];
628
656
  }
629
657
 
630
- /**
631
- * How precisely a `ContentHit.pos` resolved. Never sub-cluster: `cluster` is
632
- * the finest this API offers, `segment` the floor it degrades to.
633
- */
634
- export type HitGranularity = "cluster" | "segment";
658
+ export interface Location {
659
+ file: string;
660
+ line: number;
661
+ column: number;
662
+ }
635
663
 
636
- /**
637
- * Options for rendering.
638
- */
639
664
  export interface RenderOptions {
640
665
  format?: OutputFormat;
641
666
  /**
@@ -644,14 +669,10 @@ export interface RenderOptions {
644
669
  ppi?: number;
645
670
  /**
646
671
  * 0-based page indices to render; `undefined` renders all pages. An index
647
- * `>= pageCount` throws `typst::page_index_out_of_bounds`. Not supported
648
- * for PDF output: throws `typst::pdf_page_selection_not_supported`.
672
+ * `>= pageCount` throws `backend::page_index_out_of_bounds`. Not supported
673
+ * for PDF output: throws `backend::page_selection_not_supported`.
649
674
  */
650
675
  pages?: number[];
651
- /**
652
- * PDF `/Info` `/Producer` override; defaults to `Quillmark <version>`.
653
- */
654
- producer?: string;
655
676
  /**
656
677
  * Populate `RenderResult.regions` with schema-field geometry, for consumers
657
678
  * without a live session. Defaults to `false`. Page indices are
@@ -660,32 +681,10 @@ export interface RenderOptions {
660
681
  regions?: boolean;
661
682
  }
662
683
 
663
- /**
664
- * Output formats supported by backends. Gated behind the engine surface so
665
- * tsify omits it from the core bundle, which has no rendering surface.
666
- */
667
- export type OutputFormat = "pdf" | "svg" | "png";
668
-
669
- /**
670
- * Rendered artifact (PDF, SVG, etc.).
671
- */
672
- export interface Artifact {
673
- format: OutputFormat;
674
- /**
675
- * `serde_bytes` so the boundary emits a real `Uint8Array`, not `number[]`.
676
- */
677
- bytes: Uint8Array;
678
- mimeType: string;
679
- }
680
-
681
- /**
682
- * Result of a render operation.
683
- */
684
684
  export interface RenderResult {
685
685
  artifacts: Artifact[];
686
686
  warnings: Diagnostic[];
687
687
  outputFormat: OutputFormat;
688
- renderTimeMs: number;
689
688
  /**
690
689
  * Schema-field geometry, populated only when `RenderOptions.regions` asked
691
690
  * for it. Page indices are document-space even under a `pages` subset.
@@ -693,31 +692,9 @@ export interface RenderResult {
693
692
  regions: FieldRegion[];
694
693
  }
695
694
 
696
- /**
697
- * Source location for errors and warnings
698
- */
699
- export interface Location {
700
- file: string;
701
- line: number;
702
- column: number;
703
- }
704
-
705
- /**
706
- * What a committed `LiveSession.update` changed. `dirtyPages` lists pages whose
707
- * content differs from the previous compile, including pages the edit added;
708
- * removed pages are implied by `pageCount`.
709
- */
710
- export interface ChangeSet {
711
- pageCount: number;
712
- dirtyPages: number[];
713
- }
714
-
715
695
  export type Severity = "error" | "warning";
716
696
 
717
697
 
718
- /**
719
- * Typed in-memory Quillmark document.
720
- */
721
698
  export class Document {
722
699
  free(): void;
723
700
  [Symbol.dispose](): void;
@@ -739,8 +716,8 @@ export class Document {
739
716
  */
740
717
  applyChange(addr: Addr | string, bundle: ChangeBundle): void;
741
718
  /**
742
- * Authoring-ergonomics header introducing a blueprint to an LLM/MCP consumer
743
- * for the given `quillName`, re-exposed from core.
719
+ * A blueprint's fill obligation for the given `quillName`, re-exposed from
720
+ * core. Carries no tool name: pair it with your own next-step directive.
744
721
  */
745
722
  static blueprintInstruction(quill_name: string): string;
746
723
  /**
@@ -753,12 +730,6 @@ export class Document {
753
730
  * which interprets by declared type. An out-of-range `addr.card` throws.
754
731
  */
755
732
  bodyMarkdown(addr?: CardAddr): string;
756
- /**
757
- * A single composable card by index, so reading one need not materialize
758
- * every card via [`cards`](Self::cards). An out-of-range `index` throws
759
- * `edit::index_out_of_range`.
760
- */
761
- card(index: number): Card;
762
733
  /**
763
734
  * The composable card's own path, `cards.<kind>[index]`: the root
764
735
  * [`pathFor`](Self::path_for) extends, for anchoring the card rather than
@@ -766,9 +737,15 @@ export class Document {
766
737
  * `cards[index]`.
767
738
  */
768
739
  cardPath(index: number): string;
740
+ /**
741
+ * A single composable card by index, so reading one need not materialize
742
+ * every card via [`cards`](Self::cards). An out-of-range `index` throws
743
+ * `edit::index_out_of_range`.
744
+ */
745
+ card(index: number): Card;
769
746
  clone(): Document;
770
747
  /**
771
- * Storage version this build writes via [`toJson`](Document::to_json). The
748
+ * Storage version this build writes via [`toStored`](Document::to_stored). The
772
749
  * tag advances only when the wire format changes, not on every release.
773
750
  */
774
751
  static currentStorageVersion(): string;
@@ -776,27 +753,22 @@ export class Document {
776
753
  * Structural equality, excluding parse-time `warnings`.
777
754
  */
778
755
  equals(other: Document): boolean;
779
- /**
780
- * Render a Diagnostic as the canonical pretty-printed text, so it looks
781
- * identical whichever consumer surfaces it.
782
- */
783
- static formatDiagnostic(diag: Diagnostic): string;
784
756
  /**
785
757
  * Authoring-format rules for the card-yaml markdown surface, re-exposed from
786
758
  * core. Constant across calls; read once and cache.
787
759
  */
788
760
  static formatRules(): string;
761
+ /**
762
+ * Parse markdown into a typed Document. Throws on parse errors.
763
+ */
764
+ static fromMarkdown(markdown: string): Document;
789
765
  /**
790
766
  * Reconstruct a `Document` from a versioned storage DTO string produced by
791
- * [`toJson`](Document::to_json). The result carries no parse-time warnings.
767
+ * [`toStored`](Document::to_stored). The result carries no parse-time warnings.
792
768
  * Throws if `json` is not a valid storage DTO (malformed JSON, unknown
793
769
  * `schema`, missing fields, or unparseable quill reference).
794
770
  */
795
- static fromJson(json: string): Document;
796
- /**
797
- * Parse markdown into a typed Document. Throws on parse errors.
798
- */
799
- static fromMarkdown(markdown: string): Document;
771
+ static fromStored(json: string): Document;
800
772
  /**
801
773
  * The whole `$ext` map at `addr` (a card address, absent `card` = main), or
802
774
  * `undefined` when the card carries none: the `$ext` read that avoids
@@ -804,12 +776,6 @@ export class Document {
804
776
  * out-of-range card.
805
777
  */
806
778
  getExt(addr?: CardAddr): Record<string, unknown> | undefined;
807
- /**
808
- * The value stored under `$ext[ns]` at `addr` (a card address, absent `card`
809
- * = main), or `undefined`. Throws on a present `field` or an out-of-range
810
- * card.
811
- */
812
- getExtNamespace(addr: CardAddr, ns: string): unknown;
813
779
  /**
814
780
  * Read the **verbatim stored value** at `addr`: a field's raw payload value,
815
781
  * or the body content when `addr.field` is absent. A bare string is `Addr`
@@ -826,9 +792,8 @@ export class Document {
826
792
  * conformed, and this read reports what is there. For the `Content` either
827
793
  * way use `reader.getContent`.
828
794
  *
829
- * The body arm is typed `Content` and answers in the seam form, spelling
830
- * every `ContentContainer.instance`. A field arm echoes the stored bytes,
831
- * which omit a zero: verbatim is the contract, and is why it is `unknown`.
795
+ * The body arm is typed `Content`; a field arm echoes the stored bytes
796
+ * unread, which is the contract and why it is `unknown`.
832
797
  */
833
798
  getStored(addr: Addr | string): unknown;
834
799
  /**
@@ -846,26 +811,12 @@ export class Document {
846
811
  isFill(addr: Addr | string): boolean;
847
812
  /**
848
813
  * Replace this document's contents **in place** from a versioned storage DTO
849
- * string: the mutating twin of [`fromJson`](Document::from_json). Parse-time
850
- * `warnings` are cleared. Throws on an invalid DTO, leaving the document
851
- * unchanged.
852
- *
853
- * The cross-WASM-memory `Document` bridge: mutate a document on a
854
- * backend-memory clone, then write the state back into the caller's
855
- * canonical document, without the caller re-binding its variable.
814
+ * string: the mutating twin of [`fromStored`](Document::from_stored).
815
+ * Parse-time `warnings` are cleared. Throws on an invalid DTO, leaving the
816
+ * document unchanged. A caller holding the document need not re-bind its
817
+ * variable.
856
818
  */
857
- loadJson(json: string): void;
858
- /**
859
- * Build a fresh `Card` from a kind and a flat field map: the ergonomic
860
- * constructor for `insertCard`, which also takes any `Card` object
861
- * directly. Each `fields` entry becomes a card field in insertion order;
862
- * `body` defaults to `""`.
863
- *
864
- * Checks only what a detached card can decide alone: field-name grammar and
865
- * value depth. Kind validity is positional, so `insertCard` is its gate and
866
- * any kind string is accepted here.
867
- */
868
- static makeCard(kind: string, fields?: Record<string, unknown>, body?: string): Card;
819
+ loadStored(json: string): void;
869
820
  /**
870
821
  * Move the card at `from` to position `to`. `from == to` is a no-op.
871
822
  */
@@ -914,17 +865,10 @@ export class Document {
914
865
  removeCard(index: number): Card | undefined;
915
866
  /**
916
867
  * Remove the `$ext` map on the card `addr` targets entirely, returning the
917
- * previous map or `undefined`. Discards every namespace at once; prefer
918
- * `removeExtNamespace`. Throws on a present `field` or an out-of-range card.
868
+ * previous map or `undefined`. Discards every namespace at once. Throws on
869
+ * a present `field` or an out-of-range card.
919
870
  */
920
871
  removeExt(addr?: CardAddr): Record<string, unknown> | undefined;
921
- /**
922
- * Remove `$ext[ns]` on the card `addr` targets, returning its value or
923
- * `undefined`; drops `$ext` once empty. `addr` is a card address (absent =
924
- * main). Preserves sibling namespaces. Throws on a present `field` or an
925
- * out-of-range card.
926
- */
927
- removeExtNamespace(addr: CardAddr, ns: string): any;
928
872
  /**
929
873
  * Remove a field at `addr`, returning the removed value or `undefined`. A
930
874
  * bare string is `Addr` shorthand for `{ field }`. A body address throws, as
@@ -954,12 +898,6 @@ export class Document {
954
898
  * and keeps `seedCard` pure: the quill never reads the document.
955
899
  */
956
900
  seedOverlay(kind: string): Record<string, unknown> | undefined;
957
- /**
958
- * Replace the kind of the card at `index`. Payload and body are untouched;
959
- * schema-aware migration is the caller's responsibility.
960
- * Throws if `index` is out of range or `newKind` is invalid.
961
- */
962
- setCardKind(index: number, new_kind: string): void;
963
901
  /**
964
902
  * Replace the QUILL reference string. Throws if `ref_str` is invalid.
965
903
  */
@@ -967,7 +905,7 @@ export class Document {
967
905
  /**
968
906
  * Read the storage version tag from a raw storage DTO string without a full
969
907
  * parse, or `undefined`. Unknown future versions come back as-is, which
970
- * distinguishes "build too old" from "payload corrupt" when `fromJson`
908
+ * distinguishes "build too old" from "payload corrupt" when `fromStored`
971
909
  * throws. This is the storage version, not a field schema, though the JSON
972
910
  * key is spelled `"schema"`: that is the DTO's serde tag.
973
911
  */
@@ -975,16 +913,12 @@ export class Document {
975
913
  /**
976
914
  * Replace the opaque `$ext` map on the card `addr` targets (absent `card` =
977
915
  * main). `value` must be a plain object. `$ext` carries out-of-band consumer
978
- * state and never reaches the rendered output. Throws on a present `field`
979
- * or an out-of-range card.
916
+ * state and never reaches the rendered output. The whole map is the write,
917
+ * so a consumer holding one namespace merges the rest:
918
+ * `{...doc.getExt(addr), [ns]: v}`. Throws on a present `field` or an
919
+ * out-of-range card.
980
920
  */
981
921
  storeExt(addr: CardAddr, value: any): void;
982
- /**
983
- * Merge `value` into `$ext[ns]` on the card `addr` targets, preserving
984
- * sibling namespaces: the recommended `$ext` write. Throws on a present
985
- * `field` or an out-of-range card.
986
- */
987
- storeExtNamespace(addr: CardAddr, ns: string, value: any): void;
988
922
  /**
989
923
  * Store a field verbatim at `addr`, deferring coercion to render; the typed
990
924
  * write is [`commitField`](Document::commit_field). A bare string is `Addr`
@@ -1014,24 +948,18 @@ export class Document {
1014
948
  * with. Throws if `overlay` cannot be serialized or nests too deep.
1015
949
  */
1016
950
  storeSeedOverlay(card_kind: string, overlay: any): void;
1017
- /**
1018
- * Serialize this document to a versioned storage DTO string. Prefer it over
1019
- * `toMarkdown` for persistence: the wire format is frozen per `schema`
1020
- * version and the output is byte-deterministic within one, so equal
1021
- * documents hash equal. Parse-time `warnings` are excluded.
1022
- */
1023
- toJson(): string;
1024
951
  /**
1025
952
  * Emit canonical Quillmark Markdown. Round-trip safe: re-parsing the
1026
953
  * result produces a `Document` equal to `self` by value and by type.
1027
954
  */
1028
955
  toMarkdown(): string;
1029
956
  /**
1030
- * Like [`fromJson`](Document::from_json) but returns `undefined` instead of
1031
- * throwing when `json` is not a valid storage DTO, to discriminate format
1032
- * without exceptions as control flow.
957
+ * Serialize this document to a versioned storage DTO string. Prefer it over
958
+ * `toMarkdown` for persistence: the wire format is frozen per `schema`
959
+ * version and the output is byte-deterministic within one, so equal
960
+ * documents hash equal. Parse-time `warnings` are excluded.
1033
961
  */
1034
- static tryFromJson(json: string): Document | undefined;
962
+ toStored(): string;
1035
963
  /**
1036
964
  * Number of composable cards, excluding the main card.
1037
965
  */
@@ -1046,20 +974,20 @@ export class Document {
1046
974
  * The non-fatal diagnostics of the load that produced this document: parse
1047
975
  * warnings, plus `conform::*` warnings when it came through `quill.parse`.
1048
976
  * Session state, not document value: `equals` and the storage DTO exclude
1049
- * it, and `fromJson` / `loadJson` clear it.
977
+ * it, and `fromStored` / `loadStored` clear it.
1050
978
  */
1051
979
  readonly warnings: Diagnostic[];
1052
980
  }
1053
981
 
1054
982
  /**
1055
- * Live render session: every read serves the current compile. `apply(doc)`
983
+ * Live render session: every read serves the current compile. `update(doc)`
1056
984
  * recompiles a whole document in place, transactionally — on throw the reads
1057
985
  * keep serving the last-good compile. Geometry is per-compile, so re-read it
1058
- * after each committed `apply`.
986
+ * after each committed `update`.
1059
987
  *
1060
988
  * A zero-page document yields a valid session (`pageCount === 0`) whose
1061
- * `paint(ctx, 0)` and `pageSize(0)` throw; branch on `pageCount === 0` rather
1062
- * than catching.
989
+ * `paint(ctx, 0)` and `pageSize(0)` throw as any out-of-range page does; branch
990
+ * on `pageCount === 0` rather than catching.
1063
991
  */
1064
992
  export class LiveSession {
1065
993
  private constructor();
@@ -1072,8 +1000,14 @@ export class LiveSession {
1072
1000
  * `FieldRegion.rect`, so from a canvas click use
1073
1001
  * `x = clickPx.x / renderScale`, `y = pageHeightPt - clickPx.y / renderScale`.
1074
1002
  * Unlike `regions()`, *every* placement answers, not just the first.
1003
+ *
1004
+ * `tolPt` is how far off the ink a click still counts, in the same points,
1005
+ * and defaults to `0` — exact. Convert the pointer slack a surface wants
1006
+ * from CSS pixels at the scale it drew the page (`slackPx / renderScale`),
1007
+ * so it stays the same size under the cursor as the page zooms. The
1008
+ * nearest placement answers, so raising it only fills a miss.
1075
1009
  */
1076
- fieldAt(page: number, x: number, y: number): string | undefined;
1010
+ fieldAt(page: number, x: number, y: number, tol_pt?: number | null): string | undefined;
1077
1011
  /**
1078
1012
  * The whole-field highlight boxes for `field`: one union rect per page over
1079
1013
  * the field's `span`-bearing content segments, the union `regions()` leaves
@@ -1090,8 +1024,8 @@ export class LiveSession {
1090
1024
  */
1091
1025
  locate(field: string, pos: number): FieldRegion | undefined;
1092
1026
  /**
1093
- * Page dimensions in points (1 pt = 1/72 inch).
1094
- * Throws if the backend has no canvas painter or `page` is out of range.
1027
+ * Page dimensions in points (1 pt = 1/72 inch). Throws if `page` is out of
1028
+ * range, which a zero-page compile makes true of every index.
1095
1029
  */
1096
1030
  pageSize(page: number): PageSize;
1097
1031
  /**
@@ -1106,18 +1040,23 @@ export class LiveSession {
1106
1040
  * its own `<canvas>`: no compositing, sub-rect, or transform reaches through
1107
1041
  * this call.
1108
1042
  *
1109
- * Throws if the backend has no canvas painter, `page` is out of range, `ctx`
1110
- * is the wrong type, or either scale is non-finite or `<= 0`.
1043
+ * Throws if `page` is out of range, `ctx` is the wrong type, either scale is
1044
+ * non-finite or `<= 0`, or the page cannot be rasterized at the resulting
1045
+ * scale (`backend::invalid_raster_scale`).
1111
1046
  */
1112
1047
  paint(ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, page: number, opts: PaintOptions | undefined): PaintResult;
1113
1048
  /**
1114
1049
  * A point → **content position**: the field *and* a USV offset into its
1115
1050
  * `Content`, for placing a caret or mapping a selection into the content
1116
- * model, or `undefined` off all content ink. `x`/`y` are PDF points,
1117
- * bottom-left origin, as in `fieldAt`. The offset is cluster-exact and
1118
- * degrades to the containing segment's start on origin-less ink.
1051
+ * model, or `undefined` off all content ink. `x`/`y`/`tolPt` are PDF
1052
+ * points, bottom-left origin, as in `fieldAt`. The offset is cluster-exact
1053
+ * and degrades to the containing segment's start on origin-less ink.
1054
+ *
1055
+ * `tolPt` earns the most here: the leading between two lines lies inside a
1056
+ * paragraph and on no glyph, and under `tolPt` such a point takes the
1057
+ * nearer line.
1119
1058
  */
1120
- positionAt(page: number, x: number, y: number): ContentHit | undefined;
1059
+ positionAt(page: number, x: number, y: number, tol_pt?: number | null): ContentHit | undefined;
1121
1060
  /**
1122
1061
  * Schema-field geometry for this compiled session: each content field's
1123
1062
  * **first placement** (one region per page it touches) plus widget and
@@ -1144,13 +1083,9 @@ export class LiveSession {
1144
1083
  */
1145
1084
  readonly backendId: string;
1146
1085
  readonly pageCount: number;
1147
- /**
1148
- * `true` iff `paint` and `pageSize` will succeed for this session.
1149
- */
1150
- readonly supportsCanvas: boolean;
1151
1086
  /**
1152
1087
  * Non-fatal diagnostics of the session's **current compile**, refreshed by
1153
- * each committed `apply`; a failed apply keeps the last-good compile's.
1088
+ * each committed `update`; a failed `update` keeps the last-good compile's.
1154
1089
  * Also appended to `RenderResult.warnings` on each `render()`.
1155
1090
  */
1156
1091
  readonly warnings: Diagnostic[];
@@ -1164,7 +1099,7 @@ export class Quill {
1164
1099
  * Land `doc`'s declared content fields at their canonical rest **in
1165
1100
  * place**, returning the `conform::*` diagnostics for values that would not
1166
1101
  * commit. The read-repair verb for a document that arrived through the
1167
- * transport door (`fromMarkdown`, `fromJson`, a stored row).
1102
+ * transport door (`fromMarkdown`, `fromStored`, a stored row).
1168
1103
  *
1169
1104
  * Idempotent: an equal value is not rewritten, so YAML comments and stored
1170
1105
  * bytes survive. A `!must_fill` marker anywhere in a field's value skips
@@ -1192,14 +1127,6 @@ export class Quill {
1192
1127
  * is stale, use `Document.fromMarkdown`, `setQuillRef`, then `quill.conform`.
1193
1128
  */
1194
1129
  parse(markdown: string): Document;
1195
- /**
1196
- * The resolved-value view of `doc`: for every declared field, the value the
1197
- * render projection would use and the `FieldSource` rung it came from
1198
- * (`"authored" | "default" | "blank"`). The card body is a `body` sibling on
1199
- * its card, never a row in `fields`, and `null` when the kind enables no
1200
- * body. Value and provenance only; completeness stays `validate`'s.
1201
- */
1202
- resolve(doc: Document): Resolved;
1203
1130
  /**
1204
1131
  * Seed a starter composable `Card` of the given kind (carries `$kind`),
1205
1132
  * layering an optional per-kind seed `overlay` over the schema-example base
@@ -1229,8 +1156,8 @@ export class Quill {
1229
1156
  *
1230
1157
  * This is how a quill crosses a WASM linear-memory boundary as data: a
1231
1158
  * `Quill` built in one build cannot be passed to an engine in another, so
1232
- * `@quillmark/wasm/runtime` re-feeds this tree to the backend build's
1233
- * `Quill.fromTree` on demand.
1159
+ * the `@quillmark/wasm` runtime layer re-feeds this tree to the backend
1160
+ * build's `Quill.fromTree` on demand.
1234
1161
  */
1235
1162
  toTree(): Map<string, Uint8Array>;
1236
1163
  /**
@@ -1247,9 +1174,9 @@ export class Quill {
1247
1174
  readonly backendId: string;
1248
1175
  readonly blueprint: string;
1249
1176
  /**
1250
- * Identity snapshot of the `quill:` section of `Quill.yaml` plus any extra
1251
- * `quill:` keys. Pure config: output formats are a resolved-backend
1252
- * capability read from `Quillmark.supportedFormats`, not part of this.
1177
+ * Identity snapshot of the `quill:` section of `Quill.yaml`. Pure config:
1178
+ * output formats are a resolved-backend capability read from
1179
+ * `Quillmark.supportedFormats`, not part of this.
1253
1180
  */
1254
1181
  readonly metadata: QuillMetadata;
1255
1182
  /**
@@ -1258,6 +1185,12 @@ export class Quill {
1258
1185
  * ordering contract.
1259
1186
  */
1260
1187
  readonly schema: QuillSchema;
1188
+ /**
1189
+ * The advisory diagnostics of the load that produced this quill: what is
1190
+ * wrong with it short of refusing it. A quill that loads clean answers
1191
+ * `[]`.
1192
+ */
1193
+ readonly warnings: Diagnostic[];
1261
1194
  }
1262
1195
 
1263
1196
  /**
@@ -1284,12 +1217,6 @@ export class Quillmark {
1284
1217
  * backend matches the quill's declared one.
1285
1218
  */
1286
1219
  supportedFormats(quill: Quill): OutputFormat[];
1287
- /**
1288
- * Whether `quill`'s backend can paint sessions to a canvas; `false` when the
1289
- * backend is unsupported. A cheap probe before mounting a preview UI. The
1290
- * authoritative answer is the session's `supportsCanvas` getter.
1291
- */
1292
- supportsCanvas(quill: Quill): boolean;
1293
1220
  }
1294
1221
 
1295
1222
  /**
@@ -1388,18 +1315,15 @@ export interface InitOutput {
1388
1315
  readonly document_clone: (a: number) => number;
1389
1316
  readonly document_currentStorageVersion: (a: number) => void;
1390
1317
  readonly document_equals: (a: number, b: number) => number;
1391
- readonly document_formatDiagnostic: (a: number, b: number) => void;
1392
1318
  readonly document_formatRules: (a: number) => void;
1393
- readonly document_fromJson: (a: number, b: number, c: number) => void;
1394
1319
  readonly document_fromMarkdown: (a: number, b: number, c: number) => void;
1320
+ readonly document_fromStored: (a: number, b: number, c: number) => void;
1395
1321
  readonly document_getExt: (a: number, b: number, c: number) => void;
1396
- readonly document_getExtNamespace: (a: number, b: number, c: number, d: number, e: number) => void;
1397
1322
  readonly document_getStored: (a: number, b: number, c: number) => void;
1398
1323
  readonly document_insertCard: (a: number, b: number, c: number, d: number) => void;
1399
1324
  readonly document_isFill: (a: number, b: number, c: number) => void;
1400
- readonly document_loadJson: (a: number, b: number, c: number, d: number) => void;
1325
+ readonly document_loadStored: (a: number, b: number, c: number, d: number) => void;
1401
1326
  readonly document_main: (a: number, b: number) => void;
1402
- readonly document_makeCard: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
1403
1327
  readonly document_moveCard: (a: number, b: number, c: number, d: number) => void;
1404
1328
  readonly document_new: (a: number, b: number, c: number) => void;
1405
1329
  readonly document_overwrite: (a: number, b: number, c: number, d: number) => void;
@@ -1408,61 +1332,56 @@ export interface InitOutput {
1408
1332
  readonly document_quillRefHint: (a: number) => void;
1409
1333
  readonly document_removeCard: (a: number, b: number, c: number) => void;
1410
1334
  readonly document_removeExt: (a: number, b: number, c: number) => void;
1411
- readonly document_removeExtNamespace: (a: number, b: number, c: number, d: number, e: number) => void;
1412
1335
  readonly document_removeField: (a: number, b: number, c: number) => void;
1413
1336
  readonly document_removeSeedOverlay: (a: number, b: number, c: number, d: number) => void;
1414
1337
  readonly document_revise: (a: number, b: number, c: number, d: number, e: number) => void;
1415
1338
  readonly document_seedOverlay: (a: number, b: number, c: number, d: number) => void;
1416
- readonly document_setCardKind: (a: number, b: number, c: number, d: number, e: number) => void;
1417
1339
  readonly document_setQuillRef: (a: number, b: number, c: number, d: number) => void;
1418
1340
  readonly document_storageVersionOf: (a: number, b: number, c: number) => void;
1419
1341
  readonly document_storeExt: (a: number, b: number, c: number, d: number) => void;
1420
- readonly document_storeExtNamespace: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
1421
1342
  readonly document_storeField: (a: number, b: number, c: number, d: number) => void;
1422
1343
  readonly document_storeFields: (a: number, b: number, c: number, d: number) => void;
1423
1344
  readonly document_storeFill: (a: number, b: number, c: number, d: number) => void;
1424
1345
  readonly document_storeSeedOverlay: (a: number, b: number, c: number, d: number, e: number) => void;
1425
- readonly document_toJson: (a: number, b: number) => void;
1426
1346
  readonly document_toMarkdown: (a: number, b: number) => void;
1427
- readonly document_tryFromJson: (a: number, b: number) => number;
1347
+ readonly document_toStored: (a: number, b: number) => void;
1428
1348
  readonly document_warnings: (a: number, b: number) => void;
1429
1349
  readonly exportMarkdown: (a: number, b: number) => void;
1430
1350
  readonly formatDocPath: (a: number, b: number) => void;
1431
1351
  readonly importMarkdown: (a: number, b: number, c: number) => void;
1432
1352
  readonly livesession_backendId: (a: number, b: number) => void;
1433
- readonly livesession_fieldAt: (a: number, b: number, c: number, d: number, e: number) => void;
1353
+ readonly livesession_fieldAt: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
1434
1354
  readonly livesession_fieldBoxes: (a: number, b: number, c: number, d: number) => void;
1435
- readonly livesession_locate: (a: number, b: number, c: number, d: number) => number;
1355
+ readonly livesession_locate: (a: number, b: number, c: number, d: number, e: number) => void;
1436
1356
  readonly livesession_pageCount: (a: number) => number;
1437
1357
  readonly livesession_pageSize: (a: number, b: number, c: number) => void;
1438
1358
  readonly livesession_paint: (a: number, b: number, c: number, d: number, e: number) => void;
1439
- readonly livesession_positionAt: (a: number, b: number, c: number, d: number) => number;
1359
+ readonly livesession_positionAt: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
1440
1360
  readonly livesession_regions: (a: number, b: number) => void;
1441
1361
  readonly livesession_render: (a: number, b: number, c: number) => void;
1442
- readonly livesession_supportsCanvas: (a: number) => number;
1443
1362
  readonly livesession_update: (a: number, b: number, c: number) => void;
1444
1363
  readonly livesession_warnings: (a: number, b: number) => void;
1445
1364
  readonly mapMarks: (a: number, b: number, c: number) => void;
1446
1365
  readonly mapPos: (a: number, b: number, c: number, d: number) => void;
1447
1366
  readonly parseDocPath: (a: number, b: number, c: number) => void;
1367
+ readonly quill__resolve: (a: number, b: number, c: number) => void;
1448
1368
  readonly quill_backendId: (a: number, b: number) => void;
1449
1369
  readonly quill_blueprint: (a: number, b: number) => void;
1450
1370
  readonly quill_conform: (a: number, b: number, c: number) => void;
1451
1371
  readonly quill_fromTree: (a: number, b: number) => void;
1452
1372
  readonly quill_metadata: (a: number, b: number) => void;
1453
1373
  readonly quill_parse: (a: number, b: number, c: number, d: number) => void;
1454
- readonly quill_resolve: (a: number, b: number, c: number) => void;
1455
1374
  readonly quill_schema: (a: number, b: number) => void;
1456
1375
  readonly quill_seedCard: (a: number, b: number, c: number, d: number, e: number) => void;
1457
1376
  readonly quill_seedDocument: (a: number) => number;
1458
1377
  readonly quill_seedMain: (a: number, b: number) => void;
1459
1378
  readonly quill_toTree: (a: number) => number;
1460
1379
  readonly quill_validate: (a: number, b: number, c: number) => void;
1380
+ readonly quill_warnings: (a: number, b: number) => void;
1461
1381
  readonly quillmark_new: () => number;
1462
1382
  readonly quillmark_open: (a: number, b: number, c: number, d: number) => void;
1463
1383
  readonly quillmark_render: (a: number, b: number, c: number, d: number, e: number) => void;
1464
1384
  readonly quillmark_supportedFormats: (a: number, b: number, c: number) => void;
1465
- readonly quillmark_supportsCanvas: (a: number, b: number) => number;
1466
1385
  readonly rebase: (a: number, b: number, c: number, d: number) => void;
1467
1386
  readonly start: () => void;
1468
1387
  readonly __wbindgen_export: (a: number, b: number) => number;