@quillmark/quiver 0.12.0 → 0.15.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.
package/README.md CHANGED
@@ -29,6 +29,24 @@ This keeps the author flow to a single command (`npm publish` or `git tag`)
29
29
  and puts the deployment-topology decision where it belongs: with the
30
30
  consumer.
31
31
 
32
+ ## The render model
33
+
34
+ `@quillmark/quiver` produces quills; `@quillmark/wasm` renders them.
35
+
36
+ - `quiver.getQuill(ref)` returns a core `Quill` — engine-free, portable data,
37
+ good for schema inspection, validation, blueprint access, and seeding. It is
38
+ the **only** way to obtain a quill from a quiver.
39
+ - `const engine = new Engine()` (from the `@quillmark/wasm` root) renders it:
40
+ `await engine.render(quill, doc, opts?)`. The Engine routes on
41
+ `quill.backendId`, lazily loads that backend, clones the quill and document
42
+ into the backend's WASM memory, renders, and frees the clones — so a core
43
+ `Quill` passes straight to `engine.render` with no boundary-crossing step.
44
+
45
+ `Engine.render`, `open`, `supportedFormats`, and `supportsCanvas` are all
46
+ **async** — always `await` them. The canonical `Quill`/`Document`/`Engine`
47
+ types are not re-exported from `@quillmark/quiver`; import them straight from
48
+ the `@quillmark/wasm` peer dependency, which is the single source of truth.
49
+
32
50
  ## Authoring a quiver
33
51
 
34
52
  Lay out the source per the spec, then publish to npm (or push a git tag):
@@ -50,6 +68,14 @@ consumer's build. The harness uses `node:test` (built into Node 18+); no extra
50
68
  test-runner dependency required. If you prefer vitest/jest/mocha, write a
51
69
  12-line loop against the main API instead.
52
70
 
71
+ ```ts
72
+ // quiver.test.ts — run with: node --test
73
+ import { Engine } from "@quillmark/wasm";
74
+ import { runQuiverTests } from "@quillmark/quiver/testing";
75
+
76
+ runQuiverTests(import.meta.url, new Engine());
77
+ ```
78
+
53
79
  ## Manual validation (rendering samples)
54
80
 
55
81
  The CI harness proves every quill _compiles_; it does not produce output a
@@ -58,19 +84,19 @@ human can look at. To eyeball real renders, run the
58
84
 
59
85
  ```ts
60
86
  // scripts/preview.ts — run with: node --experimental-strip-types scripts/preview.ts
61
- import { Quillmark, Document } from "@quillmark/wasm";
87
+ import { Engine } from "@quillmark/wasm";
62
88
  import { renderQuiverSamples } from "@quillmark/quiver/preview";
63
89
 
64
90
  await renderQuiverSamples(import.meta.url, {
65
- engine: new Quillmark(),
66
- Document,
91
+ engine: new Engine(),
67
92
  });
68
93
  // → writes ./preview/<name>@<version>.<fmt> + index.html
69
94
  ```
70
95
 
71
- It renders every quill's illustrative example document (`quill.example` — a
72
- fully filled-out, always-renderable sample; the blueprint itself carries
73
- `<must-fill>` sentinels and is not directly renderable), writes the artifacts
96
+ It renders every quill's illustrative example document (seeded via
97
+ `quill.seedDocument()` — a fully filled-out, always-renderable sample; the
98
+ blueprint itself carries `<must-fill>` sentinels and is not directly
99
+ renderable), writes the artifacts
74
100
  to `outDir` (default `preview/`), and emits an `index.html`
75
101
  gallery. A `.gitignore` is written into `outDir` so the generated artifacts
76
102
  are never accidentally committed. A quill that throws is recorded as failed —
@@ -82,8 +108,7 @@ quill name or canonical ref):
82
108
 
83
109
  ```ts
84
110
  await renderQuiverSamples(import.meta.url, {
85
- engine: new Quillmark(),
86
- Document,
111
+ engine: new Engine(),
87
112
  exclude: ["broken-quill"], // or: include: ["memo@1.0.0"]
88
113
  });
89
114
  ```
