@hueest/xray 0.6.0 → 0.7.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/dist/index.d.ts CHANGED
@@ -1,39 +1,34 @@
1
1
  import { Plugin } from "vite";
2
-
3
2
  //#region src/diagnostics.d.ts
4
3
  /**
5
- * Dev-only capture diagnostics: a small, serializable record of why a Plate may
6
- * be incomplete or lower-fidelity, plus the one shared formatter both the
7
- * browser console (`client.ts`) and the Vite server output (`index.ts`) print.
4
+ * Dev-only capture diagnostics: a small, serializable record of why a Plate may be incomplete or
5
+ * lower-fidelity, plus the one shared formatter both the browser console (`client.ts`) and the Vite
6
+ * server output (`index.ts`) print.
8
7
  *
9
- * Motivation: the serializer silently swallows a handful of capture omissions
10
- * (an unreadable cross-origin stylesheet, skipped pseudo-elements, off-screen
11
- * bones dropped at the fold, an over-the-limit subtree). Early adopters asking "why does this
12
- * skeleton look wrong?" had to read the serializer source to find out. These
13
- * diagnostics surface those omissions as data the capture process returns, so a
14
- * caller can log them — without the core performing any console side effects.
8
+ * Motivation: the serializer silently swallows a handful of capture omissions (an unreadable
9
+ * cross-origin stylesheet, skipped pseudo-elements, off-screen bones dropped at the fold, an
10
+ * over-the-limit subtree). Without these records, "why does this skeleton look wrong?" has no
11
+ * answer short of reading the serializer source. Diagnostics surface those omissions as data the
12
+ * capture returns, so a caller can log them; the core performs no console side effects.
15
13
  *
16
- * Strictly DEV-ONLY (see the plan's decisions and ADR 0008): this type is NOT a
17
- * public package export and MUST NEVER reach the persisted Plate JSON, the
18
- * `MergedPlate`, or the production adapter. It rides on the TRANSIENT
19
- * `ViewIR.diagnostics` field only, which `captureView` populates and the
20
- * dev client strips before posting (so committed `plates/<name>.json` stays
21
- * byte-identical to a capture that produced no diagnostics).
14
+ * Strictly DEV-ONLY (ADR 0024, ADR 0008): this type is NOT a public package export and MUST NEVER
15
+ * reach the persisted Plate JSON, the `GatedPlate`, or the production adapter. It rides on the
16
+ * TRANSIENT `ViewIR.diagnostics` field only, which `captureView` populates and the dev client
17
+ * strips before posting (so committed `plates/<name>.json` stays byte-identical to a capture that
18
+ * produced no diagnostics).
22
19
  *
23
- * Centralized on purpose: a follow-up plan (capture-input-validation) reuses
24
- * this same messaging for invalid posted/committed plates, so the code table
25
- * and formatter are kept reusable. Browser and server share `formatDiagnostic`
26
- * so their warning text cannot drift.
20
+ * Centralized on purpose: invalid posted/committed plates (ADR 0023) reuse the same messaging, so
21
+ * the code table and formatter stay reusable. Browser and server share `formatDiagnostic` so their
22
+ * warning text cannot drift.
27
23
  *
28
24
  * @module
29
25
  */
30
26
  /**
31
- * One aggregated capture omission. Serializable on purpose: NO DOM nodes, NO
32
- * CSS bodies, NO captured text — only a stable `code`, a human message, an
33
- * optional aggregate `count`, and an optional short `detail` (e.g. a plate name
34
- * or a node count, never user content). `count` aggregates occurrences: there
35
- * is at most one record per code per capture, never one per skipped selector or
36
- * node.
27
+ * One aggregated capture omission. Serializable on purpose: NO DOM nodes, NO CSS bodies, NO
28
+ * captured text — only a stable `code`, a human message, an optional aggregate `count`, and an
29
+ * optional short `detail` (e.g. a plate name or a node count, never user content). `count`
30
+ * aggregates occurrences: there is at most one record per code per capture, never one per skipped
31
+ * selector or node.
37
32
  */
