@quillmark/wasm 0.92.1 → 0.94.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
@@ -2,23 +2,34 @@
2
2
  /* eslint-disable */
3
3
  export const memory: WebAssembly.Memory;
4
4
  export const __wbg_document_free: (a: number, b: number) => void;
5
+ export const __wbg_livesession_free: (a: number, b: number) => void;
5
6
  export const __wbg_quill_free: (a: number, b: number) => void;
6
7
  export const __wbg_quillmark_free: (a: number, b: number) => void;
7
- export const __wbg_rendersession_free: (a: number, b: number) => void;
8
+ export const document_addCard: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void;
9
+ export const document_applyChange: (a: number, b: number, c: number, d: number) => void;
8
10
  export const document_blueprintInstruction: (a: number, b: number, c: number) => void;
9
11
  export const document_cardCount: (a: number) => number;
10
12
  export const document_cards: (a: number, b: number) => void;
11
13
  export const document_clone: (a: number) => number;
14
+ export const document_commitCardField: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
15
+ export const document_commitCardFields: (a: number, b: number, c: number, d: number, e: number) => void;
16
+ export const document_commitField: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
17
+ export const document_commitFields: (a: number, b: number, c: number, d: number) => void;
12
18
  export const document_currentSchemaVersion: (a: number) => void;
13
19
  export const document_equals: (a: number, b: number) => number;
14
20
  export const document_formatDiagnostic: (a: number, b: number) => void;
15
21
  export const document_formatRules: (a: number) => void;
16
22
  export const document_fromJson: (a: number, b: number, c: number) => void;
17
23
  export const document_fromMarkdown: (a: number, b: number, c: number) => void;
24
+ export const document_get: (a: number, b: number, c: number, d: number) => void;
25
+ export const document_getMarkdown: (a: number, b: number, c: number, d: number) => void;
18
26
  export const document_insertCard: (a: number, b: number, c: number, d: number) => void;
27
+ export const document_install: (a: number, b: number, c: number, d: number) => void;
28
+ export const document_loadJson: (a: number, b: number, c: number, d: number) => void;
19
29
  export const document_main: (a: number, b: number) => void;
20
30
  export const document_makeCard: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
21
31
  export const document_moveCard: (a: number, b: number, c: number, d: number) => void;
32
+ export const document_new: (a: number, b: number, c: number) => void;
22
33
  export const document_pushCard: (a: number, b: number, c: number) => void;
23
34
  export const document_quillRef: (a: number, b: number) => void;
24
35
  export const document_quillRefHint: (a: number) => void;
@@ -30,24 +41,42 @@ export const document_removeExt: (a: number, b: number) => void;
30
41
  export const document_removeExtNamespace: (a: number, b: number, c: number, d: number) => void;
31
42
  export const document_removeField: (a: number, b: number, c: number, d: number) => void;
32
43
  export const document_removeSeedNamespace: (a: number, b: number, c: number, d: number) => void;
33
- export const document_replaceBody: (a: number, b: number, c: number) => void;
44
+ export const document_replaceBody: (a: number, b: number, c: number, d: number) => void;
45
+ export const document_revise: (a: number, b: number, c: number, d: number, e: number) => void;
34
46
  export const document_schemaVersionOf: (a: number, b: number, c: number) => void;
35
47
  export const document_setCardExt: (a: number, b: number, c: number, d: number) => void;
36
48
  export const document_setCardExtNamespace: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
49
+ export const document_setCardField: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
50
+ export const document_setCardFields: (a: number, b: number, c: number, d: number) => void;
37
51
  export const document_setCardKind: (a: number, b: number, c: number, d: number, e: number) => void;
38
52
  export const document_setExt: (a: number, b: number, c: number) => void;
39
53
  export const document_setExtNamespace: (a: number, b: number, c: number, d: number, e: number) => void;
40
54
  export const document_setField: (a: number, b: number, c: number, d: number, e: number) => void;
55
+ export const document_setFields: (a: number, b: number, c: number) => void;
41
56
  export const document_setFill: (a: number, b: number, c: number, d: number, e: number) => void;
42
57
  export const document_setQuillRef: (a: number, b: number, c: number, d: number) => void;
43
58
  export const document_setSeedNamespace: (a: number, b: number, c: number, d: number, e: number) => void;
44
59
  export const document_toJson: (a: number, b: number) => void;
45
60
  export const document_toMarkdown: (a: number, b: number) => void;
46
61
  export const document_tryFromJson: (a: number, b: number) => number;