@@ -96,21 +121,38 @@ await renderQuiverSamples(import.meta.url, {
96
121
  ## Consuming a quiver (Node)
97
122
 
98
123
  ```ts
99
- import { Quillmark, Document } from "@quillmark/wasm";
124
+ import { Engine, Document } from "@quillmark/wasm";
100
125
  import { Quiver } from "@quillmark/quiver/node";
101
126
 
102
- const engine = new Quillmark();
103
127
  const quiver = await Quiver.fromPackage("@org/my-quiver");
128
+ const engine = new Engine();
104
129
 
105
130
  const doc = Document.fromMarkdown(markdownString);
106
- const quill = await quiver.getQuill(doc.quillRef, { engine });
107
- const result = quill.render(doc, { format: "pdf" });
131
+ const quill = await quiver.getQuill(doc.quillRef);
132
+ const result = await engine.render(quill, doc, { format: "pdf" });
108
133
  ```
109
134
 
110
135
  `getQuill` accepts both selector refs (`"memo"`, `"memo@1"`) and canonical
111
136
  refs (`"memo@1.0.0"`). It resolves the selector, materializes the quill via
112
- `engine.quill(tree)`, and caches per (engine, canonical-ref). Concurrent
113
- calls for the same ref share a single load.
137
+ `Quill.fromTree(tree)` (engine-free), and caches one instance per canonical
138
+ ref for the lifetime of the `Quiver`. Concurrent calls for the same ref
139
+ coalesce into a single load.
140
+
141
+ The returned quill lives in the core build's WASM memory and is suitable for
142
+ schema inspection, validation, blueprint access, and seeding. To render it,
143
+ hand it straight to `engine.render(quill, doc)` — the Engine clones both
144
+ handles into the backend on demand, so no separate boundary-crossing step is
145
+ needed:
146
+
147
+ ```ts
148
+ // Editor path — core only, ~0.66 MB gzip
149
+ const coreQuill = await quiver.getQuill(ref);
150
+ coreQuill.schema; // ✓ schema, validate, blueprint, seed — all fine
151
+ const doc = coreQuill.seedDocument(); // a fully-filled example document
152
+
153
+ // Render path — the same core handles render directly.
154
+ const result = await engine.render(coreQuill, doc, { format: "pdf" });
155
+ ```
114
156
 
115
157
  If you only need the canonical ref (without materializing), use `resolve`:
116
158
 
@@ -118,6 +160,10 @@ If you only need the canonical ref (without materializing), use `resolve`:
118
160
  const canonicalRef = await quiver.resolve("memo"); // "memo@1.1.0"
119
161
  ```
120
162
 
163
+ If you need the raw file tree (e.g. to drive a backend binary directly), call
164
+ `(await quiver.getQuill(ref)).toTree()` on the core `Quill` — it is I/O-free
165
+ once the quill is materialized.
166
+
121
167
  ## Consuming a quiver (browser)
122
168
 
123
169
  Browsers cannot read the source layout directly, so build at deploy time and
@@ -135,10 +181,15 @@ await Quiver.build(
135
181
 
136
182
  ```ts
137
183
  // browser runtime
184
+ import { Engine, Document } from "@quillmark/wasm";
138
185
  import { Quiver } from "@quillmark/quiver";
139
186
 
140
187
  const quiver = await Quiver.fromBuiltUrl("/quivers/my-quiver/");
141
- const quill = await quiver.getQuill(doc.quillRef, { engine });
188
+ const engine = new Engine();
189
+
190
+ const doc = Document.fromMarkdown(markdownString);
191
+ const quill = await quiver.getQuill(doc.quillRef);
192
+ const result = await engine.render(quill, doc, { format: "pdf" });
142
193
  ```
143
194
 
144
195
  ## Server-side runtime (Node, packed artifact on disk)
@@ -178,15 +229,10 @@ await quiver.warm();
178
229
 
179
230
  `warm()` is I/O-only: it loads every quill's tree (over the network for
180
231
  `fromBuiltUrl`, off the filesystem for `fromPackage` / `fromDir` /
181
- `fromBuiltDir`) and caches
182
- them. It does not require an engine and does not materialize Quill
183
- instances — that happens lazily on the first `getQuill` call, which is
184
- microseconds. A subsequent `getQuill` reuses the cached tree, skipping
185
- the load.
186
-
187
- Once a tree has been turned into a Quill, the cached tree is dropped so
188
- its bytes can be GC'd — the materialized Quill is the runtime artifact.
189
- Calling `warm()` again refills the tree cache.
232
+ `fromBuiltDir`) and caches them. It does not require an engine and does
233
+ not materialize Quill instances — that happens lazily on the first
234
+ `getQuill` call, which is microseconds. A subsequent `getQuill` reuses
235
+ the cached tree, skipping the load.
190
236
 
191
237
  ## Error handling
192
238
 
@@ -208,6 +254,26 @@ try {
208
254
 
209
255
  Error codes: `invalid_ref`, `quill_not_found`, `quiver_invalid`, `transport_error`.
210
256
 
211
- ## Full specification
257
+ ## Using `getQuill` vs calling `Quill.fromTree` directly
258
+
259
+ `getQuill(ref)` is the correct entry point for any code that loads a quill
260
+ through a `Quiver`. It handles ref resolution, tree fetching, `Quill.fromTree`
261
+ construction, and per-ref caching in one call. Do **not** reach for
262
+ `Quill.fromTree` directly inside a Quiver consumer:
263
+
264
+ ```ts
265
+ import { Quill } from "@quillmark/wasm";
266
+
267
+ // wrong — bypasses Quiver's cache; duplicates work getQuill already does
268
+ const tree = new Map<string, Uint8Array>();
269
+ tree.set("Quill.yaml", new TextEncoder().encode("name: memo\n..."));
270
+ // ...assemble the rest of the file tree by hand...
271
+ const quill = Quill.fromTree(tree);
272
+
273
+ // right
274
+ const quill = await quiver.getQuill(ref);
275
+ ```
212
276
 
213
- See [PROGRAM.md](./PROGRAM.md) for the complete API surface, runtime artifact format specification, and design decisions.
277
+ `Quill.fromTree` is for code that builds quills **outside** of a Quiver (e.g.
278
+ a server route that receives a raw file tree over the network, or a test
279
+ fixture that constructs a quill from a hand-rolled in-memory tree).
@@ -9,8 +9,8 @@
9
9
  * [--include <ref>...] [--exclude <ref>...]
10
10
  *
11
11
  * Engine discovery (for `test` and `preview`):
12
- * 1. Named exports `engine` and `Document` from `quiver.config.js` at the
13
- * collection root, if the file exists.
12
+ * 1. Named export `engine` from `quiver.config.js` at the collection root,
13
+ * if the file exists.
14
14
  * 2. Auto-imported `@quillmark/wasm` from the collection's node_modules.
15
15
  */
16
16
  export {};
@@ -9,8 +9,8 @@
9
9
  * [--include <ref>...] [--exclude <ref>...]
10
10
  *
11
11
  * Engine discovery (for `test` and `preview`):
12
- * 1. Named exports `engine` and `Document` from `quiver.config.js` at the
13
- * collection root, if the file exists.
12
+ * 1. Named export `engine` from `quiver.config.js` at the collection root,
13
+ * if the file exists.
14
14
  * 2. Auto-imported `@quillmark/wasm` from the collection's node_modules.
15
15
  */
16
16
  import { createRequire } from "node:module";
@@ -42,32 +42,35 @@ function hasFlag(name) {
42
42
  // Engine discovery
43
43
  // ---------------------------------------------------------------------------
44
44
  async function loadEngine(cwd) {
45
- // 1. Named exports from quiver.config.js, if present.
45
+ // Resolve @quillmark/wasm from the collection's node_modules (best-effort).
46
+ // Its `Engine` renders every quill (cloning the core Quill/Document into the
47
+ // backend itself). A quiver.config.js may export a custom `engine`.
48
+ let wasm;
46
49
  try {
47
- const cfg = await import(pathToFileURL(join(cwd, "quiver.config.js")).href);
48
- if (cfg.engine != null && cfg.Document != null) {
49
- return {
50
- engine: cfg.engine,
51
- Document: cfg.Document,
52
- };
53
- }
50
+ const req = createRequire(pathToFileURL(join(cwd, "package.json")).href);
51
+ const wasmPath = req.resolve("@quillmark/wasm");
52
+ wasm = (await import(pathToFileURL(wasmPath).href));
54
53
  }
55
54
  catch {
56
- // File absent or incomplete — fall through to auto-discovery.
55
+ // Not installed — a quiver.config.js may still provide an engine.
57
56
  }
58
- // 2. Auto-discover @quillmark/wasm from the collection's own node_modules.
59
- const req = createRequire(pathToFileURL(join(cwd, "package.json")).href);
60
- let wasmPath;
57
+ // 1. Named `engine` export from quiver.config.js, if present.
61
58
  try {
62
- wasmPath = req.resolve("@quillmark/wasm");
59
+ const cfg = await import(pathToFileURL(join(cwd, "quiver.config.js")).href);
60
+ if (cfg.engine != null) {
61
+ return cfg.engine;
62
+ }
63
63
  }
64
64
  catch {
65
+ // File absent or incomplete — fall through to auto-discovery.
66
+ }
67
+ // 2. Auto-discover from @quillmark/wasm.
68
+ if (wasm == null) {
65
69
  throw new Error("Cannot find @quillmark/wasm in this collection's node_modules.\n" +
66
70
  " Install it: npm install @quillmark/wasm\n" +
67
- " Or export { engine, Document } from quiver.config.js for a custom engine.");
71
+ " Or export { engine } from quiver.config.js for a custom engine.");
68
72
  }
69
- const wasm = (await import(pathToFileURL(wasmPath).href));
70
- return { engine: new wasm.Quillmark(), Document: wasm.Document };
73
+ return new wasm.Engine();
71
74
  }
72
75
  // ---------------------------------------------------------------------------
73
76
  // Commands
@@ -81,7 +84,7 @@ async function build() {
81
84
  }
82
85
  async function test() {
83
86
  const cwd = process.cwd();
84
- const { engine, Document } = await loadEngine(cwd);
87
+ const engine = await loadEngine(cwd);
85
88
  const quiver = await Quiver.fromDir(cwd);
86
89
  const names = quiver.quillNames();
87
90
  if (names.length === 0) {
@@ -94,9 +97,15 @@ async function test() {
94
97
  for (const version of quiver.versionsOf(name)) {
95
98
  const ref = `${name}@${version}`;
96
99
  try {
97
- const quill = await quiver.getQuill(ref, { engine });
98
- const doc = Document.fromMarkdown(quill.example);
99
- const result = quill.render(doc);
100
+ const quill = await quiver.getQuill(ref);
101
+ const doc = quill.seedDocument();
102
+ let result;
103
+ try {
104
+ result = await engine.render(quill, doc);
105
+ }
106
+ finally {
107
+ doc.free();
108
+ }
100
109
  if (!Array.isArray(result.artifacts) || result.artifacts.length === 0) {
101
110
  throw new Error("example render produced no artifacts");
102
111
  }
@@ -116,7 +125,7 @@ async function test() {
116
125
  }
117
126
  async function preview() {
118
127
  const cwd = process.cwd();
119
- const { engine, Document } = await loadEngine(cwd);
128
+ const engine = await loadEngine(cwd);
120
129
  const outDir = flag("--out");
121
130
  const format = flag("--format");
122
131
  const quiet = hasFlag("--quiet");
@@ -124,7 +133,6 @@ async function preview() {
124
133
  const exclude = multiFlag("--exclude");
125
134
  await renderQuiverSamples(cwd, {
126
135
  engine,
127
- Document,
128
136
  ...(outDir !== undefined && { outDir }),
129
137
  ...(format !== undefined && { format }),
130
138
  quiet,
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
1
  export { QuiverError } from "./errors.js";
2
2
  export type { QuiverErrorCode } from "./errors.js";
3
3
  export { Quiver } from "./quiver.js";
4
- export type { QuillmarkLike, QuillLike } from "./engine-types.js";
package/dist/index.js CHANGED
@@ -5,3 +5,8 @@
5
5
  // live at `@quillmark/quiver/node`.
6
6
  export { QuiverError } from "./errors.js";
7
7
  export { Quiver } from "./quiver.js";
8
+ // The canonical API (`Quill`, `Document`, `Engine`, `RenderResult`, …) is not
9
+ // re-exported: import it straight from the `@quillmark/wasm` peer dependency,
10
+ // which is the single source of truth. `quiver.getQuill(ref)` returns a core
11
+ // `Quill` that an `Engine` renders directly — the engine clones it into the
12
+ // backend, so no boundary-crossing helper is needed.
package/dist/node.d.ts CHANGED
@@ -79,4 +79,3 @@ export declare const Quiver: typeof Base & NodeQuiverStatics;
79
79
  export { QuiverError } from "./errors.js";
80
80
  export type { QuiverErrorCode } from "./errors.js";
81
81
  export type { BuildOptions } from "./build.js";
82
- export type { QuillmarkLike, QuillLike } from "./engine-types.js";
package/dist/node.js CHANGED
@@ -70,3 +70,6 @@ Quiver.buildPackage = async function buildPackage(specifier, outDir, opts) {
70
70
  // 3. Re-export the rest of the public surface so consumers get one import.
71
71
  // ---------------------------------------------------------------------------
72
72
  export { QuiverError } from "./errors.js";
73
+ // Engine types (`Quillmark`, `Quill`, `Document`, `RenderResult`, …) are not
74
+ // re-exported: import them straight from the `@quillmark/wasm` peer dependency,
75
+ // which is the single source of truth for the engine contract.
package/dist/preview.d.ts CHANGED
@@ -11,37 +11,29 @@
11
11
  *
12
12
  * Usage (place a script next to your Quiver.yaml):
13
13
  *
14
- * import { Quillmark, Document } from "@quillmark/wasm";
14
+ * import { Engine } from "@quillmark/wasm";
15
15
  * import { renderQuiverSamples } from "@quillmark/quiver/preview";
16
16
  *
17
- * await renderQuiverSamples(import.meta.url, {
18
- * engine: new Quillmark(),
19
- * Document,
20
- * });
17
+ * await renderQuiverSamples(import.meta.url, { engine: new Engine() });
21
18
  * // → open ./preview/index.html
22
19
  *
23
- * The sample document is the illustrative example (`quill.example`) for each
24
- * quill version — a fully filled-out, always-renderable document (the
25
- * blueprint itself carries `<must-fill>` sentinels and is not renderable).
26
- * Every quill always has an example, so no quills are skipped for lack of a
27
- * sample document.
20
+ * The sample document is the illustrative example seeded by
21
+ * `quill.seedDocument()` for each quill version — a fully filled-out,
22
+ * always-renderable document (the blueprint itself carries `<must-fill>`
23
+ * sentinels and is not renderable). Every quill always seeds an example, so no
24
+ * quills are skipped for lack of a sample document.
28
25
  *
29
26
  * A `.gitignore` is written into `outDir` so the generated artifacts are not
30
27
  * accidentally committed.
31
28
  */
32
- import type { QuillmarkLike } from "./engine-types.js";
33
- /**
34
- * Structural shape of the `Document` class from `@quillmark/wasm`. Only the
35
- * `fromMarkdown` factory is used; passing the real class satisfies this.
36
- */
37
- export interface DocumentFactoryLike {
38
- fromMarkdown(markdown: string): unknown;
39
- }
29
+ import type { Engine } from "@quillmark/wasm";
40
30
  export interface RenderQuiverSamplesOptions {
41
- /** Quillmark engine instance (`new Quillmark()` from `@quillmark/wasm`). */
42
- engine: QuillmarkLike;
43
- /** The `Document` class from `@quillmark/wasm`. */
44
- Document: DocumentFactoryLike;
31
+ /**
32
+ * Canonical render engine (`new Engine()` from `@quillmark/wasm`). It takes the
33
+ * core `Quill`/`Document` that quiver produces and clones them into the
34
+ * backend on demand — no build-matching or handle-crossing for the caller.
35
+ */
36
+ engine: Engine;
45
37
  /** Directory to write rendered artifacts into. Default: `preview`. */
46
38
  outDir?: string;
47
39
  /** Force an output format (`pdf`/`svg`/`png`/`txt`). Default: engine's choice. */
package/dist/preview.js CHANGED
@@ -11,20 +11,17 @@
11
11
  *
12
12
  * Usage (place a script next to your Quiver.yaml):
13
13
  *
14
- * import { Quillmark, Document } from "@quillmark/wasm";
14
+ * import { Engine } from "@quillmark/wasm";
15
15
  * import { renderQuiverSamples } from "@quillmark/quiver/preview";
16
16
  *
17
- * await renderQuiverSamples(import.meta.url, {
18
- * engine: new Quillmark(),
19
- * Document,
20
- * });
17
+ * await renderQuiverSamples(import.meta.url, { engine: new Engine() });
21
18
  * // → open ./preview/index.html
22
19
  *
23
- * The sample document is the illustrative example (`quill.example`) for each
24
- * quill version — a fully filled-out, always-renderable document (the
25
- * blueprint itself carries `<must-fill>` sentinels and is not renderable).
26
- * Every quill always has an example, so no quills are skipped for lack of a
27
- * sample document.
20
+ * The sample document is the illustrative example seeded by
21
+ * `quill.seedDocument()` for each quill version — a fully filled-out,
22
+ * always-renderable document (the blueprint itself carries `<must-fill>`
23
+ * sentinels and is not renderable). Every quill always seeds an example, so no
24
+ * quills are skipped for lack of a sample document.
28
25
  *
29
26
  * A `.gitignore` is written into `outDir` so the generated artifacts are not
30
27
  * accidentally committed.
@@ -32,6 +29,7 @@
32
29
  import { mkdir, writeFile } from "node:fs/promises";
33
30
  import { join } from "node:path";
34
31
  import { Quiver } from "./node.js";
32
+ import { isQuillmarkError } from "@quillmark/wasm";
35
33
  /** Default directory rendered artifacts are written to. */
36
34
  const DEFAULT_OUT_DIR = "preview";
37
35
  /**
@@ -74,13 +72,12 @@ function isSelected(name, ref, opts) {
74
72
  }
75
73
  /**
76
74
  * Formats a thrown render error into one string per diagnostic. `@quillmark/wasm`
77
- * attaches a `diagnostics` array to its errors; fall back to the message when
78
- * an error carries none.
75
+ * throws `QuillmarkError`s (an `Error` carrying `diagnostics`); fall back to
76
+ * the message for anything else.
79
77
  */
80
78
  function failureReasons(err) {
81
- const diagnostics = err.diagnostics;
82
- if (Array.isArray(diagnostics) && diagnostics.length > 0) {
83
- return diagnostics.map((d) => `${d.severity}: ${d.message}`);
79
+ if (isQuillmarkError(err) && err.diagnostics.length > 0) {
80
+ return err.diagnostics.map((d) => `${d.severity}: ${d.message}`);
84
81
  }
85
82
  return [err.message];
86
83
  }
@@ -88,10 +85,16 @@ async function renderOne(quiver, name, version, outDir, opts) {
88
85
  const ref = `${name}@${version}`;
89
86
  let result;
90
87
  try {
91
- const quill = await quiver.getQuill(ref, { engine: opts.engine });
92
- const markdown = quill.example;
93
- const doc = opts.Document.fromMarkdown(markdown);
94
- result = quill.render(doc, opts.format ? { format: opts.format } : undefined);
88
+ // Canonical render path: a core Quill + its seeded Document handed straight
89
+ // to the Engine, which clones them into the backend and frees the clones.
90
+ const quill = await quiver.getQuill(ref);
91
+ const doc = quill.seedDocument();
92
+ try {
93
+ result = await opts.engine.render(quill, doc, opts.format ? { format: opts.format } : undefined);
94
+ }
95
+ finally {
96
+ doc.free();
97
+ }
95
98
  }
96
99
  catch (err) {
97
100
  return {
package/dist/quiver.d.ts CHANGED
@@ -9,7 +9,7 @@
9
9
  * `build`) are installed on this class by `./node.js`, which is the
10
10
  * consumer's explicit opt-in to the Node API surface.
11
11
  */
12
- import type { QuillmarkLike, QuillLike } from "./engine-types.js";
12
+ import { Quill } from "@quillmark/wasm";
13
13
  /** @internal Internal loader strategy: source or build output. */
14
14
  export interface QuiverLoader {
15
15
  loadTree(name: string, version: string): Promise<Map<string, Uint8Array>>;
@@ -49,16 +49,6 @@ export declare class Quiver {
49
49
  * Returns an empty array if the quill name is not in the catalog.
50
50
  */
51
51
  versionsOf(name: string): string[];
52
- /**
53
- * Lazily loads the file tree for a specific quill version.
54
- *
55
- * Returns `Map<string, Uint8Array>` suitable for `engine.quill(tree)`.
56
- * Does NOT cache the result — caching of materialized Quill instances
57
- * happens in `getQuill`.
58
- *
59
- * Throws `transport_error` if name/version not in catalog or I/O fails.
60
- */
61
- loadTree(name: string, version: string): Promise<Map<string, Uint8Array>>;
62
52
  /**
63
53
  * Resolves a selector ref → canonical ref (e.g. "memo" → "memo@1.1.0").
64
54
  *
@@ -71,29 +61,32 @@ export declare class Quiver {
71
61
  */
72
62
  resolve(ref: string): Promise<string>;
73
63
  /**
74
- * Returns a render-ready `Quill` for a ref (selector or canonical).
64
+ * Returns a `Quill` for a ref (selector or canonical).
65
+ *
66
+ * The returned quill is materialized from the `@quillmark/wasm` root export
67
+ * — it is engine-free, portable data suitable for schema inspection,
68
+ * validation, blueprint access, and document seeding.
69
+ *
70
+ * A core `Quill` renders directly: pass it to `engine.render(quill, doc)`.
75
71
  *
76
- * Selector refs (e.g. `"memo"`, `"memo@1"`) are resolved to canonical
77
- * form first. Materializes via `engine.quill(tree)` on first call;
78
- * caches per (engine, canonical-ref). Reuses a tree cached by `warm()`
79
- * (or a previous `getQuill`) so the network fetch isn't paid twice.
80
- * Concurrent calls for the same ref coalesce into a single load.
72
+ * Selector refs (e.g. `"memo"`, `"memo@1"`) are resolved to canonical form
73
+ * first. Materializes once and caches per canonical ref — concurrent calls
74
+ * coalesce into a single load.
81
75
  *
82
76
  * Throws:
83
77
  * - `invalid_ref` if ref is malformed
84
78
  * - `quill_not_found` if ref does not match any version in this quiver
85
- * - propagates I/O errors from loadTree unchanged
86
- * - propagates engine errors from engine.quill() unchanged
79
+ * - propagates I/O errors from the loader unchanged
80
+ * - propagates validation errors from Quill.fromTree() unchanged
87
81
  */
88
- getQuill(ref: string, opts: {
89
- engine: QuillmarkLike;
90
- }): Promise<QuillLike>;
82
+ getQuill(ref: string): Promise<Quill>;
91
83
  /**
92
84
  * Prefetches the tree for every quill version in this quiver. Fail-fast.
93
85
  *
94
86
  * Network-bound only — does not materialize Quill instances and does not
95
87
  * require an engine. Subsequent `getQuill` calls reuse the cached trees,
96
- * skipping the fetch. Rejects on the first fetch failure.
88
+ * skipping the fetch (the tree then evicts as its quill materializes).
89
+ * Rejects on the first fetch failure.
97
90
  */
98
91
  warm(): Promise<void>;
99
92
  }