38
33
  interface CaptureDiagnostic {
39
34
  code: DiagnosticCode;
@@ -42,59 +37,59 @@ interface CaptureDiagnostic {
42
37
  detail?: string;
43
38
  }
44
39
  /**
45
- * The closed set of capture-omission codes. Each maps to one silent site in the
46
- * serializer (or an existing oversized-capture warning folded into the same
47
- * vocabulary). Kept as a const union so the message table is exhaustive.
40
+ * The closed set of capture-omission codes. Each maps to one silent site in the serializer (or an
41
+ * existing oversized-capture warning folded into the same vocabulary). Kept as a const union so the
42
+ * message table is exhaustive.
48
43
  */
49
44
  type DiagnosticCode = 'unreadable-stylesheet' | 'unreadable-import' | 'skipped-dynamic-pseudo' | 'skipped-pseudo-element' | 'unsupported-rule' | 'dropped-tag' | 'dropped-subset' | 'dropped-cropped' | 'too-large' | 'invalid-plate-file';
50
45
  //#endregion
51
46
  //#region src/plate.d.ts
52
- type LeafKind = 'text' | 'text-block' | 'media' | 'box';
53
47
  /**
54
- * The shipped structural capture of a component's rendered DOM the TREE
55
- * artifact a Skeleton renders from (see CONTEXT.md). Since the two-artifact
56
- * cutover (plan 005 round 2), a Plate carries structure ONLY: its scoped CSS
57
- * is an INDEPENDENT sibling artifact — the plugin serves it through Vite's
58
- * own CSS pipeline (`virtual:xray/plates/<name>.css`, plus the shared
59
- * `virtual:xray/base.css`, and an `export const css` on the virtual JS module
60
- * for dev/programmatic reads), and the framework-neutral `core.ts` path hands
61
- * it back separately (`captureElement` `{ plate, css }`;
62
- * `renderPlateHtml(plate, css)` receives it explicitly). Consumers decide how
63
- * to render either part. Still self-contained in ADR 0003's sense: both
64
- * artifacts originate from the capture and depend on nothing in the
65
- * consumer's build. Built from the RenderNode tree at plugin load (see
66
- * chunk.ts), so the adapter injects strings instead of walking a tree on the
67
- * latency-critical first paint and no per-framework serializer ships to the
68
- * client (ADR 0008).
48
+ * `hidden` is EXPLICIT-ONLY (a `data-xr-bone-kind` hint or a walker `ctx.bone({ kind: 'hidden'
49
+ * })`), never inferred: a bone that holds its measured box in the layout but paints nothing — the
50
+ * space-preserving complement to `data-xr-ignore`, which drops the box entirely.
51
+ */
52
+ type LeafKind = 'text-line' | 'text-block' | 'media' | 'box' | 'hidden';
53
+ /**
54
+ * The shipped structural capture of a component's rendered DOM — the TREE artifact a Skeleton
55
+ * renders from (see the glossary: xray-js.dev/glossary). A Plate carries structure ONLY (ADR 0026):
56
+ * its scoped CSS is an INDEPENDENT sibling artifact — the plugin serves it through Vite's own CSS
57
+ * pipeline (`virtual:xray/plates/<name>.css`, plus the shared `virtual:xray/base.css`, and an
58
+ * `export const css` on the virtual JS module for dev/programmatic reads), and the
59
+ * framework-neutral `core.ts` path hands it back separately (`captureElement` `{ plate, css }`;
60
+ * `renderPlateHtml(plate, css)` receives it explicitly). Consumers decide how to render either
61
+ * part. Still self-contained in ADR 0003's sense: both artifacts originate from the capture and
62
+ * depend on nothing in the consumer's build. Built from the RenderNode tree at plugin load (see
63
+ * chunk.ts), so the adapter injects strings instead of walking a tree on the latency-critical first
64
+ * paint — and no per-framework serializer ships to the client (ADR 0008).
69
65
  */
70
66
  interface Plate {
71
67
  v: number;
72
68
  /** Capture name; comes from the virtual-module specifier, never typed at a call site. */
73
69
  name: string;
74
70
  /**
75
- * The root's children, pre-serialized (ADR 0008): a stitch-free run is one
76
- * HTML `string`; a stitch is `{ r: name }`; a stitch-bearing element is
77
- * `{ c: className, k: chunk[] }`. Null until first capture.
71
+ * The root's children, pre-serialized (ADR 0008): a stitch-free run is one HTML `string`; a
72
+ * stitch is `{ r: name }`; a stitch-bearing element is `{ c: className, k: chunk[] }`. Null until
73
+ * first capture.
78
74
  */
79
75
  chunks: Chunk[] | null;
80
76
  /** The root node's own content classes (its inherited font context), if any. */
81
77
  rootCls?: string;
82
78
  /**
83
- * Child plates named by the chunks' `{ r }` stitches, resolved through the
84
- * import graph (ADR 0006). Populated by the loader's generated imports, never
85
- * serialized into the plates JSON; absent in production when there are no
86
- * stitches. In dev the live store takes precedence, so this need not be present.
79
+ * Child plates named by the chunks' `{ r }` stitches, resolved through the import graph (ADR
80
+ * 0006). Populated by the loader's generated imports, never serialized into the plates JSON;
81
+ * absent in production when there are no stitches. In dev the live store takes precedence, so
82
+ * this need not be present.
87
83
  */
88
84
  refs?: Record<string, Plate>;
89
85
  }
90
86
  /**
91
- * One serialized child of a plate root (or of a stitch-bearing node): a
92
- * stitch-free HTML run (`string`), a stitch to a child plate (`{ r: name }`),
93
- * a stitch-bearing element kept real so its inner stitches can mount
94
- * (`{ c: className, k: chunk[] }`), or a templated uniform run (`{ t: html, n }`):
95
- * the cell's HTML once plus a repeat count the adapter expands to N copies (Phase
96
- * 2). The framework-neutral render contract: an adapter injects the strings,
97
- * mounts a child plate at each stitch, and repeats each template (ADR 0008).
87
+ * One serialized child of a plate root (or of a stitch-bearing node): a stitch-free HTML run
88
+ * (`string`), a stitch to a child plate (`{ r: name }`), a stitch-bearing element kept real so its
89
+ * inner stitches can mount (`{ c: className, k: chunk[] }`), or a templated uniform run (`{ t:
90
+ * html, n }`): the cell's HTML once plus a repeat count the adapter expands to N copies (Template,
91
+ * ADR 0022). The framework-neutral render contract: an adapter injects the strings, mounts a child
92
+ * plate at each stitch, and repeats each template (ADR 0008).
98
93
  */
99
94
  type Chunk = string | {
100
95
  r: string;
@@ -106,13 +101,12 @@ type Chunk = string | {
106
101
  n: number;
107
102
  };
108
103
  /**
109
- * A plate after the in-browser Serialize (emit + merge/gate + classify) but
110
- * before chunk serialization: the build-time RenderNode tree plus its scoped
111
- * CSS. Produced by `serializePlateIR` (the structural part of `StoredPlate`) and
112
- * the single-View `capture`, then serialized into the shipped `Plate` (chunks) at
113
- * load (`serializePlate`). Never shipped to the client.
104
+ * A plate after the in-browser Serialize (emit + gate + classify) but before chunk serialization:
105
+ * the build-time RenderNode tree plus its scoped CSS. Produced by `serializePlateIR` (the
106
+ * structural part of `StoredPlate`) and the single-View `capture`, then serialized into the shipped
107
+ * `Plate` (chunks) at load (`serializePlate`). Never shipped to the client.
114
108
  */
115
- interface MergedPlate {
109
+ interface GatedPlate {
116
110
  v: number;
117
111
  name: string;
118
112
  tree: RenderNode | null;
@@ -124,37 +118,38 @@ interface PlateNode {
124
118
  /** Present on paint leaves; absent on layout containers. */
125
119
  leaf?: LeafKind;
126
120
  /**
127
- * A stitch: render the named child plate's skeleton here instead of own
128
- * structure (ADR 0006). Mutually exclusive with `leaf`/`kids`. Resolved
129
- * against `Plate.refs` (prod) or the live store (dev).
121
+ * A stitch: render the named child plate's skeleton here instead of own structure (ADR 0006).
122
+ * Mutually exclusive with `leaf`/`kids`. Resolved against `Plate.refs` (prod) or the live store
123
+ * (dev).
130
124
  */
131
125
  ref?: string;
132
126
  /**
133
- * A templated uniform run (Phase 2): render this node's subtree `count` times.
134
- * The serializer emits the subtree's HTML once plus the count; the adapter
135
- * expands it to N copies at render. Absent on ordinary nodes.
127
+ * A templated uniform run (Template, ADR 0022): render this node's subtree `count` times. The
128
+ * serializer emits the subtree's HTML once plus the count; the adapter expands it to N copies at
129
+ * render. Absent on ordinary nodes.
136
130
  */
137
131
  count?: number;
138
132
  kids?: PlateNode[];
139
133
  }
140
134
  /**
141
- * A node in the shipped tree, after classify (ADR 0007). Carries the
142
- * content-addressed style classes it needs instead of an id — the CSS targets
143
- * those classes, not a per-node `data-xr` value, so node scoping (the old
144
- * `nodeKey`) is gone. `cls` is a space-joined class-token list.
135
+ * A node in the shipped tree, after classify (ADR 0007). Carries the content-addressed style
136
+ * classes it needs instead of an id — the CSS targets those classes, not a per-node `data-xr`
137
+ * value, so no per-node scoping key is needed. `cls` is a space-joined class-token list.
145
138
  */
146
139
  interface RenderNode {
147
140
  leaf?: LeafKind;
148
141
  ref?: string;
149
142
  cls?: string;
150
- /** A templated uniform run (Phase 2): serialize this subtree once + a count the adapter repeats. */
143
+ /**
144
+ * A templated uniform run (Template, ADR 0022): serialize this subtree once + a count the adapter
145
+ * repeats.
146
+ */
151
147
  count?: number;
152
148
  kids?: RenderNode[];
153
149
  }
154
150
  /**
155
- * A captured style rule in id form — selectors are generated at render time,
156
- * so view merging can remap node ids without string surgery. `ids: []`
157
- * targets the plate root.
151
+ * A captured style rule in id form — selectors are generated downstream, so Serialize can remap
152
+ * node ids without string surgery. `ids: []` targets the plate root.
158
153
  */
159
154
  interface PlateRule {
160
155
  ids: number[];
@@ -168,12 +163,10 @@ interface PlateRule {
168
163
  order: number;
169
164
  }
170
165
  /**
171
- * One capture of a component within one viewport view — `[min, max)` in px,
172
- * either side open-ended when undefined. The id-form `{ tree, rules }` shape
173
- * `emit` projects a measured View into (ADR 0004). NO LONGER the disk/wire shape
174
- * after the ADR 0022 cutover `StoredPlate` (below) is. Kept as the
175
- * framework-neutral per-View capture shape, exported for consumers reading the
176
- * id-form projection directly.
166
+ * One capture of a component within one viewport view — `[min, max)` in px, either side open-ended
167
+ * when undefined. The id-form `{ tree, rules }` shape `emit` projects a measured View into (ADR
168
+ * 0004). The disk/wire shape is `StoredPlate` (below); this is the framework-neutral per-View
169
+ * capture shape, exported for consumers reading the id-form projection directly.
177
170
  */
178
171
  interface ViewCapture {
179
172
  /** Viewport width at capture time. */
@@ -183,37 +176,32 @@ interface ViewCapture {
183
176
  tree: PlateNode;
184
177
  rules: PlateRule[];
185
178
  /**
186
- * TRANSIENT, dev-only capture diagnostics (why this view may be lower
187
- * fidelity). Captured in the browser (mirrored onto `ViewIR.diagnostics`); the
188
- * dev client logs it and posts it alongside the `StoredPlate` (so the Vite
189
- * server can print the same text). It MUST NEVER be persisted: it is not part
190
- * of the committed
191
- * `StoredPlate` disk shape, the validator does not carry it, and the POST
192
- * envelope keeps it in a SIBLING field that never reaches the stored artifact
193
- * (ADR 0008). Absent in production (the prod adapter ships no capture). See
194
- * diagnostics.ts and ADR 0008.
179
+ * TRANSIENT, dev-only capture diagnostics (why this view may be lower fidelity). Captured in the
180
+ * browser (mirrored onto `ViewIR.diagnostics`); the dev client logs it and posts it alongside the
181
+ * `StoredPlate` (so the Vite server can print the same text). It MUST NEVER be persisted: it is
182
+ * not part of the committed `StoredPlate` disk shape, the validator does not carry it, and the
183
+ * POST envelope keeps it in a SIBLING field that never reaches the stored artifact (ADR 0008).
184
+ * Absent in production (the prod adapter ships no capture). See diagnostics.ts and ADR 0008.
195
185
  */
196
186
  diagnostics?: CaptureDiagnostic[];
197
187
  }
198
188
  /**
199
- * The committed `plates/<name>.json` shape AFTER the ADR 0022 cutover: the whole
200
- * Plate already projected in the browser (the in-browser Serialize folds emit +
201
- * the multi-View merge/gate + classify in one session), so disk holds ONE gated,
202
- * content-addressed tree + css instead of per-View captures merged at load. It is
203
- * a `MergedPlate` (the structural `{tree, css}` `serializePlate` consumes) PLUS the
204
- * `breakpoints` the HUD coverage reads the analysis-only geometry never crosses
205
- * the wire (ADR 0021). The gen-side runs `serializePlate(stored) → Plate` (chunks)
206
- * at module-load, leaving the Tailwind/Bundle passthrough a clean gen-side seam.
207
- * Replaces `PlateFile` (+ `ViewCapture`) on disk and on the `/__xray` wire.
189
+ * The committed `plates/<name>.json` shape (ADR 0022): the whole Plate already projected in the
190
+ * browser (the in-browser Serialize folds emit + the multi-View gating + classify in one session),
191
+ * so disk holds ONE gated, content-addressed tree + css rather than per-View captures assembled at
192
+ * load. It is a `GatedPlate` (the structural `{tree, css}` `serializePlate` consumes) PLUS the
193
+ * `breakpoints` the HUD coverage reads the analysis-only geometry never crosses the wire (ADR
194
+ * 0021). The gen-side runs `serializePlate(stored) Plate` (chunks) at module-load, leaving the
195
+ * Tailwind/Bundle passthrough a clean gen-side seam.
208
196
  */
209
- interface StoredPlate extends MergedPlate {
197
+ interface StoredPlate extends GatedPlate {
210
198
  /** Width thresholds (view boundaries); the HUD coverage derives its bands from these. */
211
199
  breakpoints: number[];
212
200
  }
213
201
  /**
214
- * A dev-only sticky boolean toggle (get/set/subscribe), persisted per tab.
215
- * Used for both "light box" (render every `<Skeleton>` regardless of readiness)
216
- * and "capture" (whether browsing re-captures plates).
202
+ * A dev-only sticky boolean toggle (get/set/subscribe), persisted per tab. Used for both "light
203
+ * box" (render every `<Skeleton>` regardless of readiness) and "capture" (whether browsing
204
+ * re-captures plates).
217
205
  */
218
206
  interface ToggleStore {
219
207
  get: () => boolean;
@@ -221,19 +209,17 @@ interface ToggleStore {
221
209
  subscribe: (onChange: () => void) => () => void;
222
210
  }
223
211
  /**
224
- * Dev-only store of the freshest plate per name, updated in place when a
225
- * capture lands. `<Skeleton>` reads through it so a new plate re-renders the
226
- * site rather than reloading the module which would remount the capture
227
- * boundary and re-fire the capture, a feedback loop.
212
+ * Dev-only store of the freshest plate per name, updated in place when a capture lands.
213
+ * `<Skeleton>` reads through it so a new plate re-renders the site rather than reloading the module
214
+ * which would remount the capture boundary and re-fire the capture, a feedback loop.
228
215
  */
229
216
  interface PlateStore {
230
217
  get: (name: string) => Plate | undefined;
231
218
  subscribe: (name: string, onChange: () => void) => () => void;
232
219
  /**
233
- * Register a plate imported via the ref graph if the store has none yet — so a
234
- * stitch resolves even before its child is re-captured, and survives a parent
235
- * hot-swap (whose pushed plate carries no resolved `refs`). Never overwrites a
236
- * live capture.
220
+ * Register a plate imported via the ref graph if the store has none yet — so a stitch resolves
221
+ * even before its child is re-captured, and survives a parent hot-swap (whose pushed plate
222
+ * carries no resolved `refs`). Never overwrites a live capture.
237
223
  */
238
224
  seed: (name: string, plate: Plate) => void;
239
225
  }
@@ -243,34 +229,31 @@ interface Span {
243
229
  max?: number;
244
230
  }
245
231
  /**
246
- * Dev-only Fixture store (ADR 0015): stored render-INPUT `data` per Plate,
247
- * recorded to and replayed from a `plates/<name>.fixture.json` sidecar. Entirely
248
- * dev-only — devalue and this store never reach the production bundle.
232
+ * Dev-only Fixture store (ADR 0015): stored render-INPUT `data` per Plate, recorded to and replayed
233
+ * from a `plates/<name>.fixture.json` sidecar. Entirely dev-only — devalue and this store never
234
+ * reach the production bundle.
235
+ *
236
+ * Two cooperating halves, both flowing through the render-prop `data` seam (ADR 0014):
249
237
  *
250
- * Two cooperating halves, both flowing through the render-prop `data` seam (ADR
251
- * 0014):
252
- * - The dev adapter (`react.dev.tsx`) calls `register(name, data)` at
253
- * `loading=false` with the live `data` it is about to render, so the latest
254
- * recordable input for each mounted Plate is always in scope for Record.
255
- * - `record(name)` serializes that registered live `data` with devalue and POSTs
256
- * it to the sidecar (the HUD button and the `first-ready`/`always` modes call
257
- * it). `has(name)` reports whether a Fixture exists (HUD coverage marker), and
258
- * `read(name)` returns the parsed Fixture `data` for Replay to substitute in
259
- * front of the render prop.
238
+ * - The dev adapter (`react.dev.tsx`) calls `register(name, data)` at `loading=false` with the live
239
+ * `data` it is about to render, so the latest recordable input for each mounted Plate is always
240
+ * in scope for Record.
241
+ * - `record(name)` serializes that registered live `data` with devalue and POSTs it to the sidecar
242
+ * (the HUD button and the `first-ready`/`always` modes call it). `has(name)` reports whether a
243
+ * Fixture exists (HUD coverage marker), and `read(name)` returns the parsed Fixture `data` for
244
+ * Replay to substitute in front of the render prop.
260
245
  *
261
- * The store holds DECODED values (the dev client owns the devalue parse, since it
262
- * has the live runtime); only the on-disk sidecar and the wire carry the opaque
263
- * devalue string.
246
+ * The store holds DECODED values (the dev client owns the devalue parse, since it has the live
247
+ * runtime); only the on-disk sidecar and the wire carry the opaque devalue string.
264
248
  */
265
249
  interface FixtureStore {
266
250
  /**
267
- * Record the latest live `data` the dev adapter is about to render for `name`,
268
- * so Record always has the current recordable input in scope. A `register` with
269
- * the same value is cheap; the adapter calls it on every ready render. Returns a
270
- * disposer the adapter runs on unmount so an unmounted Skeleton's `data` never
271
- * lingers in the store: an unmounted instance must never be recorded or shadow a
272
- * still-mounted one (ADR 0015). With several Skeletons of the same plate name
273
- * mounted, the live value is the most-recently-registered still-mounted instance.
251
+ * Record the latest live `data` the dev adapter is about to render for `name`, so Record always
252
+ * has the current recordable input in scope. A `register` with the same value is cheap; the
253
+ * adapter calls it on every ready render. Returns a disposer the adapter runs on unmount so an
254
+ * unmounted Skeleton's `data` never lingers in the store: an unmounted instance must never be
255
+ * recorded or shadow a still-mounted one (ADR 0015). With several Skeletons of the same plate
256
+ * name mounted, the live value is the most-recently-registered still-mounted instance.
274
257
  */
275
258
  register: (name: string, data: unknown) => () => void;
276
259
  /** True once a recorded Fixture exists for `name` (drives the HUD coverage marker). */
@@ -280,25 +263,22 @@ interface FixtureStore {
280
263
  data: unknown;
281
264
  } | undefined;
282
265
  /**
283
- * Serialize the registered live `data` for `name` with devalue and POST it to
284
- * the sidecar. Returns a promise that resolves once the write is
285
- * server-confirmed (so the HUD can surface a failed Record). Throws loudly when
286
- * the live `data` is unrecordable (devalue's contract) or no live `data` was
287
- * registered (a plain-children `<Skeleton>` has none).
266
+ * Serialize the registered live `data` for `name` with devalue and POST it to the sidecar.
267
+ * Returns a promise that resolves once the write is server-confirmed (so the HUD can surface a
268
+ * failed Record). Throws loudly when the live `data` is unrecordable (devalue's contract) or no
269
+ * live `data` was registered (a plain-children `<Skeleton>` has none).
288
270
  */
289
271
  record: (name: string) => Promise<void>;
290
272
  /**
291
- * Record every Skeleton that currently has live `data` registered (the HUD's
292
- * single "Record fixture" button — one click captures the inputs of all mounted
293
- * render-prop Skeletons). Resolves once all writes are server-confirmed; a
294
- * rejected write surfaces to the HUD.
273
+ * Record every Skeleton that currently has live `data` registered (the HUD's single "Record
274
+ * fixture" button — one click captures the inputs of all mounted render-prop Skeletons). Resolves
275
+ * once all writes are server-confirmed; a rejected write surfaces to the HUD.
295
276
  */
296
277
  recordAll: () => Promise<void>;
297
278
  /**
298
- * Seed the store from the on-disk sidecars on boot: a `{ <name>: devalueString }`
299
- * map (the opaque strings the server serves). The client decodes each with
300
- * devalue. Existing entries are not clobbered, so a Fixture recorded this
301
- * session survives a re-seed.
279
+ * Seed the store from the on-disk sidecars on boot: a `{ <name>: devalueString }` map (the opaque
280
+ * strings the server serves). The client decodes each with devalue. Existing entries are not
281
+ * clobbered, so a Fixture recorded this session survives a re-seed.
302
282
  */
303
283
  seed: (encoded: Record<string, string>) => void;
304
284
  /** React subscription so the HUD re-renders when a Fixture is recorded or seeded. */
@@ -310,10 +290,10 @@ interface PlateCoverage {
310
290
  spans: Span[];
311
291
  }
312
292
  /**
313
- * Dev-only per-plate coverage, sourced from the committed plate files (not the
314
- * session): the breakpoints detected so far and which view spans are captured.
315
- * The HUD renders every band — covered ones lit, the rest dim — and the
316
- * capture-all sweep derives its target widths from the breakpoints.
293
+ * Dev-only per-plate coverage, sourced from the committed plate files (not the session): the
294
+ * breakpoints detected so far and which view spans are captured. The HUD renders every band —
295
+ * covered ones lit, the rest dim — and the capture-all sweep derives its target widths from the
296
+ * breakpoints.
317
297
  */
318
298
  interface CoverageStore {
319
299
  get: () => ReadonlyMap<string, PlateCoverage>;
@@ -321,9 +301,9 @@ interface CoverageStore {
321
301
  subscribe: (onChange: () => void) => () => void;
322
302
  }
323
303
  /**
324
- * Dev-only capture hook, installed by the dev client before the app boots.
325
- * Absent in production builds, so `<Skeleton>` carries zero capture weight.
326
- * `captured` returns a dispose callback (stop observing this site).
304
+ * Dev-only capture hook, installed by the dev client before the app boots. Absent in production
305
+ * builds, so `<Skeleton>` carries zero capture weight. `captured` returns a dispose callback (stop
306
+ * observing this site).
327
307
  */
328
308
  interface CaptureHook {
329
309
  captured: (name: string, el: Element, opts?: {
@@ -349,20 +329,18 @@ interface CaptureHook {
349
329
  /** Dev-only per-plate breakpoints + captured spans, from disk; fed by the bootstrap. */
350
330
  coverage?: CoverageStore;
351
331
  /**
352
- * Replay toggle (ADR 0015): when active, the dev adapter substitutes a recorded
353
- * Fixture's `data` for the live `data` at `loading=false`. The boolean is the
354
- * coarse on/off the HUD owns per tab; the per-mode policy (`prefer` vs
355
- * `missing-only`) is carried alongside in `replayMode`.
332
+ * Replay toggle (ADR 0015): when active, the dev adapter substitutes a recorded Fixture's `data`
333
+ * for the live `data` at `loading=false`. The boolean is the coarse on/off the HUD owns per tab;
334
+ * the per-mode policy (`prefer` vs `missing-only`) is carried alongside in `replayMode`.
356
335
  */
357
336
  replay?: ToggleStore;
358
337
  /** Dev-only Replay policy: how a Fixture substitutes for live `data` (ADR 0015). */
359
338
  replayMode?: 'prefer' | 'missing-only';
360
339
  /**
361
- * Dev-only Record policy (ADR 0015): when the dev adapter records the live
362
- * `data` it is about to render. `'manual'` (the default) records nothing
363
- * automatically — only the HUD button does; `'first-ready'` records once when a
364
- * Skeleton goes ready and has no Fixture yet; `'always'` records on every ready
365
- * render.
340
+ * Dev-only Record policy (ADR 0015): when the dev adapter records the live `data` it is about to
341
+ * render. `'manual'` (the default) records nothing automatically — only the HUD button does;
342
+ * `'first-ready'` records once when a Skeleton goes ready and has no Fixture yet; `'always'`
343
+ * records on every ready render.
366
344
  */
367
345
  recordMode?: 'manual' | 'first-ready' | 'always';
368
346
  /** Dev-only Fixture record/replay store (ADR 0015); never present in production. */
@@ -374,40 +352,36 @@ declare global {
374
352
  //#endregion
375
353
  //#region src/chunk.d.ts
376
354
  /**
377
- * Distinct plate names referenced by the tree's stitches, in first-seen order.
378
- * Walks a `RenderNode` tree (the stored, post-classify shape), so it drives the
379
- * gen-side stitch import graph straight off a `StoredPlate.tree`
380
- * (`renderPlateModule`, index.ts). Relocated here from the now-deleted `merge.ts`
381
- * in the ADR 0022 cutover — it is the one node-side primitive that survived the
382
- * `mergeViews`/`addCapture` removal (the multi-View merge/gate now lives in the
383
- * in-browser `serializePlateIR`, project.ts).
355
+ * Distinct plate names referenced by the tree's stitches, in first-seen order. Walks a `RenderNode`
356
+ * tree (the stored, post-classify shape), so it drives the gen-side stitch import graph straight
357
+ * off a `StoredPlate.tree` (`renderPlateModule`, index.ts). The one node-side primitive needed at
358
+ * build time; multi-View gating happens in the in-browser `serializePlateIR` (serialize.ts, ADR
359
+ * 0022).
384
360
  */
385
361
  declare function collectRefs(tree: RenderNode | null): string[];
386
362
  //#endregion
387
363
  //#region src/name.d.ts
388
364
  /**
389
- * Plate-name validation, shared by the Vite plugin (`index.ts`) and the
390
- * Node-only POST validator (`validate.ts`).
365
+ * Plate-name validation, shared by the Vite plugin (`index.ts`) and the Node-only POST validator
366
+ * (`validate.ts`).
391
367
  *
392
- * Lives in its own dependency-free module so `validate.ts` can reuse it without
393
- * importing the plugin entry (which would be a cycle), and so the regex stays
394
- * the single source of truth for what a plate name may be — the same rule the
395
- * loader, the file watcher, the coverage reader, the POST endpoint, and the
396
- * ref-graph emitter all gate on.
368
+ * Lives in its own dependency-free module so `validate.ts` can reuse it without importing the
369
+ * plugin entry (which would be a cycle), and so the regex stays the single source of truth for what
370
+ * a plate name may be — the same rule the loader, the file watcher, the coverage reader, the POST
371
+ * endpoint, and the ref-graph emitter all gate on.
397
372
  *
398
373
  * @module
399
374
  */
400
375
  /**
401
376
  * Names come from import specifiers and POST bodies — keep them inside the plates dir.
402
377
  *
403
- * Each path segment is `\w+(-\w+)*` — word chars with single interior hyphens,
404
- * never doubled and never at a segment edge — and segments are joined by `/`.
405
- * The class-prefix encoder (`classify.ts`) renders `/` as `--` to keep nested
406
- * names readable, and that prefix is the isolation boundary across stitched
407
- * plates (ADR 0007), so the encoding must be injective. Banning a literal `--`
408
- * and any edge hyphen guarantees no `-` ever abuts a `/`, so every `--` in the
409
- * prefix came from exactly one `/` making distinct names always map to
410
- * distinct prefixes (else e.g. `a/-b` and `a-/b` would both encode to `a---b`).
378
+ * Each path segment is `\w+(-\w+)*` — word chars with single interior hyphens, never doubled and
379
+ * never at a segment edge — and segments are joined by `/`. The class-prefix encoder
380
+ * (`classify.ts`) renders `/` as `--` to keep nested names readable, and that prefix is the
381
+ * isolation boundary across stitched plates (ADR 0007), so the encoding must be injective. Banning
382
+ * a literal `--` and any edge hyphen guarantees no `-` ever abuts a `/`, so every `--` in the
383
+ * prefix came from exactly one `/` making distinct names always map to distinct prefixes (else
384
+ * e.g. `a/-b` and `a-/b` would both encode to `a---b`).
411
385
  *
412
386
  * @internal
413
387
  */
@@ -418,32 +392,38 @@ declare function isValidPlateName(name: string): boolean;
418
392
  * Options for `xrayVitePlugin()`.
419
393
  *
420
394
  * Fixed conventions are intentionally not configurable: Plate names come from
421
- * `virtual:xray/plates/<name>`, files live under `platesDir`, and responsive
422
- * breakpoints are derived from captured CSS plus the `matchMedia` queries the
423
- * page evaluates.
395
+ * `virtual:xray/plates/<name>`, files live under `platesDir`, and responsive breakpoints are
396
+ * derived from captured CSS plus the `matchMedia` queries the page evaluates.
424
397
  */
425
398
  interface XrayOptions {
426
- /** Directory where Plate JSON files are written and read, relative to the Vite root. Default: `plates`. */
399
+ /**
400
+ * Directory where Plate JSON files are written and read, relative to the Vite root. Default:
401
+ * `plates`.
402
+ */
427
403
  platesDir?: string;
428
404
  /** Mount the dev HUD for coverage, Capture, Light Box, and capture-all controls. Default: `false`. */
429
405
  hud?: boolean;
430
406
  /**
431
- * Initial state of the browse-time Capture toggle in dev. Keep this off for
432
- * normal browsing and let the HUD, capture-all flow, or `?xray-capture` turn
433
- * Capture on per tab. Default: `false`.
407
+ * Initial state of the browse-time Capture toggle in dev. Keep this off for normal browsing and
408
+ * let the HUD, capture-all flow, or `?xray-capture` turn Capture on per tab. Default: `false`.
434
409
  */
435
410
  capture?: boolean;
436
- /** Settle delay in milliseconds before capturing a ready Skeleton; override one boundary with the `delay` prop. Default: `200`. */
411
+ /**
412
+ * Settle delay in milliseconds before capturing a ready Skeleton; override one boundary with the
413
+ * `delay` prop. Default: `200`.
414
+ */
437
415
  delay?: number;
438
- /** Upper bound in milliseconds on waiting for a busy subtree to go quiet before capturing anyway. Default: `5000`. */
416
+ /**
417
+ * Upper bound in milliseconds on waiting for a busy subtree to go quiet before capturing anyway.
418
+ * Default: `5000`.
419
+ */
439
420
  settleCap?: number;
440
421
  /**
441
- * Collect-stage limits (ADR 0022): refuse to capture a boundary whose measured
442
- * tree exceeds any axis — too big means the Skeleton sits too high in the tree.
443
- * `maxNodes` caps total surviving nodes (default `4096`), `maxBreadth` the widest
444
- * level (default `512`), `maxDepth` the nesting depth (default `32`). Omit
445
- * `maxNodes` and it derives as `round(maxBreadth × maxDepth / 4)`. Override one
446
- * boundary with the flat `maxNodes`/`maxBreadth`/`maxDepth` `<Skeleton>` props.
422
+ * Collect-stage limits (ADR 0022): refuse to capture a boundary whose measured tree exceeds any
423
+ * axis — too big means the Skeleton sits too high in the tree. `maxNodes` caps total surviving
424
+ * nodes (default `4096`), `maxBreadth` the widest level (default `512`), `maxDepth` the nesting
425
+ * depth (default `32`). Omit `maxNodes` and it derives as `round(maxBreadth × maxDepth / 4)`.
426
+ * Override one boundary with the flat `maxNodes`/`maxBreadth`/`maxDepth` `<Skeleton>` props.
447
427
  */
448
428
  collect?: {
449
429
  maxNodes?: number;
@@ -452,31 +432,30 @@ interface XrayOptions {
452
432
  };
453
433
  /**
454
434
  * Dev-only Fixtures (ADR 0015): record a `<Skeleton>`'s render-input `data` to a
455
- * `plates/<name>.fixture.json` sidecar and replay it in place of live data so
456
- * capture is deterministic. Boot state only — the HUD is per-tab authority, just
457
- * like `capture`. Entirely dev-only; nothing here ships in production.
435
+ * `plates/<name>.fixture.json` sidecar and replay it in place of live data so capture is
436
+ * deterministic. Boot state only — the HUD is per-tab authority, just like `capture`. Entirely
437
+ * dev-only; nothing here ships in production.
458
438
  */
459
439
  fixtures?: {
460
440
  /**
461
- * When to record the live `data`: `'manual'` (HUD button only — the default,
462
- * so live app data is never silently committed), `'first-ready'` (record once
463
- * the first time a Skeleton goes ready with no Fixture yet), or `'always'`
464
- * (record on every ready render). Default: `'manual'`.
441
+ * When to record the live `data`: `'manual'` (HUD button only — the default, so live app data
442
+ * is never silently committed), `'first-ready'` (record once the first time a Skeleton goes
443
+ * ready with no Fixture yet), or `'always'` (record on every ready render). Default:
444
+ * `'manual'`.
465
445
  */
466
446
  record?: 'manual' | 'first-ready' | 'always';
467
447
  /**
468
- * Whether to replay a recorded Fixture in place of live `data`: `false` (off,
469
- * the default), `'prefer'` (always use the Fixture when one exists), or
470
- * `'missing-only'` (use the Fixture only when live `data` is nullish —
471
- * `missing nullish`, so an empty array/object is present and stays
472
- * capturable). Default: `false`.
448
+ * Whether to replay a recorded Fixture in place of live `data`: `false` (off, the default),
449
+ * `'prefer'` (always use the Fixture when one exists), or `'missing-only'` (use the Fixture
450
+ * only when live `data` is nullish — `missing ≡ nullish`, so an empty array/object is present
451
+ * and stays capturable). Default: `false`.
473
452
  */
474
453
  replay?: false | 'prefer' | 'missing-only';
475
454
  };
476
455
  }
477
456
  /**
478
- * Create the Vite plugins that resolve committed Plates and, during dev,
479
- * capture new Plates from rendered `<Skeleton>` boundaries.
457
+ * Create the Vite plugins that resolve committed Plates and, during dev, capture new Plates from
458
+ * rendered `<Skeleton>` boundaries.
480
459
  *
481
460
  * Typical setup:
482
461
  *
@@ -489,8 +468,10 @@ interface XrayOptions {
489
468
  * ```
490
469
  *
491
470
  * Returns two plugins:
471
+ *
492
472
  * - `xray:data` resolves `virtual:xray/plates/<name>` from committed Plate files in dev and build.
493
- * - `xray:dev` runs only during `vite serve`; it injects the capture client, receives Captures, writes Plate files, and hot-updates the page.
473
+ * - `xray:dev` runs only during `vite serve`; it injects the capture client, receives Captures,
474
+ * writes Plate files, and hot-updates the page.
494
475
  */
495
476
  declare function xrayVitePlugin(options?: XrayOptions): Plugin[];
496
477
  interface CaptureRequest {
@@ -507,29 +488,26 @@ interface CaptureResponse {
507
488
  interface PlateBroadcaster {
508
489
  send(payload: unknown): void;
509
490
  }
510
- /** The subset of Vite's logger we use; it preserves the formatted string verbatim. */
491
+ /** The subset of Vite's logger used here; it preserves the formatted string verbatim. */
511
492
  interface ServerLogger {
512
493
  warn(message: string): void;
513
494
  }
514
495
  interface CaptureServer {
515
496
  ws: PlateBroadcaster;
516
497
  /**
517
- * Vite's logger (`server.config.logger`). When present its `warn` prints the
518
- * diagnostic text to the server output; otherwise we fall back to
519
- * `console.warn`. Either way the SAME shared formatter (diagnostics.ts) is
520
- * used, so server output matches the browser console exactly.
498
+ * Vite's logger (`server.config.logger`). When present its `warn` prints the diagnostic text to
499
+ * the server output; otherwise `console.warn` is the fallback. Either way the SAME shared
500
+ * formatter (diagnostics.ts) is used, so server output matches the browser console exactly.
521
501
  */
522
502
  config?: {
523
503
  logger?: ServerLogger;
524
504
  };
525
505
  /**
526
- * The subset of Vite's dev server needed to keep BOTH of a plate's virtual
527
- * modules fresh after a plate file changes (capture POST, hand edit, git
528
- * checkout). Optional — absent in the unit tests that stub a minimal
529
- * `server`. `getModuleById`/`invalidateModule`/`reloadModule` mirror
530
- * `ViteDevServer`'s real shape (a subset, so this module stays free of a
531
- * hard `vite` import at the type level beyond the `Plugin` type already
532
- * used elsewhere).
506
+ * The subset of Vite's dev server needed to keep BOTH of a plate's virtual modules fresh after a
507
+ * plate file changes (capture POST, hand edit, git checkout). Optional — absent in the unit tests
508
+ * that stub a minimal `server`. `getModuleById`/`invalidateModule`/`reloadModule` mirror
509
+ * `ViteDevServer`'s real shape (a subset, so this module stays free of a hard `vite` import at
510
+ * the type level beyond the `Plugin` type already used elsewhere).
533
511
  */
534
512
  moduleGraph?: {
535
513
  getModuleById(id: string): unknown;
@@ -538,10 +516,9 @@ interface CaptureServer {
538
516
  reloadModule?(mod: unknown): Promise<void>;
539
517
  }
540
518
  /**
541
- * Per-plate breakpoints + derived coverage bands, read from the committed
542
- * StoredPlate files. The `spans` derive from each plate's `breakpoints` (ADR 0022
543
- * cutover per-View spans no longer exist on disk; a StoredPlate sweeps all
544
- * widths in one session, so its coverage is complete).
519
+ * Per-plate breakpoints + derived coverage bands, read from the committed StoredPlate files. The
520
+ * `spans` derive from each plate's `breakpoints` (ADR 0022: a StoredPlate sweeps all widths in one
521
+ * session, so its coverage is complete).
545
522
  *
546
523
  * @internal
547
524
  */
@@ -550,53 +527,47 @@ declare function readCoverage(dir: string): Record<string, {
550
527
  spans: Span[];
551
528
  }>;
552
529
  /**
553
- * All recorded Fixtures as `{ <name>: <devalueString> }`, read from the
554
- * `<name>.fixture.json` sidecars (ADR 0015). The map values are the OPAQUE
555
- * devalue strings exactly as written the node side never parses them; the
556
- * browser dev client owns the devalue decode. The `.fixture.json` suffix keeps
557
- * these distinct from Plate files (`isValidPlateName` rejects the dotted name, so
530
+ * All recorded Fixtures as `{ <name>: <devalueString> }`, read from the `<name>.fixture.json`
531
+ * sidecars (ADR 0015). The map values are the OPAQUE devalue strings exactly as written — the node
532
+ * side never parses them; the browser dev client owns the devalue decode. The `.fixture.json`
533
+ * suffix keeps these distinct from Plate files (`isValidPlateName` rejects the dotted name, so
558
534
  * `readCoverage` never picks them up — Fixtures never leak into Plate coverage).
559
535
  *
560
536
  * @internal
561
537
  */
562
538
  declare function readFixtures(dir: string): Record<string, string>;
563
539
  /**
564
- * Write a recorded Fixture sidecar (ADR 0015). Reuses the capture endpoint's
565
- * front-door checks (method, content type, declared/streamed size cap) and the
566
- * `isValidPlateName` gate, but treats the devalue `data` payload as OPAQUE TEXT:
567
- * it is validated only as a string and written verbatim, never eval'd or parsed
568
- * server-side. The sidecar lives NEXT TO the Plate but is never merged into it,
569
- * so the persisted Plate stays purely structural.
540
+ * Write a recorded Fixture sidecar (ADR 0015). Reuses the capture endpoint's front-door checks
541
+ * (method, content type, declared/streamed size cap) and the `isValidPlateName` gate, but treats
542
+ * the devalue `data` payload as OPAQUE TEXT: it is validated only as a string and written verbatim,
543
+ * never eval'd or parsed server-side. The sidecar lives NEXT TO the Plate but is never merged into
544
+ * it, so the persisted Plate stays purely structural.
570
545
  *
571
546
  * @internal
572
547
  */
573
548
  declare function handleFixturePost(req: CaptureRequest, res: CaptureResponse, fixturePath: (name: string) => string): void;
574
549
  /**
575
- * Validate a posted `StoredPlate` envelope, write it AS-IS, and hot-swap the
576
- * plate in place. After the ADR 0022 cutover the dev client posts a finished
577
- * StoredPlate (the whole Plate already projected in the browser) inside a
578
- * `{ plate, diagnostics? }` envelope there is NO server-side accumulation/merge
579
- * anymore. `diagnostics` is a SIBLING field the server logs and then drops; it
580
- * never reaches the stored artifact (ADR 0008).
550
+ * Validate a posted `StoredPlate` envelope, write it AS-IS, and hot-swap the plate in place. The
551
+ * dev client posts a finished StoredPlate (the whole Plate already projected in the browser, ADR
552
+ * 0022) inside a `{ plate, diagnostics? }` envelope; there is NO server-side accumulation/merge.
553
+ * `diagnostics` is a SIBLING field the server logs and then drops; it never reaches the stored
554
+ * artifact (ADR 0008).
581
555
  *
582
556
  * @internal
583
557
  */
584
558
  declare function handleCapturePost(req: CaptureRequest, res: CaptureResponse, server: CaptureServer, platePath: (name: string) => string): void;
585
559
  /**
586
- * Render a plate as the virtual module's source. Each stitch (`ref` node) becomes
587
- * a real import of that child's virtual module, wired into a `refs` map on the
588
- * default export so the bundler builds the actual reference graph and chunks
589
- * the transitive closure a page uses, with no runtime registry (ADR 0006). A
590
- * stitchless plate is just its JSON. Self-references are dropped (a module can't
591
- * import itself); an unknown child resolves to its own empty plate, never a
592
- * build break.
560
+ * Render a plate as the virtual module's source. Each stitch (`ref` node) becomes a real import of
561
+ * that child's virtual module, wired into a `refs` map on the default export — so the bundler
562
+ * builds the actual reference graph and chunks the transitive closure a page uses, with no runtime
563
+ * registry (ADR 0006). A stitchless plate is just its JSON. Self-references are dropped (a module
564
+ * can't import itself); an unknown child resolves to its own empty plate, never a build break.
593
565
  *
594
- * `name` defaults to the plate's own `name`, but the loader passes the
595
- * PATH-derived name so a hand-edited StoredPlate whose `name` field drifted from
596
- * its filename still serializes and self-references under the canonical name
597
- * (`collectRefs` reads `stored.tree`, a RenderNode, unchanged by the cutover).
566
+ * `name` defaults to the plate's own `name`, but the loader passes the PATH-derived name so a
567
+ * hand-edited StoredPlate whose `name` field drifted from its filename still serializes and
568
+ * self-references under the canonical name (`collectRefs` reads `stored.tree`, a RenderNode).
598
569
  *
599
- * Two-artifact module shape (plan 005 round 2):
570
+ * Two-artifact module shape (ADR 0026):
600
571
  *
601
572
  * ```js
602
573
  * import "virtual:xray/base.css"
@@ -605,29 +576,25 @@ declare function handleCapturePost(req: CaptureRequest, res: CaptureResponse, se
605
576
  * export const css = "<the plate's scoped css string>"
606
577
  * ```
607
578
  *
608
- * The default export is the TREE artifact (`Plate` carries no css field
609
- * anymore); the page's styling flows through Vite's own CSS pipeline via the
610
- * two side-effect imports (dev inject + HMR, build extraction into the
611
- * chunk's `.css` asset). `export const css` is the plate's css as data, for
612
- * dev tooling / programmatic consumers that want the string itself
613
- * production adapters import only the default, so Rollup TREE-SHAKES the
614
- * unused named export out of built chunks (verified empirically in the plan's
615
- * scratch app; the side-effect css imports do not pin it).
579
+ * The default export is the TREE artifact (`Plate` carries no css field); the page's styling flows
580
+ * through Vite's own CSS pipeline via the two side-effect imports (dev inject + HMR, build
581
+ * extraction into the chunk's `.css` asset). `export const css` is the plate's css as data, for dev
582
+ * tooling / programmatic consumers that want the string itself production adapters import only
583
+ * the default, so Rollup TREE-SHAKES the unused named export out of built chunks (verified
584
+ * empirically; the side-effect css imports do not pin it).
616
585
  *
617
- * BASE_CSS rides as a JS-level import of the SHARED `virtual:xray/base.css`
618
- * module (not an `@import` inside each plate's css): Vite dedupes JS module
619
- * imports by id, so the base rules reach the page exactly once no matter how
620
- * many plates (nested/stitched included every plate module emits this
621
- * import, module identity collapses them) a page mounts, and at build a
622
- * multi-chunk app gets it hoisted/shared rather than copied per chunk. An
623
- * `@import` inside each plate's `.css` would instead be INLINED per importer
624
- * by Vite's postcss-import at build, duplicating BASE_CSS into every plate's
625
- * asset — the opposite of the dedupe this design locks in. Base rides before
626
- * the plate's css module so a plate rule still beats a base rule at equal
627
- * specificity by source order (the old inline `${BASE_CSS}\n${css}` order).
586
+ * BASE_CSS rides as a JS-level import of the SHARED `virtual:xray/base.css` module (not an
587
+ * `@import` inside each plate's css): Vite dedupes JS module imports by id, so the base rules reach
588
+ * the page exactly once no matter how many plates (nested/stitched included every plate module
589
+ * emits this import, module identity collapses them) a page mounts, and at build a multi-chunk app
590
+ * gets it hoisted/shared rather than copied per chunk. An `@import` inside each plate's `.css`
591
+ * would instead be INLINED per importer by Vite's postcss-import at build, duplicating BASE_CSS
592
+ * into every plate's asset the opposite of the dedupe this design locks in. Base rides before the
593
+ * plate's css module so a plate rule still beats a base rule at equal specificity by source order
594
+ * (the `${BASE_CSS}\n${css}` composition order).
628
595
  *
629
596
  * @internal
630
597
  */
631
- declare function renderPlateModule(merged: MergedPlate, name?: string): string;
598
+ declare function renderPlateModule(merged: GatedPlate, name?: string): string;
632
599
  //#endregion
633
600
  export { type LeafKind, type Plate, type PlateNode, type PlateRule, type StoredPlate, type ViewCapture, XrayOptions, collectRefs, handleCapturePost, handleFixturePost, isValidPlateName, readCoverage, readFixtures, renderPlateModule, xrayVitePlugin };