47
- export const document_updateCardBody: (a: number, b: number, c: number, d: number, e: number) => void;
48
- export const document_updateCardField: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
49
62
  export const document_warnings: (a: number, b: number) => void;
63
+ export const exportMarkdown: (a: number, b: number) => void;
64
+ export const importMarkdown: (a: number, b: number, c: number) => void;
50
65
  export const init: () => void;
66
+ export const livesession_apply: (a: number, b: number, c: number) => void;
67
+ export const livesession_backendId: (a: number, b: number) => void;
68
+ export const livesession_fieldAt: (a: number, b: number, c: number, d: number, e: number) => void;
69
+ export const livesession_fieldBoxes: (a: number, b: number, c: number, d: number) => void;
70
+ export const livesession_locate: (a: number, b: number, c: number, d: number) => number;
71
+ export const livesession_pageCount: (a: number) => number;
72
+ export const livesession_pageSize: (a: number, b: number, c: number) => void;
73
+ export const livesession_paint: (a: number, b: number, c: number, d: number, e: number) => void;
74
+ export const livesession_positionAt: (a: number, b: number, c: number, d: number) => number;
75
+ export const livesession_regions: (a: number, b: number) => void;
76
+ export const livesession_render: (a: number, b: number, c: number) => void;
77
+ export const livesession_supportsCanvas: (a: number) => number;
78
+ export const livesession_warnings: (a: number, b: number) => void;
79
+ export const mapPos: (a: number, b: number, c: number, d: number) => void;
51
80
  export const quill_backendId: (a: number, b: number) => void;
52
81
  export const quill_blueprint: (a: number, b: number) => void;
53
82
  export const quill_fromTree: (a: number, b: number) => void;
@@ -63,13 +92,7 @@ export const quillmark_open: (a: number, b: number, c: number, d: number) => voi
63
92
  export const quillmark_render: (a: number, b: number, c: number, d: number, e: number) => void;
64
93
  export const quillmark_supportedFormats: (a: number, b: number, c: number) => void;
65
94
  export const quillmark_supportsCanvas: (a: number, b: number) => number;
66
- export const rendersession_backendId: (a: number, b: number) => void;
67
- export const rendersession_pageCount: (a: number) => number;
68
- export const rendersession_pageSize: (a: number, b: number, c: number) => void;
69
- export const rendersession_paint: (a: number, b: number, c: number, d: number, e: number) => void;
70
- export const rendersession_render: (a: number, b: number, c: number) => void;
71
- export const rendersession_supportsCanvas: (a: number) => number;
72
- export const rendersession_warnings: (a: number, b: number) => void;
95
+ export const rebase: (a: number, b: number, c: number, d: number) => void;
73
96
  export const __wbindgen_export: (a: number, b: number) => number;
74
97
  export const __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
75
98
  export const __wbindgen_export3: (a: number) => void;
package/core/wasm.d.ts CHANGED
@@ -24,10 +24,11 @@ export type PayloadItem =
24
24
  | { type: "comment"; text: string; inline?: boolean };
25
25
 
26
26
  /**
27
- * A single card block. The one shape exchanged in both directions: returned by
28
- * `Document.main` / `Document.cards` / `Document.removeCard` / `Quill.seedCard`,
29
- * and accepted by `Document.pushCard` / `Document.insertCard`. Build a fresh
30
- * one with `Document.makeCard`.
27
+ * A single card block, as read back from a document: returned by
28
+ * `Document.main` / `Document.cards` / `Document.removeCard` / `Quill.seedCard`
29
+ * / `Document.makeCard`. To feed a card *into* a document use `CardInput`
30
+ * (which `pushCard` / `insertCard` accept); every `Card` is a valid `CardInput`,
31
+ * so a card read from one document pushes straight into another.
31
32
  *
32
33
  * `$` system entries are hoisted to named fields: `kind` (the `$kind`, empty
33
34
  * string when none), optional `quill` (the `$quill` `name@version`, main card
@@ -42,15 +43,149 @@ export interface Card {
42
43
  ext?: Record<string, unknown>;
43
44
  seed?: Record<string, unknown>;
44
45
  payloadItems: PayloadItem[];
45
- body: string;
46
+ /**
47
+ * The card body as canonical `RichText` — the source-of-truth content model.
48
+ * Always this corpus shape on read, never a markdown string. For the markdown
49
+ * projection call the codec `exportMarkdown(card.body)`. Write a body back
50
+ * with `doc.install(addr, rt)` / `doc.revise(addr, md)`, or via `CardInput.body`.
51
+ */
52
+ body: RichText;
46
53
  }
