@quillmark/wasm 0.94.0 → 0.95.1

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 `pushCard` / `makeCard`.
20
+ * placeholders. Preserved across `insertCard` / `makeCard`.
21
21
  */
22
22
  nestedFills?: PathStep[][];
23
23
  }
@@ -27,7 +27,7 @@ export type PayloadItem =
27
27
  * A single card block, as read back from a document: returned by
28
28
  * `Document.main` / `Document.cards` / `Document.removeCard` / `Quill.seedCard`
29
29
  * / `Document.makeCard`. To feed a card *into* a document use `CardInput`
30
- * (which `pushCard` / `insertCard` accept); every `Card` is a valid `CardInput`,
30
+ * (which `insertCard` accepts); every `Card` is a valid `CardInput`,
31
31
  * so a card read from one document pushes straight into another.
32
32
  *
33
33
  * `$` system entries are hoisted to named fields: `kind` (the `$kind`, empty
@@ -44,19 +44,19 @@ export interface Card {
44
44
  seed?: Record<string, unknown>;
45
45
  payloadItems: PayloadItem[];
46
46
  /**
47
- * The card body as canonical `RichText` — the source-of-truth content model.
48
- * Always this corpus shape on read, never a markdown string. For the markdown
47
+ * The card body as canonical `Content` — the source-of-truth content model.
48
+ * Always this content shape on read, never a markdown string. For the markdown
49
49
  * projection call the codec `exportMarkdown(card.body)`. Write a body back
50
50
  * with `doc.install(addr, rt)` / `doc.revise(addr, md)`, or via `CardInput.body`.
51
51
  */
52
- body: RichText;
52
+ body: Content;
53
53
  }
54
54
 
55
55
  /**
56
56
  * A card written *into* a document — the input twin of `Card`, accepted by
57
- * `Document.pushCard` / `Document.insertCard`. Like `Card` but `body` also
58
- * takes a markdown `string` (imported to the corpus, so a markdown / LLM writer
59
- * needn't build the `RichText` shape), and every field but `kind` is optional —
57
+ * `Document.insertCard`. Like `Card` but `body` also
58
+ * 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 —
60
60
  * an absent field defaults (no payload items, an empty body). Write one inline
61
61
  * (`{ kind, body }`) or build it with `Document.makeCard`.
62
62
  */
@@ -67,26 +67,26 @@ export interface CardInput {
67
67
  ext?: Record<string, unknown>;
68
68
  seed?: Record<string, unknown>;
69
69
  payloadItems?: PayloadItem[];
70
- body?: RichText | string;
70
+ body?: Content | string;
71
71
  }
72
72
 
73
73
  /**
74
- * Canonical richtext corpus — the content model for a card body (and richtext
74
+ * Canonical richtext content — the content model for a card body (and richtext
75
75
  * fields). One text sequence over a single coordinate space (Unicode scalar
76
76
  * values): `text` plus line attributes, anchored `marks`, and embedded
77
77
  * `islands`. Every edit is a splice; markdown is a projection, not the model.
78
- * Mirrors `quillmark_richtext::serial`'s canonical JSON encoding.
78
+ * Mirrors `quillmark_content::serial`'s canonical JSON encoding.
79
79
  */
80
- export interface RichText {
80
+ export interface Content {
81
81
  text: string;
82
- lines: RichTextLine[];
83
- marks: RichTextMark[];
84
- islands: RichTextIsland[];
82
+ lines: ContentLine[];
83
+ marks: ContentMark[];
84
+ islands: ContentIsland[];
85
85
  }
86
86
 
87
- /** One `\n`-separated segment of `RichText.text`, in order. */
88
- export type RichTextLine = {
89
- containers: RichTextContainer[];
87
+ /** One `\n`-separated segment of `Content.text`, in order. */
88
+ export type ContentLine = {
89
+ containers: ContentContainer[];
90
90
  /** A within-block hard line break rather than a new block. Omitted (false) in the common case. */
91
91
  continues?: boolean;
92
92
  } & (
@@ -98,20 +98,20 @@ export type RichTextLine = {
98
98
  );
99
99
 
100
100
  /** An ancestor block a line nests inside, outermost first. */
101
- export type RichTextContainer =
101
+ export type ContentContainer =
102
102
  | { container: "list_item"; ordered: boolean; start: number; ordinal: number }
103
103
  | { container: "quote" };
104
104
 
105
- /** A mark over char range `[start, end)` into `RichText.text`. */
106
- export type RichTextMark = { start: number; end: number } & (
105
+ /** A mark over char range `[start, end)` into `Content.text`. */
106
+ export type ContentMark = { start: number; end: number } & (
107
107
  | { type: "strong" | "emph" | "underline" | "strike" | "code" }
108
108
  | { type: "link"; url: string }
109
109
  | { type: "anchor"; id: string }
110
110
  | { type: string; attrs: unknown }
111
111
  );
112
112
 
113
- /** A structured object (table, figure, …) occupying one island slot in `RichText.text`. */
114
- export interface RichTextIsland {
113
+ /** A structured object (table, figure, …) occupying one island slot in `Content.text`. */
114
+ export interface ContentIsland {
115
115
  id: string;
116
116
  type: string;
117
117
  props: unknown;
@@ -120,10 +120,16 @@ export interface RichTextIsland {
120
120
  }
121
121
 
122
122
  /**
123
- * A richtext write address. An absent `field` targets the card body; an absent
124
- * `card` targets the main card. `{}` is the main-card body; `{ card: 2 }` the
125
- * body of the composable card at index 2; `{ field: "intro" }` the main card's
126
- * `intro` richtext field; `{ card: 2, field: "intro" }` a card field.
123
+ * A write address one navigation concept for the whole `Document` surface. An
124
+ * absent `field` targets the card body; an absent `card` targets the main card.
125
+ * `{}` is the main-card body; `{ card: 2 }` the body of the composable card at
126
+ * index 2; `{ field: "intro" }` the main card's `intro` field; `{ card: 2,
127
+ * field: "intro" }` a card field.
128
+ *
129
+ * On the `Addr`-taking verbs a **bare string** is shorthand for `{ field: name }`
130
+ * — `doc.storeField("qty", 3)`, `doc.revise("intro", md)` — the one coercion
131
+ * rule. A bare number is *not* an addr (`{ card: 2 }` is the self-documenting
132
+ * spelling), so no third navigation idiom re-fragments the surface.
127
133
  */
128
134
  export interface Addr {
129
135
  card?: number;
@@ -131,7 +137,17 @@ export interface Addr {
131
137
  }
132
138
 
133
139
  /**
134
- * A text-splice change set over the USV corpus (CodeMirror `ChangeSet`
140
+ * A card-only address the axis the card-scoped verbs (`storeFields`,
141
+ * `storeExt`, `getExt`, `commitFields`, …) take. An absent `card` targets the
142
+ * main card. A present `field` throws: a card address takes only `card`, and a
143
+ * would-be nested write is a bug the error names rather than silently ignores.
144
+ */
145
+ export interface CardAddr {
146
+ card?: number;
147
+ }
148
+
149
+ /**
150
+ * A text-splice change set over the USV content (CodeMirror `ChangeSet`
135
151
  * semantics) — plain, structured-clone-able data. Returned by `revise` and by
136
152
  * the `rebase` codec; map a stored position through it with `mapPos`.
137
153
  */
@@ -143,9 +159,9 @@ export interface Delta {
143
159
  export type Assoc = "before" | "after";
144
160
 
145
161
  /**
146
- * A mark edit in post-text-delta coordinates. `add` / `remove` carry the
147
- * `RichTextMark` vocabulary (`{ type, … }`); `removeAnchor` drops one identity
148
- * anchor by id.
162
+ * A mark edit in final-text coordinates (post-delta, post-line-op). `add` /
163
+ * `remove` carry the `ContentMark` vocabulary (`{ type, … }`); `removeAnchor`
164
+ * drops one identity anchor by id.
149
165
  */
150
166
  export type MarkOp =
151
167
  | ({ op: "add" | "remove"; start: number; end: number } & (
@@ -156,7 +172,13 @@ export type MarkOp =
156
172
  ))
157
173
  | { op: "removeAnchor"; id: string };
158
174
 
159
- /** A line/block edit. `split`/`join` splice `\n`; `setKind`/`setContainers` touch metadata. */
175
+ /**
176
+ * A line/block edit. `split`/`join` splice `\n`; `setKind`/`setContainers`/
177
+ * `setContinues` touch metadata. `setContinues` sets/clears a line's within-block
178
+ * hard-break flag (`ContentLine.continues`) — the op-grained way to lower a
179
+ * Shift+Enter hard break or a new code-fence interior line; `continues: true` on
180
+ * line 0 is rejected (nothing precedes it to continue).
181
+ */
160
182
  export type LineOp =
161
183
  | { op: "split"; at: number }
162
184
  | { op: "join"; line: number }
@@ -165,10 +187,11 @@ export type LineOp =
165
187
  | { kind: "heading"; level: number }
166
188
  | { kind: "code"; lang?: string }
167
189
  ))
168
- | { op: "setContainers"; line: number; containers: RichTextContainer[] };
190
+ | { op: "setContainers"; line: number; containers: ContentContainer[] }
191
+ | { op: "setContinues"; line: number; continues: boolean };
169
192
 
170
193
  /**
171
- * A committed corpus edit bundle for `applyChange`: a text `delta` (default no
194
+ * A committed content edit bundle for `applyChange`: a text `delta` (default no
172
195
  * text change), then `lineOps`, then `markOps` (mark ranges are in post-delta
173
196
  * coordinates). Every field is optional.
174
197
  */
@@ -298,7 +321,7 @@ export interface QuillCardBody {
298
321
  * zero-fills the field). There is no separate `required` axis.
299
322
  */
300
323
  export interface QuillFieldSchema {
301
- type: "string" | "number" | "integer" | "boolean" | "array" | "object" | "datetime" | "richtext" | "plaintext" | "enum";
324
+ type: "string" | "number" | "integer" | "boolean" | "array" | "object" | "date" | "datetime" | "richtext" | "plaintext" | "enum";
302
325
  description?: string;
303
326
  default?: unknown;
304
327
  example?: unknown;
@@ -364,7 +387,7 @@ export interface ChangeSet {
364
387
  dirtyPages: number[];
365
388
  }
366
389
 
367
- export interface CorpusHit {
390
+ export interface ContentHit {
368
391
  field: string;
369
392
  pos: number;
370
393
  granularity?: HitGranularity;
@@ -423,28 +446,16 @@ export class Document {
423
446
  free(): void;
424
447
  [Symbol.dispose](): void;
425
448
  /**
426
- * Build a composable card of `kind`, typed-commit `fields` onto it, set its
427
- * body from optional markdown, and append it — the ABI under
428
- * `writer.addCard`. Fuses `makeCard` + typed commit + `pushCard`
429
- * transactionally: the card is committed in full before it joins the
430
- * document, so a rejected field (or an invalid kind or body) leaves the
431
- * document untouched. Field errors throw the same per-field diagnostic
432
- * bundle as [`commitFields`](Self::commit_fields), including an
433
- * `[EditError::UnknownField]` per undeclared name; an invalid kind or body
434
- * throws a single-entry bundle keyed `$kind` / `$body`.
435
- */
436
- addCard(quill: Quill, kind: string, fields?: Record<string, unknown>, body?: string): void;
437
- /**
438
- * **Apply** a committed corpus edit `bundle` (`{ delta?, lineOps?, markOps? }`)
449
+ * **Apply** a committed content edit `bundle` (`{ delta?, lineOps?, markOps? }`)
439
450
  * at `addr` — the editor splice: text delta first, then line ops, then mark
440
- * ops (mark ranges in post-delta coordinates), each all-or-nothing. An absent
451
+ * ops (mark ranges in final-text coordinates), each all-or-nothing. An absent
441
452
  * `addr.field` targets the body, an absent `addr.card` the main card.
442
453
  *
443
454
  * Throws on an out-of-range card, a field that is not richtext, a malformed
444
455
  * bundle, or an op that applies out of bounds (the value is unchanged on a
445
456
  * failed apply).
446
457
  */
447
- applyChange(addr: Addr, bundle: ChangeBundle): void;
458
+ applyChange(addr: Addr | string, bundle: ChangeBundle): void;
448
459
  /**
449
460
  * Authoring-ergonomics header introducing a blueprint to an LLM/MCP
450
461
  * consumer for the given `quillName`. Re-exposes core's canonical text for
@@ -452,61 +463,22 @@ export class Document {
452
463
  * uniform.
453
464
  */
454
465
  static blueprintInstruction(quill_name: string): string;
455
- clone(): Document;
456
466
  /**
457
- * Typed field write on the composable card at `index` — the card-indexed
458
- * twin of [`commitField`](Document::commit_field). Resolves the field's
459
- * type from the card's `$kind` schema in `quill` and strict-commits it.
460
- *
461
- * Throws `[EditError::IndexOutOfRange]` when `index` is out of range, and
462
- * the same typed-mismatch / name errors as `commitField` — including
463
- * `[EditError::UnknownField]` for a field the card-kind schema does not
464
- * declare (an unknown `$kind` has no schema, so every field is undeclared).
465
- */
466
- commitCardField(quill: Quill, index: number, name: string, value: any): void;
467
- /**
468
- * Batched twin of [`commitCardField`](Document::commit_card_field):
469
- * typed-commit several fields on the card at `index` atomically, resolving
470
- * each field's type from the card's `$kind` schema in `quill`. All-or-nothing
471
- * with the same per-field-diagnostic contract as
472
- * [`commitFields`](Document::commit_fields), including an
473
- * `[EditError::UnknownField]` diagnostic per undeclared name. Throws
474
- * `[EditError::IndexOutOfRange]` when `index` is out of range.
475
- */
476
- commitCardFields(quill: Quill, index: number, fields: Record<string, unknown>): void;
477
- /**
478
- * Typed field write on the main card, resolving the field's schema `type`
479
- * from `quill` — the one write verb for **every** field type (richtext,
480
- * scalar, array, object). The schema carries the `inline` constraint, so no
481
- * type token or flag is passed. A richtext-typed field stores the canonical
482
- * corpus, so identity marks (anchors, island ids) and corpus-only marks
483
- * (e.g. `underline`) live on it and survive compiles and the storage DTO.
484
- * Values use the encoding the seam already speaks: a corpus object
485
- * or markdown string for richtext, a scalar/array/object otherwise.
486
- *
487
- * A field declared in the schema is strict-committed — a mismatch throws
488
- * now, not at render. A name the schema does not declare throws
489
- * `[EditError::UnknownField]` rather than falling to the opaque store: on
490
- * the typed path it is a typo. Use [`setField`](Document::set_field) when
491
- * opaque storage is the intent. Also throws `[EditError::FieldConform]` /
492
- * `[EditError::FieldRichtextDecode]` / `[EditError::FieldRichtextNotInline]`
493
- * on a typed mismatch and `[EditError::InvalidFieldName]` on a malformed
494
- * name.
495
- *
496
- * The `quill` handle is passed per call because a `Document` carries only a
497
- * `$quill` reference, not the resolved schema.
467
+ * A single composable card by index — the whole `Card`, the card-indexed
468
+ * twin of the [`main`](Self::main) getter, so reading one card need not
469
+ * materialize every card via [`cards`](Self::cards). An out-of-range
470
+ * `index` throws `[EditError::IndexOutOfRange]`, matching the card write
471
+ * verbs.
498
472
  */
499
- commitField(quill: Quill, name: string, value: any): void;
473
+ card(index: number): Card;
500
474
  /**
501
- * Batched twin of [`commitField`](Document::commit_field): typed-commit
502
- * several main-card fields atomically, resolving each field's schema `type`
503
- * from `quill`. All-or-nothing with the same per-field-diagnostic error
504
- * contract as [`setFields`](Document::set_fields) nothing is applied on
505
- * error and the thrown error's `diagnostics` carry one entry per offending
506
- * field, including an `[EditError::UnknownField]` for any name the schema
507
- * does not declare, so a whole-form submit sees every typo in one pass.
475
+ * The index of the first composable card whose `$id` equals `id`, or
476
+ * `undefined` when none carries it. Resolves the canonical durable address
477
+ * without a hand-rolled scan over [`cards`](Self::cards); `$id` is
478
+ * non-unique by design, so the first match wins.
508
479
  */
509
- commitFields(quill: Quill, fields: Record<string, unknown>): void;
480
+ cardIndexById(id: string): number | undefined;
481
+ clone(): Document;
510
482
  /**
511
483
  * Schema version this build writes via [`toJson`](Document::to_json).
512
484
  * Tracks the `Document` model version (not the running crate version):
@@ -546,30 +518,54 @@ export class Document {
546
518
  */
547
519
  static fromMarkdown(markdown: string): Document;
548
520
  /**
549
- * Read a main-card field's stored value — the raw payload value (a corpus
550
- * object for a richtext field, a scalar/array/object otherwise), or
551
- * `undefined` when the field is absent. The quill-free read: reads need no
552
- * schema, so they live on `Document`, not the typed writer. For the markdown
553
- * projection of a richtext value use [`getMarkdown`](Self::get_markdown).
521
+ * Read the value at `addr` — the raw stored payload value of a field (a
522
+ * content object for a richtext field, a scalar/array/object otherwise), or
523
+ * the **body content** when `addr.field` is absent. A bare string is `Addr`
524
+ * shorthand for `{ field }`. Reads are total over the field axis: an absent
525
+ * field is `undefined`; only an out-of-range `addr.card` throws
526
+ * `[EditError::IndexOutOfRange]`. Reads need no schema, so they live on
527
+ * `Document`, not the typed writer; for the markdown projection of a
528
+ * richtext value use [`getMarkdown`](Self::get_markdown).
554
529
  */
555
- get(name: string): any;
530
+ get(addr: Addr | string): unknown;
556
531
  /**
557
- * The markdown projection of a main-card field (`name` given) or the main
558
- * body (`name` omitted) the on-demand, lossy export (corpus-only marks do
559
- * not survive markdown), returning `""` for an absent field. Re-coins,
560
- * lazily and by name, the projection the eager `fieldMarkdown` /
561
- * `bodyMarkdown` getters dropped in #925; call it only when markdown is what
562
- * you need out.
532
+ * The whole `$ext` map at `addr` (a card address, absent `card` = main), or
533
+ * `undefined` when the card carries none. The fine-grained `$ext` read —
534
+ * your own state without serializing the whole card. Throws on a present
535
+ * `field` (a card address takes only `card`) or an out-of-range card.
563
536
  */
564
- getMarkdown(name?: string): string;
537
+ getExt(addr?: CardAddr): Record<string, unknown> | undefined;
565
538
  /**
566
- * Insert a card at `index` (must be in `0..=cards.length`). Accepts a
567
- * `CardInput` (see [`pushCard`](Self::push_card)).
539
+ * The value stored under `$ext[ns]` at `addr` (a card address, absent `card`
540
+ * = main), or `undefined`. The namespace-scoped `$ext` read — your own slot
541
+ * without a whole-card serialize, and non-destructive (unlike
542
+ * `removeExtNamespace`). Throws on a present `field` or an out-of-range card.
543
+ */
544
+ getExtNamespace(addr: CardAddr, ns: string): unknown;
545
+ /**
546
+ * The **body** markdown projection — the main body, or a composable card's
547
+ * body (`{ card }`) — the on-demand, lossy export (content-only marks do not
548
+ * survive markdown). A body's type is a format fact, not a schema fact, so
549
+ * this read stays quill-free; a body is never absent.
550
+ *
551
+ * `addr` is an optional **card address** (`{ card }`, absent = main). A
552
+ * present `field` throws — a field's markdown is read through the
553
+ * schema-plane `quill.view(doc).get(field)`, which interprets by declared
554
+ * type (#978). An out-of-range `addr.card` throws.
568
555
  */
569
- insertCard(index: number, card: CardInput): void;
556
+ getMarkdown(addr?: CardAddr): string;
570
557
  /**
571
- * **Install** a richtext value at `addr` **value semantics**, corpus only.
572
- * Stores exactly `rt` (a canonical `RichText` corpus object); the identity
558
+ * Insert a card the single insertion verb: `at` absent appends, a number
559
+ * inserts at that index (must be in `0..=cards.length`). Accepts a
560
+ * `CardInput` — a card read back (`cards` / `removeCard` / `quill.seedCard`),
561
+ * a [`makeCard`](Document::make_card) result, or a bare `{ kind, body }`
562
+ * (every returned `Card` is a valid `CardInput`). Throws if `card.kind` is
563
+ * not a valid kind name, or if `at` is out of range.
564
+ */
565
+ insertCard(card: CardInput, at?: number): void;
566
+ /**
567
+ * **Install** a richtext value at `addr` — **value semantics**, content only.
568
+ * Stores exactly `rt` (a canonical `Content` content object); the identity
573
569
  * anchors of any previous value are gone. An absent `addr.field` targets the
574
570
  * body, an absent `addr.card` the main card. For "here's new markdown," use
575
571
  * [`revise`](Document::revise); the cold-import path is spelled at the call
@@ -577,9 +573,16 @@ export class Document {
577
573
  * source.
578
574
  *
579
575
  * Throws on an out-of-range card, a malformed field name, or an `rt` that is
580
- * not a canonical corpus object.
576
+ * not a canonical content object.
577
+ */
578
+ install(addr: Addr | string, rt: Content): void;
579
+ /**
580
+ * Whether the field at `addr` is marked `!must_fill`. A bare string is `Addr`
581
+ * shorthand for `{ field }`. `false` for an absent field (truthful — it isn't
582
+ * marked) and for a body address (a body is never a fill). Only an
583
+ * out-of-range `addr.card` throws.
581
584
  */
582
- install(addr: Addr, rt: RichText): void;
585
+ isFill(addr: Addr | string): boolean;
583
586
  /**
584
587
  * Replace this document's contents **in place** from a versioned storage
585
588
  * DTO string — the mutating twin of the static
@@ -594,10 +597,10 @@ export class Document {
594
597
  loadJson(json: string): void;
595
598
  /**
596
599
  * Build a fresh `Card` from a kind and a flat field map — the ergonomic
597
- * constructor for `pushCard` / `insertCard`. `fields` is an optional
600
+ * constructor for `insertCard`. `fields` is an optional
598
601
  * `Record<string, unknown>` (each entry becomes a card field, in
599
602
  * insertion order); `body` defaults to `""`. Kind validity is checked by
600
- * `pushCard` / `insertCard`, not here.
603
+ * `insertCard`, not here.
601
604
  */
602
605
  static makeCard(kind: string, fields?: Record<string, unknown>, body?: string): Card;
603
606
  /**
@@ -613,14 +616,6 @@ export class Document {
613
616
  * Throws on an invalid quill reference. Mirrors Python `Document(quill_ref)`.
614
617
  */
615
618
  constructor(quill_ref: string);
616
- /**
617
- * Append a card to the end of the card list. Accepts a `CardInput` — a card
618
- * read back (`cards` / `removeCard` / `quill.seedCard`), a
619
- * [`makeCard`](Document::make_card) result, or a bare `{ kind, body }`
620
- * (every returned `Card` is a valid `CardInput`). Throws if `card.kind` is
621
- * not a valid kind name.
622
- */
623
- pushCard(card: CardInput): void;
624
619
  /**
625
620
  * The canonical `$quill` reference grammar as author-facing text. Core is
626
621
  * the single source of truth: drive schema `describe` and validation
@@ -631,54 +626,32 @@ export class Document {
631
626
  static quillRefHint(): string;
632
627
  removeCard(index: number): Card | undefined;
633
628
  /**
634
- * Remove the `$ext` map from the composable card at `index` *entirely*,
635
- * returning the previous map or `undefined`. Throws if out of range.
636
- * Prefer `removeCardExtNamespace` to clear only one consumer's slot.
629
+ * Remove the `$ext` map on the card `addr` targets *entirely*, returning the
630
+ * previous map or `undefined` a blunt escape hatch that discards every
631
+ * namespace at once (prefer `removeExtNamespace`). `addr` is a card address
632
+ * (absent = main). Throws on a present `field` or an out-of-range card.
637
633
  */
638
- removeCardExt(index: number): Record<string, unknown> | undefined;
634
+ removeExt(addr?: CardAddr): Record<string, unknown> | undefined;
639
635
  /**
640
- * Remove `namespace` from the composable card's `$ext` map, returning the
641
- * value stored there or `undefined`; clears `$ext` entirely once empty.
642
- * The card-indexed twin of `removeExtNamespace`. Throws if out of range.
636
+ * Remove `$ext[ns]` on the card `addr` targets, returning its value or
637
+ * `undefined`; drops `$ext` once empty. `addr` is a card address (absent =
638
+ * main). Preserves sibling namespaces. Throws on a present `field` or an
639
+ * out-of-range card.
643
640
  */
644
- removeCardExtNamespace(index: number, namespace: string): any;
641
+ removeExtNamespace(addr: CardAddr, ns: string): any;
645
642
  /**
646
- * Remove a field on the card at `index`. Returns the removed value or
647
- * `undefined`. Throws if `index` is out of range or `name` is invalid.
643
+ * Remove a field at `addr`, returning the removed value or `undefined`. A
644
+ * bare string is `Addr` shorthand for `{ field }`. One `remove` verb serves
645
+ * every write lane. A body address throws; throws on an out-of-range card or
646
+ * a malformed name.
648
647
  */
649
- removeCardField(index: number, name: string): any;
650
- /**
651
- * Remove the `$ext` map from the main card *entirely*, returning the
652
- * previous map or `undefined`. This is a blunt escape hatch that discards
653
- * every namespace at once — prefer `removeExtNamespace` to clear only your
654
- * own slot while leaving sibling consumers' state intact.
655
- */
656
- removeExt(): Record<string, unknown> | undefined;
657
- /**
658
- * Remove `namespace` from the main card's `$ext` map, returning the value
659
- * stored there or `undefined`. This is the recommended way to clear `$ext`
660
- * state: sibling namespaces survive, and when the last namespace is removed
661
- * the `$ext` entry is dropped entirely (not left as `$ext: {}`).
662
- */
663
- removeExtNamespace(namespace: string): any;
664
- /**
665
- * Remove a payload field on the main card, returning the removed value or
666
- * `undefined`. Throws if `name` does not match `[A-Za-z_][A-Za-z0-9_]*`.
667
- */
668
- removeField(name: string): any;
648
+ removeField(addr: Addr | string): any;
669
649
  /**
670
650
  * Remove `cardKind` from the main card's `$seed` map, returning its
671
- * overlay or `undefined`; drops `$seed` entirely once empty. Sibling
672
- * kinds survive.
651
+ * overlay or `undefined`; drops `$seed` entirely once empty. Sibling kinds
652
+ * survive. `$seed` is main-only, so this takes no address.
673
653
  */
674
654
  removeSeedNamespace(card_kind: string): any;
675
- /**
676
- * **Deprecated** — alias for `revise({}, markdown)`, kept one release cycle.
677
- * Revise the main card's body from a markdown string (edit semantics: a
678
- * `diff_import` that rebases surviving anchors). Discards the text delta;
679
- * call [`revise`](Document::revise) to receive it.
680
- */
681
- replaceBody(body: string): void;
682
655
  /**
683
656
  * **Revise** the richtext value at `addr` from a markdown string — **edit
684
657
  * semantics**, the default write path, returning the text [`Delta`]. Imports
@@ -688,9 +661,9 @@ export class Document {
688
661
  * absent `addr.card` the main card; an absent field cold-imports from empty.
689
662
  *
690
663
  * Throws on an out-of-range card, a malformed field name, a present
691
- * non-corpus field value, or an over-nested markdown input.
664
+ * non-content field value, or an over-nested markdown input.
692
665
  */
693
- revise(addr: Addr, markdown: string): Delta;
666
+ revise(addr: Addr | string, markdown: string): Delta;
694
667
  /**
695
668
  * Read the `schema` version tag from a raw storage DTO string without a
696
669
  * full parse, or `undefined`. Returns unknown future versions as-is —
@@ -699,30 +672,13 @@ export class Document {
699
672
  */
700
673
  static schemaVersionOf(json: string): string | undefined;
701
674
  /**
702
- * Replace the `$ext` map on the composable card at `index`. Throws if out
703
- * of range or `value` is not a plain object. Named to mirror `setExt` on
704
- * the main card; `setCardExtNamespace` is the sibling-safe alternative.
675
+ * The main card's `$seed` overlay object for `kind` (the `$seed[kind]`
676
+ * entry), or `undefined` when absent. The cheap read that feeds
677
+ * `quill.seedCard(kind, overlay)` without serializing the whole main card
678
+ * via [`main`](Self::main) to fish out one key — and it keeps `seedCard`
679
+ * pure: the quill still never reads the document.
705
680
  */
706
- setCardExt(index: number, value: any): void;
707
- /**
708
- * Merge `value` into the composable card's `$ext` map under `namespace`,
709
- * preserving sibling namespaces. The card-indexed twin of `setExtNamespace`.
710
- * Throws if out of range or `value` cannot be serialized.
711
- */
712
- setCardExtNamespace(index: number, namespace: string, value: any): void;
713
- /**
714
- * Set a field on the card at `index` — the card-indexed twin of
715
- * [`setField`](Document::set_field). Stores the value opaquely.
716
- * Throws if `index` is out of range, `name` is reserved or invalid.
717
- */
718
- setCardField(index: number, name: string, value: any): void;
719
- /**
720
- * Batched twin of [`setCardField`](Document::set_card_field): set
721
- * several fields on the card at `index` atomically. Same all-or-nothing,
722
- * one-diagnostic-per-field contract as [`setFields`](Document::set_fields).
723
- * Throws if `index` is out of range.
724
- */
725
- setCardFields(index: number, fields: Record<string, unknown>): void;
681
+ seedOverlay(kind: string): Record<string, unknown> | undefined;
726
682
  /**
727
683
  * Replace the kind of the card at `index`. Payload and body are untouched;
728
684
  * schema-aware migration is the caller's responsibility.
@@ -730,50 +686,61 @@ export class Document {
730
686
  */
731
687
  setCardKind(index: number, new_kind: string): void;
732
688
  /**
733
- * Replace the opaque `$ext` map on the main card. `value` must be a plain
734
- * object; throws otherwise. `$ext` carries out-of-band consumer state and
735
- * never reaches the rendered output. Pass `{}` to record an explicit
736
- * empty `$ext`.
689
+ * Replace the QUILL reference string. Throws if `ref_str` is invalid.
737
690
  */
738
- setExt(value: any): void;
691
+ setQuillRef(ref_str: string): void;
739
692
  /**
740
- * Merge `value` into the main card's `$ext` map under `namespace`, creating
741
- * the map when absent and replacing any existing value at that key. Sibling
742
- * namespaces are preserved, so independent consumers (`$ext.editor`,
743
- * `$ext.agent`, …) don't clobber each other.
693
+ * Replace the opaque `$ext` map on the card `addr` targets (a card address,
694
+ * absent `card` = main). `value` must be a plain object. `$ext` carries
695
+ * out-of-band consumer state and never reaches the rendered output; pass
696
+ * `{}` for an explicit empty `$ext`. Quill-free and verbatim an opaque
697
+ * `store` verb. Throws on a present `field` or an out-of-range card.
744
698
  */
745
- setExtNamespace(namespace: string, value: any): void;
699
+ storeExt(addr: CardAddr, value: any): void;
746
700
  /**
747
- * Update a payload field on the main card. Clears any existing `!must_fill` marker.
748
- *
749
- * Throws if `name` does not match `[A-Za-z_][A-Za-z0-9_]*`.
701
+ * Merge `value` into `$ext[ns]` on the card `addr` targets, preserving
702
+ * sibling namespaces — the recommended `$ext` write. `addr` is a card
703
+ * address (absent = main). Quill-free and verbatim — an opaque `store` verb.
704
+ * Throws on a present `field` or an out-of-range card.
750
705
  */
751
- setField(name: string, value: any): void;
706
+ storeExtNamespace(addr: CardAddr, ns: string, value: any): void;
752
707
  /**
753
- * Set several main-card payload fields atomically from a plain object,
754
- * clearing any `!must_fill` marker on each key. Nothing is applied on
755
- * error; the thrown error's `diagnostics` array carries one entry per
756
- * offending field (`path` = field name), so externally-sourced names
757
- * (database columns, form keys) surface every violation in one pass.
758
- * Mirrors Python `set_fields`.
708
+ * Store a field verbatim at `addr` the opaque store (**store** = verbatim,
709
+ * coercion deferred to render; the typed write is
710
+ * [`commitField`](Document::commit_field)). A bare string is `Addr`
711
+ * shorthand for `{ field }`, so `doc.storeField("qty", 3)` reads as written;
712
+ * `{ card: 2, field: "qty" }` targets a composable card. Clears any
713
+ * `!must_fill` marker. A body address (no `field`) throws — a body is never
714
+ * opaque; write it with `revise` / `install` / `writer.setBody`. Throws on
715
+ * an out-of-range card or a malformed name.
759
716
  */
760
- setFields(fields: Record<string, unknown>): void;
717
+ storeField(addr: Addr | string, value: any): void;
761
718
  /**
762
- * Update a payload field on the main card and mark it as `!must_fill`.
763
- * Throws on invalid name (see [`setField`](Document::set_field)).
719
+ * Store several fields verbatim and atomically on the card `addr` targets
720
+ * the opaque store's batch. `addr` is a **card address** (`{ card }`, absent
721
+ * = main); a present `field` throws. The batch verb takes the address first
722
+ * and is never shape-overloaded, because `card` is a legal field name:
723
+ * `storeFields({}, fields)` is the main card, `storeFields({ card: 2 },
724
+ * fields)` a composable one — never ambiguous with "set field `card`".
725
+ * Nothing is applied on error; the thrown error's `diagnostics` carry one
726
+ * entry per offending field. Throws on an out-of-range card.
764
727
  */
765
- setFill(name: string, value: any): void;
728
+ storeFields(addr: CardAddr, fields: Record<string, unknown>): void;
766
729
  /**
767
- * Replace the QUILL reference string. Throws if `ref_str` is invalid.
730
+ * Store a field verbatim at `addr` and mark it `!must_fill` the opaque
731
+ * store's fill variant, card-capable (a bare string or `{ field }` for main,
732
+ * `{ card, field }` for a composable card). A body address throws. Same
733
+ * validation as [`storeField`](Document::store_field).
768
734
  */
769
- setQuillRef(ref_str: string): void;
735
+ storeFill(addr: Addr | string, value: any): void;
770
736
  /**
771
- * Merge a card-kind's seed `overlay` into the main card's `$seed` map
772
- * under `cardKind`, preserving sibling kinds. Sets the starting values
773
- * new cards of that kind spawn with. Throws if `overlay` cannot be
774
- * serialized or nests too deep.
737
+ * Merge a card-kind's seed `overlay` into the **main** card's `$seed` map
738
+ * under `cardKind`, preserving sibling kinds `$seed` lives on the main
739
+ * card by model, so this takes no address. Sets the starting values new
740
+ * cards of that kind spawn with. Quill-free and verbatim — an opaque `store`
741
+ * verb. Throws if `overlay` cannot be serialized or nests too deep.
775
742
  */
776
- setSeedNamespace(card_kind: string, overlay: any): void;
743
+ storeSeedNamespace(card_kind: string, overlay: any): void;
777
744
  /**
778
745
  * Serialize this document to a versioned storage DTO string.
779
746
  *
@@ -863,8 +830,8 @@ export class LiveSession {
863
830
  */
864
831
  fieldBoxes(field: string): FieldRegion[];
865
832
  /**
866
- * A corpus position → **caret rect** — the reverse of `positionAt`: given
867
- * a field and a USV offset into its `RichText`, return the box (in the
833
+ * A content position → **caret rect** — the reverse of `positionAt`: given
834
+ * a field and a USV offset into its `Content`, return the box (in the
868
835
  * same bottom-left PDF-point space as `FieldRegion.rect`) to draw a caret
869
836
  * at, its `span` collapsed to `[pos, pos]`; `undefined` when the field
870
837
  * places no tracked content or the offset maps to no drawn glyph.
@@ -893,16 +860,16 @@ export class LiveSession {
893
860
  */
894
861
  paint(ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, page: number, opts: PaintOptions | undefined): PaintResult;
895
862
  /**
896
- * A point → **corpus position** — the fine-grained click direction:
863
+ * A point → **content position** — the fine-grained click direction:
897
864
  * hit-test a point and get back the field *and* a USV offset into its
898
- * `RichText` (for placing a caret or mapping a selection into the content
865
+ * `Content` (for placing a caret or mapping a selection into the content
899
866
  * model), or `undefined` off all content ink. `x`/`y` are PDF points,
900
867
  * bottom-left origin — the same space as `fieldAt`. The offset is
901
868
  * cluster-exact and degrades to the containing segment's start on
902
869
  * origin-less ink (list markers, a code fence's interior). See
903
- * `CorpusHit`.
870
+ * `ContentHit`.
904
871
  */
905
- positionAt(page: number, x: number, y: number): CorpusHit | undefined;
872
+ positionAt(page: number, x: number, y: number): ContentHit | undefined;
906
873
  /**
907
874
  * Schema-field geometry for this compiled session — each content field's
908
875
  * **first placement** (one region per page it touches) plus widget and
@@ -954,9 +921,9 @@ export class Quill {
954
921
  * layering an optional per-kind seed `overlay` over the schema-example
955
922
  * base (`overlay › example › absent`). Returns `undefined` if `cardKind`
956
923
  * is not declared in this quill's schema, else a `Card` that feeds
957
- * straight into `Document.pushCard` / `insertCard`.
924
+ * straight into `Document.insertCard`.
958
925
  *
959
- * Pass `document.main.seed?.[cardKind]` as `overlay` so a card added to a
926
+ * Pass `document.seedOverlay(cardKind)` as `overlay` so a card added to a
960
927
  * template-derived document inherits its curated starting values; omit it
961
928
  * (or pass `undefined` / `null`) for the bare schema seed. `overlay` is a
962
929
  * plain object — this reads the document, it does not mutate it.
@@ -1062,19 +1029,19 @@ export class Quillmark {
1062
1029
  }
1063
1030
 
1064
1031
  /**
1065
- * Export a canonical `RichText` corpus to its markdown projection — the pure
1066
- * codec that replaces the eager `bodyMarkdown` / `fieldMarkdown` precomputes
1067
- * (`exportMarkdown(card.body)`). Throws if `rt` is not a canonical corpus.
1032
+ * Export a canonical `Content` content to its markdown projection — the pure
1033
+ * on-demand codec behind `exportMarkdown(card.body)`. Throws if `rt` is not a
1034
+ * canonical content.
1068
1035
  */
1069
- export function exportMarkdown(rt: RichText): string;
1036
+ export function exportMarkdown(rt: Content): string;
1070
1037
 
1071
1038
  /**
1072
- * Import a markdown string to a canonical `RichText` corpus — the pure,
1039
+ * Import a markdown string to a canonical `Content` content — the pure,
1073
1040
  * document-free codec. Pair with `install(addr, importMarkdown(md))` to spell
1074
1041
  * the cold (anchor-losing) write at the call site; prefer `revise` for edit
1075
1042
  * semantics. Throws on an over-nested input.
1076
1043
  */
1077
- export function importMarkdown(markdown: string): RichText;
1044
+ export function importMarkdown(markdown: string): Content;
1078
1045
 
1079
1046
  /**
1080
1047
  * Initialize the WASM module with panic hooks for better error messages
@@ -1082,7 +1049,7 @@ export function importMarkdown(markdown: string): RichText;
1082
1049
  export function init(): void;
1083
1050
 
1084
1051
  /**
1085
- * Map a base corpus position through a `delta` to its new position — the pure
1052
+ * Map a base content position through a `delta` to its new position — the pure
1086
1053
  * position-mapping codec an editor bridge composes to hold a caret stable
1087
1054
  * across a `revise`. `assoc` decides the side of a same-position insertion
1088
1055
  * (`"after"` moves past it). Throws on a malformed `delta`.
@@ -1090,10 +1057,10 @@ export function init(): void;
1090
1057
  export function mapPos(delta: Delta, pos: number, assoc: Assoc): number;
1091
1058
 
1092
1059
  /**
1093
- * Rebase `markdown` onto a `base` corpus — the pure, document-free twin of
1094
- * `revise`: cold-import + `diff_import`, returning the new `corpus` and the
1060
+ * Rebase `markdown` onto a `base` content — the pure, document-free twin of
1061
+ * `revise`: cold-import + `diff_import`, returning the new `content` and the
1095
1062
  * text `delta` (surviving anchors rebased). Use it to compute a revise without
1096
1063
  * a document in hand; `revise(addr, md)` fuses this with the store for
1097
- * atomicity. Throws on an over-nested markdown input or a non-corpus `base`.
1064
+ * atomicity. Throws on an over-nested markdown input or a non-content `base`.
1098
1065
  */
1099
- export function rebase(base: RichText, markdown: string): { corpus: RichText; delta: Delta };
1066
+ export function rebase(base: Content, markdown: string): { content: Content; delta: Delta };