47
54
 
55
+ /**
56
+ * A card written *into* a document — the input twin of `Card`, accepted by
57
+ * `Document.pushCard` / `Document.insertCard`. Like `Card` but `body` also
58
+ * takes a markdown `string` (imported to the corpus, so a markdown / LLM writer
59
+ * needn't build the `RichText` shape), and every field but `kind` is optional —
60
+ * an absent field defaults (no payload items, an empty body). Write one inline
61
+ * (`{ kind, body }`) or build it with `Document.makeCard`.
62
+ */
63
+ export interface CardInput {
64
+ kind: string;
65
+ quill?: string;
66
+ id?: string;
67
+ ext?: Record<string, unknown>;
68
+ seed?: Record<string, unknown>;
69
+ payloadItems?: PayloadItem[];
70
+ body?: RichText | string;
71
+ }
48
72
 
73
+ /**
74
+ * Canonical richtext corpus — the content model for a card body (and richtext
75
+ * fields). One text sequence over a single coordinate space (Unicode scalar
76
+ * values): `text` plus line attributes, anchored `marks`, and embedded
77
+ * `islands`. Every edit is a splice; markdown is a projection, not the model.
78
+ * Mirrors `quillmark_richtext::serial`'s canonical JSON encoding.
79
+ */
80
+ export interface RichText {
81
+ text: string;
82
+ lines: RichTextLine[];
83
+ marks: RichTextMark[];
84
+ islands: RichTextIsland[];
85
+ }
86
+
87
+ /** One `\n`-separated segment of `RichText.text`, in order. */
88
+ export type RichTextLine = {
89
+ containers: RichTextContainer[];
90
+ /** A within-block hard line break rather than a new block. Omitted (false) in the common case. */
91
+ continues?: boolean;
92
+ } & (
93
+ | { kind: "para" }
94
+ | { kind: "heading"; level: number }
95
+ | { kind: "code"; lang?: string }
96
+ | { kind: "island" }
97
+ | { kind: "rule" }
98
+ );
99
+
100
+ /** An ancestor block a line nests inside, outermost first. */
101
+ export type RichTextContainer =
102
+ | { container: "list_item"; ordered: boolean; start: number; ordinal: number }
103
+ | { container: "quote" };
104
+
105
+ /** A mark over char range `[start, end)` into `RichText.text`. */
106
+ export type RichTextMark = { start: number; end: number } & (
107
+ | { type: "strong" | "emph" | "underline" | "strike" | "code" }
108
+ | { type: "link"; url: string }
109
+ | { type: "anchor"; id: string }
110
+ | { type: string; attrs: unknown }
111
+ );
112
+
113
+ /** A structured object (table, figure, …) occupying one island slot in `RichText.text`. */
114
+ export interface RichTextIsland {
115
+ id: string;
116
+ type: string;
117
+ props: unknown;
118
+ /** How faithfully the markdown projection can carry this island. */
119
+ loss: "lossless" | "degraded" | "unrepresentable";
120
+ }
49
121
 
50
- /** UI layout hints for a single field. */
122
+ /**
123
+ * A richtext write address. An absent `field` targets the card body; an absent
124
+ * `card` targets the main card. `{}` is the main-card body; `{ card: 2 }` the
125
+ * body of the composable card at index 2; `{ field: "intro" }` the main card's
126
+ * `intro` richtext field; `{ card: 2, field: "intro" }` a card field.
127
+ */
128
+ export interface Addr {
129
+ card?: number;
130
+ field?: string;
131
+ }
132
+
133
+ /**
134
+ * A text-splice change set over the USV corpus (CodeMirror `ChangeSet`
135
+ * semantics) — plain, structured-clone-able data. Returned by `revise` and by
136
+ * the `rebase` codec; map a stored position through it with `mapPos`.
137
+ */
138
+ export interface Delta {
139
+ ops: ({ retain: number } | { insert: string } | { delete: number })[];
140
+ }
141
+
142
+ /** Which side of a same-position insertion `mapPos` lands a point on. */
143
+ export type Assoc = "before" | "after";
144
+
145
+ /**
146
+ * A mark edit in post-text-delta coordinates. `add` / `remove` carry the
147
+ * `RichTextMark` vocabulary (`{ type, … }`); `removeAnchor` drops one identity
148
+ * anchor by id.
149
+ */
150
+ export type MarkOp =
151
+ | ({ op: "add" | "remove"; start: number; end: number } & (
152
+ | { type: "strong" | "emph" | "underline" | "strike" | "code" }
153
+ | { type: "link"; url: string }
154
+ | { type: "anchor"; id: string }
155
+ | { type: string; attrs: unknown }
156
+ ))
157
+ | { op: "removeAnchor"; id: string };
158
+
159
+ /** A line/block edit. `split`/`join` splice `\n`; `setKind`/`setContainers` touch metadata. */
160
+ export type LineOp =
161
+ | { op: "split"; at: number }
162
+ | { op: "join"; line: number }
163
+ | ({ op: "setKind"; line: number } & (
164
+ | { kind: "para" | "island" | "rule" }
165
+ | { kind: "heading"; level: number }
166
+ | { kind: "code"; lang?: string }
167
+ ))
168
+ | { op: "setContainers"; line: number; containers: RichTextContainer[] };
169
+
170
+ /**
171
+ * A committed corpus edit bundle for `applyChange`: a text `delta` (default no
172
+ * text change), then `lineOps`, then `markOps` (mark ranges are in post-delta
173
+ * coordinates). Every field is optional.
174
+ */
175
+ export interface ChangeBundle {
176
+ delta?: Delta;
177
+ lineOps?: LineOp[];
178
+ markOps?: MarkOp[];
179
+ }
180
+
181
+
182
+
183
+ /** UI layout hints for a single field. Field display order is not a hint:
184
+ * key order in the schema's `fields`/`properties` objects is declaration
185
+ * order, the ordering contract. */
51
186
  export interface QuillFieldUi {
187
+ title?: string;
52
188
  group?: string;
53
- order?: number;
54
189
  compact?: boolean;
55
190
  multiline?: boolean;
56
191
  }
@@ -73,20 +208,28 @@ export interface QuillCardBody {
73
208
  * A field's *cell* is determined by `default`: a field with a `default`
74
209
  * is **Endorsed** (the rendered value is shippable as-is), while a field
75
210
  * without a `default` is **Unendorsed** (the blueprint carries a
76
- * `<must-fill>` sentinel and validation reports
77
- * `validation::field_absent` if the field is absent at validate
78
- * time — a non-fatal signal, since the render path zero-fills an absent
79
- * field). There is no separate `required` axis.
211
+ * `!must_fill` marker; a marker left in the document yields the non-fatal
212
+ * `validation::must_fill` warning from validate, and the render path
213
+ * zero-fills the field). There is no separate `required` axis.
80
214
  */
81
215
  export interface QuillFieldSchema {
82
- type: "string" | "number" | "integer" | "boolean" | "array" | "object" | "datetime" | "markdown";
216
+ type: "string" | "number" | "integer" | "boolean" | "array" | "object" | "datetime" | "richtext" | "plaintext" | "enum";
83
217
  description?: string;
84
218
  default?: unknown;
85
219
  example?: unknown;
220
+ /** Closed value domain. On `type: "enum"` declared as `values`; the
221
+ * deprecated `enum` modifier on `type: "string"` is accepted for one
222
+ * release. Both round-trip through this field. */
86
223
  enum?: string[];
224
+ /** Required on `type: "enum"`: the closed set of allowed string values. */
225
+ values?: string[];
87
226
  ui?: QuillFieldUi;
88
227
  properties?: Record<string, QuillFieldSchema>;
89
228
  items?: QuillFieldSchema;
229
+ /** Present (and `true`) on a `richtext` or `plaintext` field declared
230
+ * `inline` — the single-paragraph, container-free, island-free constraint.
231
+ * Core serializes `inline: true` into the schema JSON; absent otherwise. */
232
+ inline?: boolean;
90
233
  }
91
234
 
92
235
  /** Schema entry for the main card or a named card kind. */
@@ -141,16 +284,38 @@ export interface Location {
141
284
  column: number;
142
285
  }
143
286
 
144
- export type Severity = "error" | "warning" | "note";
287
+ export type Severity = "error" | "warning";
145
288
 
146
289
 
147
290
  /**
148
291
  * Typed in-memory Quillmark document.
149
292
  */
150
293
  export class Document {
151
- private constructor();
152
294
  free(): void;
153
295
  [Symbol.dispose](): void;
296
+ /**
297
+ * Build a composable card of `kind`, typed-commit `fields` onto it, set its
298
+ * body from optional markdown, and append it — the ABI under
299
+ * `writer.addCard`. Fuses `makeCard` + typed commit + `pushCard`
300
+ * transactionally: the card is committed in full before it joins the
301
+ * document, so a rejected field (or an invalid kind or body) leaves the
302
+ * document untouched. Field errors throw the same per-field diagnostic
303
+ * bundle as [`commitFields`](Self::commit_fields), including an
304
+ * `[EditError::UnknownField]` per undeclared name; an invalid kind or body
305
+ * throws a single-entry bundle keyed `$kind` / `$body`.
306
+ */
307
+ addCard(quill: Quill, kind: string, fields?: Record<string, unknown>, body?: string): void;
308
+ /**
309
+ * **Apply** a committed corpus edit `bundle` (`{ delta?, lineOps?, markOps? }`)
310
+ * at `addr` — the editor splice: text delta first, then line ops, then mark
311
+ * ops (mark ranges in post-delta coordinates), each all-or-nothing. An absent
312
+ * `addr.field` targets the body, an absent `addr.card` the main card.
313
+ *
314
+ * Throws on an out-of-range card, a field that is not richtext, a malformed
315
+ * bundle, or an op that applies out of bounds (the value is unchanged on a
316
+ * failed apply).
317
+ */
318
+ applyChange(addr: Addr, bundle: ChangeBundle): void;
154
319
  /**
155
320
  * Authoring-ergonomics header introducing a blueprint to an LLM/MCP
156
321
  * consumer for the given `quillName`. Re-exposes core's canonical text for
@@ -159,6 +324,60 @@ export class Document {
159
324
  */
160
325
  static blueprintInstruction(quill_name: string): string;
161
326
  clone(): Document;
327
+ /**
328
+ * Typed field write on the composable card at `index` — the card-indexed
329
+ * twin of [`commitField`](Document::commit_field). Resolves the field's
330
+ * type from the card's `$kind` schema in `quill` and strict-commits it.
331
+ *
332
+ * Throws `[EditError::IndexOutOfRange]` when `index` is out of range, and
333
+ * the same typed-mismatch / name errors as `commitField` — including
334
+ * `[EditError::UnknownField]` for a field the card-kind schema does not
335
+ * declare (an unknown `$kind` has no schema, so every field is undeclared).
336
+ */
337
+ commitCardField(quill: Quill, index: number, name: string, value: any): void;
338
+ /**
339
+ * Batched twin of [`commitCardField`](Document::commit_card_field):
340
+ * typed-commit several fields on the card at `index` atomically, resolving
341
+ * each field's type from the card's `$kind` schema in `quill`. All-or-nothing
342
+ * with the same per-field-diagnostic contract as
343
+ * [`commitFields`](Document::commit_fields), including an
344
+ * `[EditError::UnknownField]` diagnostic per undeclared name. Throws
345
+ * `[EditError::IndexOutOfRange]` when `index` is out of range.
346
+ */
347
+ commitCardFields(quill: Quill, index: number, fields: Record<string, unknown>): void;
348
+ /**
349
+ * Typed field write on the main card, resolving the field's schema `type`
350
+ * from `quill` — the one write verb for **every** field type (richtext,
351
+ * scalar, array, object). The schema carries the `inline` constraint, so no
352
+ * type token or flag is passed. A richtext-typed field stores the canonical
353
+ * corpus, so identity marks (anchors, island ids) and corpus-only marks
354
+ * (e.g. `underline`) live on it and survive compiles and the storage DTO.
355
+ * Values use the encoding the seam already speaks: a corpus object
356
+ * or markdown string for richtext, a scalar/array/object otherwise.
357
+ *
358
+ * A field declared in the schema is strict-committed — a mismatch throws
359
+ * now, not at render. A name the schema does not declare throws
360
+ * `[EditError::UnknownField]` rather than falling to the opaque store: on
361
+ * the typed path it is a typo. Use [`setField`](Document::set_field) when
362
+ * opaque storage is the intent. Also throws `[EditError::FieldConform]` /
363
+ * `[EditError::FieldRichtextDecode]` / `[EditError::FieldRichtextNotInline]`
364
+ * on a typed mismatch and `[EditError::InvalidFieldName]` on a malformed
365
+ * name.
366
+ *
367
+ * The `quill` handle is passed per call because a `Document` carries only a
368
+ * `$quill` reference, not the resolved schema.
369
+ */
370
+ commitField(quill: Quill, name: string, value: any): void;
371
+ /**
372
+ * Batched twin of [`commitField`](Document::commit_field): typed-commit
373
+ * several main-card fields atomically, resolving each field's schema `type`
374
+ * from `quill`. All-or-nothing with the same per-field-diagnostic error
375
+ * contract as [`setFields`](Document::set_fields) — nothing is applied on
376
+ * error and the thrown error's `diagnostics` carry one entry per offending
377
+ * field, including an `[EditError::UnknownField]` for any name the schema
378
+ * does not declare, so a whole-form submit sees every typo in one pass.
379
+ */
380
+ commitFields(quill: Quill, fields: Record<string, unknown>): void;
162
381
  /**
163
382
  * Schema version this build writes via [`toJson`](Document::to_json).
164
383
  * Tracks the `Document` model version (not the running crate version):
@@ -197,11 +416,53 @@ export class Document {
197
416
  * Parse markdown into a typed Document. Throws on parse errors.
198
417
  */
199
418
  static fromMarkdown(markdown: string): Document;
419
+ /**
420
+ * Read a main-card field's stored value — the raw payload value (a corpus
421
+ * object for a richtext field, a scalar/array/object otherwise), or
422
+ * `undefined` when the field is absent. The quill-free read: reads need no
423
+ * schema, so they live on `Document`, not the typed writer. For the markdown
424
+ * projection of a richtext value use [`getMarkdown`](Self::get_markdown).
425
+ */
426
+ get(name: string): any;
427
+ /**
428
+ * The markdown projection of a main-card field (`name` given) or the main
429
+ * body (`name` omitted) — the on-demand, lossy export (corpus-only marks do
430
+ * not survive markdown), returning `""` for an absent field. Re-coins,
431
+ * lazily and by name, the projection the eager `fieldMarkdown` /
432
+ * `bodyMarkdown` getters dropped in #925; call it only when markdown is what
433
+ * you need out.
434
+ */
435
+ getMarkdown(name?: string): string;
200
436
  /**
201
437
  * Insert a card at `index` (must be in `0..=cards.length`). Accepts a
202
- * `Card` (see [`pushCard`](Self::push_card)).
438
+ * `CardInput` (see [`pushCard`](Self::push_card)).
439
+ */
440
+ insertCard(index: number, card: CardInput): void;
441
+ /**
442
+ * **Install** a richtext value at `addr` — **value semantics**, corpus only.
443
+ * Stores exactly `rt` (a canonical `RichText` corpus object); the identity
444
+ * anchors of any previous value are gone. An absent `addr.field` targets the
445
+ * body, an absent `addr.card` the main card. For "here's new markdown," use
446
+ * [`revise`](Document::revise); the cold-import path is spelled at the call
447
+ * site as `install(addr, importMarkdown(md))`, so anchor loss is visible in
448
+ * source.
449
+ *
450
+ * Throws on an out-of-range card, a malformed field name, or an `rt` that is
451
+ * not a canonical corpus object.
203
452
  */
204
- insertCard(index: number, card: Card): void;
453
+ install(addr: Addr, rt: RichText): void;
454
+ /**
455
+ * Replace this document's contents **in place** from a versioned storage
456
+ * DTO string — the mutating twin of the static
457
+ * [`fromJson`](Document::from_json) constructor. Parse-time `warnings` are
458
+ * cleared. Throws (leaving the document unchanged) on an invalid DTO.
459
+ *
460
+ * The cross-WASM-memory `Document` bridge: mutate a document on a
461
+ * backend-memory clone, then write the mutated state back into the caller's
462
+ * canonical document with this — the one way to update a live handle across
463
+ * the linear-memory seam without the caller re-binding its variable.
464
+ */
465
+ loadJson(json: string): void;
205
466
  /**
206
467
  * Build a fresh `Card` from a kind and a flat field map — the ergonomic
207
468
  * constructor for `pushCard` / `insertCard`. `fields` is an optional
@@ -215,12 +476,22 @@ export class Document {
215
476
  */
216
477
  moveCard(from: number, to: number): void;
217
478
  /**
218
- * Append a card to the end of the card list. Accepts a `Card` (the shape
219
- * returned by `cards` / `removeCard` / `quill.seedCard`); build a fresh
220
- * one with [`Document.makeCard`](Document::make_card). Throws if
221
- * `card.kind` is not a valid kind name.
479
+ * `new Document(quillRef)` a blank document: a main card carrying only
480
+ * `$quill`, an empty body, and no composable cards. The programmatic
481
+ * blank canvas: absent fields resolve at render time (`default`, else
482
+ * type-empty zero), so nothing the caller did not set reaches the
483
+ * output. For an example-filled starter use `Quill.seedDocument()`.
484
+ * Throws on an invalid quill reference. Mirrors Python `Document(quill_ref)`.
485
+ */
486
+ constructor(quill_ref: string);
487
+ /**
488
+ * Append a card to the end of the card list. Accepts a `CardInput` — a card
489
+ * read back (`cards` / `removeCard` / `quill.seedCard`), a
490
+ * [`makeCard`](Document::make_card) result, or a bare `{ kind, body }`
491
+ * (every returned `Card` is a valid `CardInput`). Throws if `card.kind` is
492
+ * not a valid kind name.
222
493
  */
223
- pushCard(card: Card): void;
494
+ pushCard(card: CardInput): void;
224
495
  /**
225
496
  * The canonical `$quill` reference grammar as author-facing text. Core is
226
497
  * the single source of truth: drive schema `describe` and validation
@@ -272,7 +543,25 @@ export class Document {
272
543
  * kinds survive.
273
544
  */
274
545
  removeSeedNamespace(card_kind: string): any;
546
+ /**
547
+ * **Deprecated** — alias for `revise({}, markdown)`, kept one release cycle.
548
+ * Revise the main card's body from a markdown string (edit semantics: a
549
+ * `diff_import` that rebases surviving anchors). Discards the text delta;
550
+ * call [`revise`](Document::revise) to receive it.
551
+ */
275
552
  replaceBody(body: string): void;
553
+ /**
554
+ * **Revise** the richtext value at `addr` from a markdown string — **edit
555
+ * semantics**, the default write path, returning the text [`Delta`]. Imports
556
+ * the markdown, diffs it against the current value, rebases surviving
557
+ * identity anchors, and returns the change an editor bridge maps its own
558
+ * positions through (`mapPos`). An absent `addr.field` targets the body, an
559
+ * absent `addr.card` the main card; an absent field cold-imports from empty.
560
+ *
561
+ * Throws on an out-of-range card, a malformed field name, a present
562
+ * non-corpus field value, or an over-nested markdown input.
563
+ */
564
+ revise(addr: Addr, markdown: string): Delta;
276
565
  /**
277
566
  * Read the `schema` version tag from a raw storage DTO string without a
278
567
  * full parse, or `undefined`. Returns unknown future versions as-is —
@@ -292,6 +581,19 @@ export class Document {
292
581
  * Throws if out of range or `value` cannot be serialized.
293
582
  */
294
583
  setCardExtNamespace(index: number, namespace: string, value: any): void;
584
+ /**
585
+ * Set a field on the card at `index` — the card-indexed twin of
586
+ * [`setField`](Document::set_field). Stores the value opaquely.
587
+ * Throws if `index` is out of range, `name` is reserved or invalid.
588
+ */
589
+ setCardField(index: number, name: string, value: any): void;
590
+ /**
591
+ * Batched twin of [`setCardField`](Document::set_card_field): set
592
+ * several fields on the card at `index` atomically. Same all-or-nothing,
593
+ * one-diagnostic-per-field contract as [`setFields`](Document::set_fields).
594
+ * Throws if `index` is out of range.
595
+ */
596
+ setCardFields(index: number, fields: Record<string, unknown>): void;
295
597
  /**
296
598
  * Replace the kind of the card at `index`. Payload and body are untouched;
297
599
  * schema-aware migration is the caller's responsibility.
@@ -318,6 +620,15 @@ export class Document {
318
620
  * Throws if `name` does not match `[A-Za-z_][A-Za-z0-9_]*`.
319
621
  */
320
622
  setField(name: string, value: any): void;
623
+ /**
624
+ * Set several main-card payload fields atomically from a plain object,
625
+ * clearing any `!must_fill` marker on each key. Nothing is applied on
626
+ * error; the thrown error's `diagnostics` array carries one entry per
627
+ * offending field (`path` = field name), so externally-sourced names
628
+ * (database columns, form keys) surface every violation in one pass.
629
+ * Mirrors Python `set_fields`.
630
+ */
631
+ setFields(fields: Record<string, unknown>): void;
321
632
  /**
322
633
  * Update a payload field on the main card and mark it as `!must_fill`.
323
634
  * Throws on invalid name (see [`setField`](Document::set_field)).
@@ -358,15 +669,6 @@ export class Document {
358
669
  * genuinely malformed markdown.
359
670
  */
360
671
  static tryFromJson(json: string): Document | undefined;
361
- /**
362
- * Replace the body of the card at `index`. Throws if out of range.
363
- */
364
- updateCardBody(index: number, body: string): void;
365
- /**
366
- * Update a field on the card at `index`.
367
- * Throws if `index` is out of range, `name` is reserved or invalid.
368
- */
369
- updateCardField(index: number, name: string, value: any): void;
370
672
  /**
371
673
  * Number of composable cards (excludes the main card). O(1).
372
674
  */
@@ -443,10 +745,10 @@ export class Quill {
443
745
  *
444
746
  * Forwards the canonical `validation::*` diagnostics — same `code`,
445
747
  * `path`, and `hint` the engine emits — including the non-fatal
446
- * `validation::field_absent` completeness signal that `render` demotes.
447
- * Field values, defaults, and order are not part of this surface: read
448
- * them from the `Document` payload and `Quill.schema` (fields carry
449
- * `ui.order`).
748
+ * `validation::must_fill` warning for each `!must_fill` marker left in
749
+ * the document. Field values, defaults, and order are not part of this
750
+ * surface: read them from the `Document` payload and `Quill.schema`
751
+ * (schema key order is display order).
450
752
  */
451
753
  validate(doc: Document): Diagnostic[];
452
754
  /**
@@ -465,14 +767,47 @@ export class Quill {
465
767
  readonly metadata: QuillMetadata;
466
768
  /**
467
769
  * Document schema for the quill: the user-fillable fields plus their
468
- * `ui` hints (group / order / showWhen). The single field-metadata
469
- * surface — drives form editors and LLM/MCP consumers alike. Returns the
470
- * `QuillSchema` shape.
770
+ * `ui` hints (title / group / compact / multiline). The single
771
+ * field-metadata surface — drives form editors and LLM/MCP consumers
772
+ * alike. Key order in `fields`/`properties` is declaration order — the
773
+ * ordering contract. Returns the `QuillSchema` shape.
471
774
  */
472
775
  readonly schema: QuillSchema;
473
776
  }
474
777
 
778
+ /**
779
+ * Export a canonical `RichText` corpus to its markdown projection — the pure
780
+ * codec that replaces the eager `bodyMarkdown` / `fieldMarkdown` precomputes
781
+ * (`exportMarkdown(card.body)`). Throws if `rt` is not a canonical corpus.
782
+ */
783
+ export function exportMarkdown(rt: RichText): string;
784
+
785
+ /**
786
+ * Import a markdown string to a canonical `RichText` corpus — the pure,
787
+ * document-free codec. Pair with `install(addr, importMarkdown(md))` to spell
788
+ * the cold (anchor-losing) write at the call site; prefer `revise` for edit
789
+ * semantics. Throws on an over-nested input.
790
+ */
791
+ export function importMarkdown(markdown: string): RichText;
792
+
475
793
  /**
476
794
  * Initialize the WASM module with panic hooks for better error messages
477
795
  */
478
796
  export function init(): void;
797
+
798
+ /**
799
+ * Map a base corpus position through a `delta` to its new position — the pure
800
+ * position-mapping codec an editor bridge composes to hold a caret stable
801
+ * across a `revise`. `assoc` decides the side of a same-position insertion
802
+ * (`"after"` moves past it). Throws on a malformed `delta`.
803
+ */
804
+ export function mapPos(delta: Delta, pos: number, assoc: Assoc): number;
805
+
806
+ /**
807
+ * Rebase `markdown` onto a `base` corpus — the pure, document-free twin of
808
+ * `revise`: cold-import + `diff_import`, returning the new `corpus` and the
809
+ * text `delta` (surviving anchors rebased). Use it to compute a revise without
810
+ * a document in hand; `revise(addr, md)` fuses this with the store for
811
+ * atomicity. Throws on an over-nested markdown input or a non-corpus `base`.
812
+ */
813
+ export function rebase(base: RichText, markdown: string): { corpus: RichText; delta: Delta };
package/core/wasm.js CHANGED
@@ -5,5 +5,5 @@ import { __wbg_set_wasm } from "./wasm_bg.js";
5
5
  __wbg_set_wasm(wasm);
6
6
  wasm.__wbindgen_start();
7
7
  export {
8
- Document, Quill, init
8
+ Document, Quill, exportMarkdown, importMarkdown, init, mapPos, rebase
9
9
  } from "./wasm_bg.js";