@ai-matrx/content-ir-react 0.1.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.
@@ -0,0 +1,782 @@
1
+ import * as react from 'react';
2
+ import react__default, { ReactNode } from 'react';
3
+ import { KindDefinition, CanonicalBlockIR, PartialKindEvent } from '@ai-matrx/content-ir';
4
+
5
+ /**
6
+ * THE SCREAM SEAM.
7
+ *
8
+ * Every recovery path in this package is loud: a defective component row, a
9
+ * failed resolver load, a kind whose component throws on a provisional value.
10
+ * The package refuses to own where those screams land — matrx-frontend routes
11
+ * them to the Error Inspector, the dashboard to its own log, the extension to
12
+ * its background page. Each host binds one function.
13
+ *
14
+ * A host that binds a no-op has chosen silence, which is a defect in itself;
15
+ * {@link consoleErrorReporter} is the honest default.
16
+ */
17
+ interface ContentIrErrorReport {
18
+ /** Always `"content-ir"` — hosts key their capture stores on it. */
19
+ source: "content-ir";
20
+ message: string;
21
+ name?: string;
22
+ stack?: string;
23
+ /** Free-form grouping key (the host's `relation`), e.g. `"partial-kind"`. */
24
+ relation?: string;
25
+ raw?: unknown;
26
+ }
27
+ type ContentIrErrorReporter = (report: ContentIrErrorReport) => void;
28
+ /** The default when a host binds nothing: never silent. */
29
+ declare const consoleErrorReporter: ContentIrErrorReporter;
30
+
31
+ /**
32
+ * The (kind, platform, role) → component vocabulary — the Shape System's
33
+ * resolver contract (rulings R1 + R6), stated once for every UI.
34
+ *
35
+ * Cross-repo system-of-record:
36
+ * `common-docs/systems/content-ir-twin/FEATURE.md` (package boundary) and
37
+ * `matrx-frontend/features/content-ir/docs/SHAPE_SYSTEM.md` (the semantics).
38
+ *
39
+ * Nothing here knows where a row comes from. A host supplies rows from
40
+ * `content_ir.kind_component` (Supabase, a REST call, a fixture); the resolver
41
+ * only knows the shape.
42
+ */
43
+ /** JSON object, restated locally so this package depends on no host type. */
44
+ type JsonObject = Record<string, unknown>;
45
+ /** Which half of the shape a component draws. */
46
+ type ComponentRole = "output" | "input";
47
+ /**
48
+ * One `content_ir.kind_component` row, projected to exactly what rendering
49
+ * needs. Hosts map their own query result onto this.
50
+ */
51
+ interface KindComponentRow {
52
+ kind: string;
53
+ platform: string;
54
+ role: ComponentRole;
55
+ componentKey: string;
56
+ /** `source` column vocabulary: "bundled" | "db" (db = web sandbox only). */
57
+ source: string;
58
+ config: JsonObject;
59
+ isActive: boolean;
60
+ componentSource: string | null;
61
+ propsTransform: string | null;
62
+ pinnedKindVersion: number | null;
63
+ updatedAt: string | null;
64
+ createdBy: string | null;
65
+ }
66
+ /**
67
+ * One COMPILED bootstrap entry — the trusted-at-boot floor a host ships in its
68
+ * bundle, available synchronously from the first streamed byte.
69
+ */
70
+ interface SystemComponentEntry {
71
+ kind: string;
72
+ platform: string;
73
+ role: ComponentRole;
74
+ componentKey: string;
75
+ source: string;
76
+ config: JsonObject;
77
+ }
78
+ /** The resolver's answer for one (kind, platform, role). */
79
+ interface ComponentResolution {
80
+ /** The component key the renderer routes on (e.g. "flashcards"). */
81
+ componentKey: string;
82
+ source: string;
83
+ config: JsonObject;
84
+ /**
85
+ * Render-trust verdict (R6). Compiled entries are always active (trusted at
86
+ * bootstrap); DB rows carry their own `is_active`.
87
+ */
88
+ isActive: boolean;
89
+ /** Which tier produced this answer — the verification hook's `by`. */
90
+ resolvedBy: "compiled" | "db";
91
+ componentSource: string | null;
92
+ propsTransform: string | null;
93
+ pinnedKindVersion: number | null;
94
+ /** The db row's `updated_at` — the compile-cache staleness key. */
95
+ updatedAt: string | null;
96
+ createdBy: string | null;
97
+ }
98
+ /**
99
+ * The read side of a component resolver, as the render layer consumes it.
100
+ * The package ships {@link ComponentResolver}; a host with its own resolver
101
+ * only has to satisfy this.
102
+ */
103
+ interface ComponentResolutionSource {
104
+ /** Synchronous — the render seam's per-block call. */
105
+ resolve(kind: string, platform: string, role: ComponentRole): ComponentResolution | null;
106
+ /** Eager targeted fetch for one kind; fire-and-forget, never awaited on the hot path. */
107
+ requestComponent(kind: string, platform: string, role: ComponentRole): void;
108
+ /** One list fetch per session. */
109
+ ensureWarm(): Promise<void>;
110
+ /** Refresh-on-view; rate-limited and deduped by the implementation. */
111
+ refresh(maxAgeMs?: number): Promise<void>;
112
+ /** Monotonic tier version — has anything at all changed? */
113
+ getVersion(): number;
114
+ /** Monotonic per-kind version (+ wholesale epoch) — the granular repaint key. */
115
+ getKindVersion(kind: string): number;
116
+ subscribe(listener: () => void): () => void;
117
+ subscribeKind(kind: string, listener: () => void): () => void;
118
+ }
119
+
120
+ /**
121
+ * THE HOST CONTRACT — everything this package refuses to decide.
122
+ *
123
+ * The kernel (`@ai-matrx/content-ir`) proved the shape: extract the portable
124
+ * part, let host capability enter through explicit named seams. The render
125
+ * layer needs four things it must never own:
126
+ *
127
+ * 1. WHERE KIND DEFINITIONS COME FROM (a bundled table, `content_ir`, a REST
128
+ * call). The route only asks "is this kind registered, and does it carry a
129
+ * legacy bridge / a partial-ready opt-in".
130
+ * 2. WHERE COMPONENT ROWS COME FROM — {@link ComponentResolutionSource}. The
131
+ * package ships `ComponentResolver`, which any host can construct with its
132
+ * own loaders; a host with its own resolver only has to satisfy the type.
133
+ * 3. HOW A ROUTED BLOCK ACTUALLY DRAWS. `applyIrKindRoute` decides a block's
134
+ * TYPE; turning that type into pixels is the host's dispatch table
135
+ * (matrx-frontend's `BlockRenderer`, the dashboard's small map). The
136
+ * package never imports a component library.
137
+ * 4. WHERE SCREAMS LAND — {@link ContentIrErrorReporter}.
138
+ *
139
+ * No Next.js, no Redux, no Supabase, no router, no host error capture. If a
140
+ * seam is missing, ADD A SEAM — never an import.
141
+ */
142
+
143
+ /**
144
+ * The minimum a render block must expose for the kind route to work. Hosts
145
+ * pass their own richer block type through; the route is generic over `T` and
146
+ * preserves every extra field.
147
+ */
148
+ interface IrRoutableBlock {
149
+ type: string;
150
+ serverData?: Record<string, unknown>;
151
+ metadata?: Record<string, unknown>;
152
+ }
153
+ /** A routable block that also carries its source text (the raw region). */
154
+ interface IrRenderBlock extends IrRoutableBlock {
155
+ content: string;
156
+ language?: string;
157
+ }
158
+ /**
159
+ * Where registered kinds come from. `getDefinition` is the only method the
160
+ * pure route needs; the rest drive the granular repaint and the warm-up tick
161
+ * that keeps a cold registry from being mistaken for "this kind has no
162
+ * component".
163
+ */
164
+ interface KindDefinitionSource {
165
+ getDefinition(kind: string): KindDefinition | undefined;
166
+ /** Monotonic per-kind version — the repaint snapshot key. */
167
+ getKindVersion(kind: string): number;
168
+ subscribeKind(kind: string, listener: () => void): () => void;
169
+ /** One definition load per app session. */
170
+ ensureWarm(): Promise<void>;
171
+ }
172
+ /**
173
+ * The rendering seams. Everything here returns host UI; the package supplies
174
+ * the DECISIONS and the chrome-free structure around them.
175
+ */
176
+ interface ContentIrRenderSeams {
177
+ /**
178
+ * Draw a block the kind route has already typed. This is the host's dispatch
179
+ * table — the single place a component key becomes a component.
180
+ */
181
+ renderBlock(block: IrRenderBlock): ReactNode;
182
+ /**
183
+ * THE FLOOR: render ANY JSON value as a human document. Reached when a kind
184
+ * has no render-trusted component, when the value is not an object at all,
185
+ * and by the generic structured view.
186
+ *
187
+ * This is deliberately a seam and not a bundled component. Rendering a value
188
+ * WELL means prose through the host's markdown renderer, media through the
189
+ * host's file handler, and uniform arrays through the host's data table —
190
+ * all of which are host property. A host that has none of those can pass a
191
+ * `<pre>`; it will be honest, just plain.
192
+ */
193
+ renderValue(props: StructuredValueRenderProps): ReactNode;
194
+ /**
195
+ * The "still arriving" indicator used by the provisional frame. Optional —
196
+ * hosts without a shimmer get plain text.
197
+ */
198
+ renderShimmer?(text: string): ReactNode;
199
+ /**
200
+ * The honest "this shape has no custom component yet" notice. Optional: the
201
+ * package draws a plain amber line when a host supplies nothing, and a host
202
+ * with an icon set or its own callout component supplies that instead. It is
203
+ * a seam and not a bundled component because this package depends on no icon
204
+ * library.
205
+ */
206
+ renderNotice?(text: string): ReactNode;
207
+ }
208
+ interface StructuredValueRenderProps {
209
+ value: unknown;
210
+ /** The kind slug this value claims, when known. Honesty line only — never a renderer choice. */
211
+ kind?: string;
212
+ /** Why this shape has no custom view, in human words. */
213
+ note?: string;
214
+ /** Show the "what this is / raw data" footer. Default true. */
215
+ footer?: boolean;
216
+ }
217
+ /**
218
+ * One host, wired once, read by every component in this package through
219
+ * {@link ContentIrRenderProvider}.
220
+ */
221
+ interface ContentIrHost extends ContentIrRenderSeams {
222
+ kinds: KindDefinitionSource;
223
+ components: ComponentResolutionSource;
224
+ reportError: ContentIrErrorReporter;
225
+ /**
226
+ * The `kind_component.platform` this host resolves as. "web" for every
227
+ * browser UI; the column already models "react-native" and friends, and a
228
+ * host that lies here renders the wrong component everywhere.
229
+ */
230
+ platform: string;
231
+ }
232
+ /**
233
+ * The pure route's dependencies — a strict subset of {@link ContentIrHost},
234
+ * because `applyIrKindRoute` is called OUTSIDE React (reducers, stream
235
+ * accumulators, tests) where there is no provider to read.
236
+ */
237
+ interface KindRouteEnv {
238
+ kinds: Pick<KindDefinitionSource, "getDefinition">;
239
+ components: Pick<ComponentResolutionSource, "resolve">;
240
+ reportError: ContentIrErrorReporter;
241
+ platform: string;
242
+ }
243
+ /** Narrow a host (or anything host-shaped) to what the pure route needs. */
244
+ declare function routeEnvOf(host: ContentIrHost): KindRouteEnv;
245
+
246
+ interface ContentIrRenderProviderProps {
247
+ host: ContentIrHost;
248
+ children: ReactNode;
249
+ }
250
+ declare function ContentIrRenderProvider({ host, children, }: ContentIrRenderProviderProps): react.JSX.Element;
251
+ /**
252
+ * The wired host, or null. For the rare consumer that can legitimately run
253
+ * without a provider because it was handed its sources explicitly (see
254
+ * `useContentIrKindVersion`). Everything else uses {@link useContentIrHost}.
255
+ */
256
+ declare function useContentIrHostOrNull(): ContentIrHost | null;
257
+ /** The wired host. Throws outside a provider — see the module doc. */
258
+ declare function useContentIrHost(): ContentIrHost;
259
+ /** The wired host narrowed to what the pure route functions take. */
260
+ declare function useKindRouteEnv(): KindRouteEnv;
261
+
262
+ /**
263
+ * The Shape System component RESOLVER (rulings R1 + R6): (kind, platform,
264
+ * role) → component, with two tiers:
265
+ *
266
+ * - eager: a COMPILED bootstrap the host ships in its bundle — the
267
+ * trusted-at-boot floor, available at import so the render seam can gate
268
+ * synchronously from the first streamed byte.
269
+ * - warm: one `content_ir.kind_component` list fetch per app session
270
+ * (`ensureWarm`). A DB row for a (kind, platform, role) OVERRIDES the
271
+ * compiled entry once warm; the compiled floor keeps answering until then
272
+ * (and forever, on DB failure).
273
+ *
274
+ * Resolution is SYNCHRONOUS (the render seam calls it per block); the only
275
+ * async work is the loading, off the render path.
276
+ *
277
+ * WHAT MOVED AND WHY. This class was matrx-frontend's `ComponentRegistry`. It
278
+ * is a large part of why a second UI could not render a kind: every tier rule,
279
+ * every repaint counter, every dedupe latch lived in one app. Nothing about it
280
+ * is Next.js, Redux, or Supabase — the only host-specific parts were the two
281
+ * loaders and the error sink, which are now constructor arguments.
282
+ */
283
+
284
+ interface ComponentResolverOptions {
285
+ /**
286
+ * The compiled bootstrap, as a THUNK resolved on first use: a host's system
287
+ * component table is often mid-initialization when this module evaluates
288
+ * (matrx-frontend's registry cluster has a deliberate import cycle).
289
+ */
290
+ compiledEntries?: () => SystemComponentEntry[];
291
+ /** The warm/refresh list load — every `kind_component` row the user may see. */
292
+ loadAll?: () => Promise<KindComponentRow[]>;
293
+ /** The eager single-kind load fired the moment a kind is identified mid-stream. */
294
+ loadForKind?: (kind: string, platform: string) => Promise<KindComponentRow[]>;
295
+ /** Where recovery screams land. Defaults to `console.error`, never silence. */
296
+ reportError?: ContentIrErrorReporter;
297
+ /** Clock seam — the refresh rate limiter. Defaults to `Date.now`. */
298
+ now?: () => number;
299
+ }
300
+ declare class ComponentResolver implements ComponentResolutionSource {
301
+ private compiled;
302
+ private readonly db;
303
+ private warmPromise;
304
+ private warmFailureLogged;
305
+ /**
306
+ * When the last successful wholesale refresh landed, or null for "never".
307
+ * Explicitly nullable rather than 0: with a host-supplied clock that starts
308
+ * near zero, a `0` sentinel makes the FIRST refresh look rate-limited and
309
+ * silently skip.
310
+ */
311
+ private lastRefreshAt;
312
+ private refreshPromise;
313
+ private readonly listeners;
314
+ /**
315
+ * Cold single-kind fetch dedupe (streaming eager path). In-flight is keyed
316
+ * by (kind, platform) — the fetch unit; misses are keyed by (kind, platform,
317
+ * role) so a miss on web/output never suppresses other roles, and CLEARED on
318
+ * every wholesale refresh (a component created mid-session becomes eagerly
319
+ * fetchable again — misses are cheap to re-verify).
320
+ */
321
+ private readonly coldInFlight;
322
+ private readonly coldMisses;
323
+ /** Monotonic db-tier version — the repaint hook's snapshot key. */
324
+ private version;
325
+ /** Per-kind versions + listeners (granular repaint) + wholesale epoch. */
326
+ private readonly kindVersions;
327
+ private readonly kindListeners;
328
+ private epoch;
329
+ private readonly reportError;
330
+ private readonly now;
331
+ private readonly options;
332
+ constructor(options?: ComponentResolverOptions);
333
+ private compiledMap;
334
+ /**
335
+ * Synchronous resolve — the render seam's per-block call. DB override first
336
+ * (once warm), compiled floor second, null for unknown.
337
+ */
338
+ resolve(kind: string, platform: string, role: ComponentRole): ComponentResolution | null;
339
+ /** R6 floor check: compiled-bootstrap membership = always render-trusted. */
340
+ hasCompiled(kind: string, platform: string, role: ComponentRole): boolean;
341
+ /**
342
+ * Pure ingest — the warm landing point and the unit-test seam. First row per
343
+ * key wins: rows arrive is_default-first / sort_order-asc from the source.
344
+ */
345
+ ingestDbRows(rows: readonly KindComponentRow[]): void;
346
+ /**
347
+ * Refresh landing point: REPLACE the db tier wholesale (same
348
+ * first-row-per-key contract as {@link ingestDbRows}) so edits, deletions,
349
+ * and is_active flips all take effect. Always notifies.
350
+ */
351
+ replaceDbRows(rows: readonly KindComponentRow[]): void;
352
+ getVersion(): number;
353
+ getKindVersion(kind: string): number;
354
+ subscribeKind(kind: string, listener: () => void): () => void;
355
+ subscribe(listener: () => void): () => void;
356
+ private bumpKind;
357
+ private notifyChanged;
358
+ /**
359
+ * The eager lightweight single-kind fetch (streaming path): the moment a
360
+ * cloud kind is identified mid-stream, pull ONLY that kind's resolver rows
361
+ * and ingest them so {@link resolve} can answer before — or shortly after —
362
+ * the region completes. Deduped in-flight and by known-miss. Fire-and-forget;
363
+ * failures are loud (the warm list remains the backstop).
364
+ */
365
+ requestComponent(kind: string, platform: string, role: ComponentRole): void;
366
+ /**
367
+ * Refresh-on-view: re-fetch the warm list and REPLACE the db tier, so an
368
+ * edited `source='db'` component (its `updated_at` bump re-keys the host's
369
+ * compile cache) renders fresh on the next view. Deduped in-flight and
370
+ * rate-limited by `maxAgeMs` (default 10s) — mounting several previews costs
371
+ * one fetch. Server-side edits do NOT push to open clients; the contract is
372
+ * refresh-on-view via this call.
373
+ */
374
+ refresh(maxAgeMs?: number): Promise<void>;
375
+ /** One list fetch per app session; failed loads retry on the next call. */
376
+ ensureWarm(): Promise<void>;
377
+ }
378
+
379
+ /**
380
+ * THE KIND ROUTE — the render flip, as a pure block transform.
381
+ *
382
+ * A block whose `metadata.__ir` envelope resolved a REGISTERED kind is routed
383
+ * to that kind's component: via the legacy-bridge facet (`legacyBlockType` +
384
+ * `toLegacyServerData`) when the kind has one, so the block enters the host's
385
+ * existing renderer as its real type with envelope-derived serverData;
386
+ * otherwise via the component resolver. Blocks with no envelope, an
387
+ * unregistered kind, or no bridge facet pass through UNTOUCHED — the strangler
388
+ * seam.
389
+ *
390
+ * This is where a bare/fenced JSON flashcard_set — which a text detector could
391
+ * only ever call "code" — becomes real flashcards, live while streaming.
392
+ *
393
+ * PORTABILITY. This function was matrx-frontend's `react/kind-route.ts` and is
394
+ * the single most-copied thing in the system: every UI that renders a kind has
395
+ * to make exactly these decisions in exactly this order, and a second
396
+ * implementation of them is a guaranteed divergence. It takes its registries,
397
+ * its platform, and its error sink as an {@link KindRouteEnv} argument rather
398
+ * than importing them, so it is callable from a reducer, a stream accumulator,
399
+ * a test, or a React render — in any app.
400
+ *
401
+ * Semantics: `matrx-frontend/features/content-ir/docs/SHAPE_SYSTEM.md`
402
+ * (registry, dual gate, `kind_component` resolution, rulings R1 + R6).
403
+ */
404
+
405
+ /**
406
+ * Runtime routing marker (the Shape System's verification hook): stamped on
407
+ * `metadata.__ir_route` whenever a block routes AND the component resolver
408
+ * produced the decision. `by` says which resolver tier answered ("compiled"
409
+ * floor vs a warm `content_ir.kind_component` row) — the live proof of
410
+ * registry-resolution vs hard-coded fallback. Metadata-only, non-breaking.
411
+ */
412
+ declare const IR_ROUTE_KEY: "__ir_route";
413
+ /**
414
+ * The component key the R6 generic fallback routes to — the official renderer
415
+ * for a KNOWN shape that nothing render-trusted claims. Hosts map this key to
416
+ * their generic structured view (the package ships one: `GenericStructuredView`).
417
+ */
418
+ declare const GENERIC_STRUCTURED_COMPONENT_KEY: "generic_structured";
419
+ /**
420
+ * The block type a DB-sourced (user-authored) kind component renders as.
421
+ * FE-synthesized: produced ONLY here, never emitted upstream. A host that has
422
+ * no sandbox for user components simply does not map this key — the block then
423
+ * falls to that host's unknown-type handling, which is honest.
424
+ */
425
+ declare const DB_KIND_COMPONENT_KEY: "db_kind_component";
426
+ /** Test-only reset of the once-per-kind console latch. */
427
+ declare function resetSourcelessDbRowReports(): void;
428
+ /** Why a block landed on the generic viewer instead of a real renderer. */
429
+ type GenericFallbackReason =
430
+ /** No compiled bridge and no `content_ir.kind_component` row at all. */
431
+ "no-component"
432
+ /** A component row exists but is held `is_active = false`. */
433
+ | "inactive";
434
+ interface IrRouteMarker {
435
+ by: ComponentResolution["resolvedBy"] | "generic";
436
+ key: string;
437
+ /**
438
+ * Only on the generic fallback: the shape is NOT render-trusted, so the
439
+ * viewer must say so out loud (R6 — never an error, never hidden content).
440
+ */
441
+ unverified?: true;
442
+ reason?: GenericFallbackReason;
443
+ }
444
+ /** Read the routing marker a block picked up at the seam (or null). */
445
+ declare function readIrRouteMarker(metadata: Record<string, unknown> | null | undefined): IrRouteMarker | null;
446
+ interface KindRouteOptions {
447
+ /**
448
+ * Block types this host OWNS and the route must never re-type, however good
449
+ * the envelope on them looks.
450
+ *
451
+ * matrx-frontend passes `["artifact"]`: an artifact block has an identity, a
452
+ * version, and a Canvas to open in, and since 2026-08-18 it carries
453
+ * `metadata.__ir` so SELECTORS can read the envelope. That envelope is DATA
454
+ * there, not a route — re-typing it to the bare kind component would strip
455
+ * the artifact chrome and lose the door to the Canvas.
456
+ */
457
+ ownedTypes?: readonly string[];
458
+ }
459
+ declare function applyIrKindRoute<T extends IrRoutableBlock>(block: T, env: KindRouteEnv, options?: KindRouteOptions): T;
460
+ /**
461
+ * Rehydration route for STRUCTURED persisted artifacts.
462
+ *
463
+ * A materialized kind artifact stores its zero-loss value object (carrying
464
+ * `__kind`) alongside its row. Given that stored value, derive the registered
465
+ * kind's legacy `serverData` WITHOUT re-parsing any text: the value wraps into
466
+ * a complete envelope and runs through the same `toLegacyServerData` bridge the
467
+ * live stream uses. Returns null for non-objects, unregistered kinds, or kinds
468
+ * without a legacy bridge — callers fall back to their string-payload path.
469
+ */
470
+ declare function kindServerDataFromStoredValue(value: unknown, env: Pick<KindRouteEnv, "kinds">): Record<string, unknown> | null;
471
+
472
+ /**
473
+ * Routing the PROVISIONAL half of the streaming partial-kinds contract.
474
+ *
475
+ * Cross-repo system-of-record (read it before changing anything here):
476
+ * `common-docs/systems/content-ir-system/STREAMING_PARTIAL_KINDS.md` §8.
477
+ * The reader/validator half lives in `@ai-matrx/content-ir` (`wire/partial-kind`);
478
+ * the wire gate runs in each host's stream ingest.
479
+ *
480
+ * WHAT THIS DOES
481
+ * --------------
482
+ * While a structured region streams, the server announces what it thinks the
483
+ * region IS and what has arrived so far (`metadata.__ir_partial`). This module
484
+ * turns that provisional event into a routed block that renders through the
485
+ * EXACT SAME component the final value renders in — which is the entire point:
486
+ * a bespoke skeleton renderer would be a second render path and is banned.
487
+ *
488
+ * HOW, without touching the verified channel
489
+ * ------------------------------------------
490
+ * `root` is deliberately `IrStructuredNode`-shaped, so the event wraps into a
491
+ * `CanonicalBlockIR` and every existing reader — the compiled bridge, the
492
+ * component resolver, the db-component flip, the generic viewer — works
493
+ * unchanged. That provisional envelope is placed on a RENDER-LOCAL COPY of the
494
+ * block's metadata under `__ir`, never on the wire and never in host state. The
495
+ * block also carries `__ir_provisional: true` so any downstream reader can tell
496
+ * a provisional render from a verified one.
497
+ *
498
+ * THE POSTURE: WITHHOLD BY DEFAULT, OPT IN PER KIND
499
+ * -------------------------------------------------
500
+ * A provisional value MAY be missing required fields — that is what the
501
+ * `partial_unvalidated` notice declares — and §8 of the contract requires that
502
+ * a component which throws on an absent field is not routed one. Rather than
503
+ * audit every component, the default is WITHHOLD: nothing changes and the block
504
+ * keeps its loading skeleton. A kind opts in with `partialReady: true` on its
505
+ * registry definition. If an opted-in component throws anyway,
506
+ * `ProvisionalKindBoundary` screams and calls `markKindPartialUnsafe`, which
507
+ * drops that kind back to withhold for the rest of the session — loud recovery,
508
+ * never a broken surface.
509
+ *
510
+ * TERMINALS
511
+ * ---------
512
+ * `superseded` and `retracted` produce NO provisional render, so the swap to
513
+ * the final value happens in the same frame the terminal arrives — never a
514
+ * flicker through an empty state. Both are explicit EVENTS: the terminal is
515
+ * never inferred from the arrival of `__ir`, because a completed block often
516
+ * has no `__ir` at all (unregistered kind, schema drift, cold catalog) and
517
+ * inferring it would leave the skeleton up forever in exactly those cases.
518
+ */
519
+
520
+ /**
521
+ * Marker stamped on a render-local block whose `__ir` is PROVISIONAL. Never
522
+ * emitted by a producer, never persisted, never on the wire.
523
+ */
524
+ declare const IR_PROVISIONAL_KEY: "__ir_provisional";
525
+ /** True when this block's metadata carries a provisional (not verified) envelope. */
526
+ declare function isProvisionalBlock(metadata: Record<string, unknown> | null | undefined): boolean;
527
+ /** Wrap a validated `partial` event into the envelope shape every IR reader consumes. */
528
+ declare function envelopeFromPartialKind(event: PartialKindEvent): CanonicalBlockIR;
529
+ /** Loud recovery hook — called by ProvisionalKindBoundary when a render throws. */
530
+ declare function markKindPartialUnsafe(kind: string): void;
531
+ /** Test-only reset of the session latch. */
532
+ declare function resetPartialUnsafeKinds(): void;
533
+ /**
534
+ * Has this kind opted in to being handed a provisional value? Withhold is the
535
+ * default; see the module doc.
536
+ */
537
+ declare function isPartialReadyKind(kind: string, env: Pick<KindRouteEnv, "kinds">): boolean;
538
+ interface PartialRenderOptions extends KindRouteOptions {
539
+ /**
540
+ * Is the STREAM still running? Message-wide, deliberately — not this block's
541
+ * own completion.
542
+ *
543
+ * 🚨 THE ANTI-STUCK-SKELETON BACKSTOP. Law 1 of the contract says every
544
+ * partial ends in exactly one terminal, and that law is the ONLY thing
545
+ * standing between a user and a "Still arriving" skeleton that never
546
+ * resolves. It is a producer guarantee with at least three ways to not fire:
547
+ * the drain skips a block missing from the final block list, the emitter
548
+ * early-returns once the stream ended or was cancelled (so a client abort
549
+ * drops every retraction), and a flush failure is swallowed so it never kills
550
+ * a run.
551
+ *
552
+ * Once the stream is over, no terminal can ever arrive, so a still-open
553
+ * provisional is stuck by definition — drop it and let the block's own
554
+ * content and `__ir` be the truth. Correct to be message-wide: a terminal for
555
+ * THIS block may still be in flight while the block itself looks finished.
556
+ *
557
+ * `undefined` reads as active, so a caller that does not thread stream state
558
+ * keeps live rendering rather than silently losing it.
559
+ */
560
+ streamActive?: boolean;
561
+ }
562
+ /**
563
+ * The ANNOUNCED-but-not-yet-renderable state: the server has said what this
564
+ * region is, and the region cannot render its real component yet.
565
+ *
566
+ * WHY THIS EXISTS SEPARATELY FROM THE VERIFIED CHANNEL. On a chat stream the
567
+ * host's own accumulator fills `__ir` in as it parses. A WORKFLOW run's lane
568
+ * does not: when the server opens the block scope it marks the text channel
569
+ * `block_shadowed` and the lane stops feeding its accumulator, precisely so one
570
+ * region is never rendered twice under two sets of block ids
571
+ * (STREAMING_PARTIAL_KINDS.md §7b rule 4). So on a run page there is NO
572
+ * streaming `__ir` — the ONLY thing that knows what the region is, is the
573
+ * partial channel. Without this, a workflow node's structured answer fell
574
+ * through to the raw-text renderer: a generic loader, then raw JSON
575
+ * accumulating, then a swap at the end.
576
+ *
577
+ * Returns the provisional envelope to feed the kind's loading component, or
578
+ * null when there is nothing announced (no event, a terminal, a dead stream).
579
+ * Deliberately independent of `partialReady`: withholding a VALUE from a
580
+ * component that might throw on it is a real decision, but withholding the
581
+ * kind's own loading state is not — a skeleton cannot throw, and the reader
582
+ * seeing what is coming is the whole point.
583
+ */
584
+ declare function resolveAnnouncedKindLoading(block: {
585
+ metadata?: Record<string, unknown>;
586
+ }, options?: Pick<PartialRenderOptions, "streamActive">): {
587
+ kind: string;
588
+ envelope: CanonicalBlockIR;
589
+ } | null;
590
+ interface ProvisionalKindRender<T> {
591
+ /** The routed block — same type/serverData shape the final value produces. */
592
+ block: T;
593
+ /** The announced (speculative) kind. */
594
+ kind: string;
595
+ /** Per-block ordering key, for diagnostics. */
596
+ seq: number;
597
+ /** The provisional envelope — feeds the loading skeleton used as the throw fallback. */
598
+ envelope: CanonicalBlockIR;
599
+ }
600
+ /**
601
+ * Resolve a block's provisional render, or null when there is nothing to show
602
+ * provisionally (no event, a terminal event, a withheld kind, a kind nothing
603
+ * can route, or a verified envelope that already won).
604
+ *
605
+ * Pure: no React, no host state, no side effects beyond the registry reads.
606
+ */
607
+ declare function resolveProvisionalKindRender<T extends IrRoutableBlock & {
608
+ metadata?: Record<string, unknown>;
609
+ }>(block: T, env: KindRouteEnv, options?: PartialRenderOptions): ProvisionalKindRender<T> | null;
610
+
611
+ /**
612
+ * The two registries this hook watches. Passed explicitly by a host whose
613
+ * render path sits BELOW no provider — matrx-frontend's block renderer runs
614
+ * deep inside chat, workflow, and canvas trees that predate this package, and
615
+ * threading a provider through all of them to read two counters would be the
616
+ * tail wagging the dog.
617
+ */
618
+ interface KindVersionSources {
619
+ kinds: Pick<KindDefinitionSource, "getKindVersion" | "subscribeKind">;
620
+ components: Pick<ComponentResolutionSource, "getKindVersion" | "subscribeKind">;
621
+ }
622
+ /**
623
+ * Subscribes the caller to registry changes FOR ONE KIND and returns that
624
+ * kind's combined version. Pass null for blocks with no envelope kind — they
625
+ * never repaint from registries (nothing to learn about them).
626
+ *
627
+ * `sources` defaults to the provider's host. Passing them explicitly is the
628
+ * supported way to use this hook outside a provider.
629
+ */
630
+ declare function useContentIrKindVersion(kind: string | null, sources?: KindVersionSources): number;
631
+
632
+ declare function isRecordValue(value: unknown): value is Record<string, unknown>;
633
+ /**
634
+ * True when `applyIrKindRoute` has a registered render path for this kind — a
635
+ * compiled legacy bridge OR any ACTIVE resolver row (including db-sourced user
636
+ * components, which route to `db_kind_component`). Mirrors the route's own
637
+ * decision order; requires the resolver warm tier for db rows (see the warm
638
+ * tick in {@link KindInstanceRender}).
639
+ */
640
+ declare function kindIsRoutable(kind: string, host: ContentIrHost): boolean;
641
+ interface KindInstanceRenderProps {
642
+ kind: string;
643
+ /** The canonical instance value (a `kind_example.data` row, a form-emitted instance, a node output). */
644
+ value: unknown;
645
+ /** Show the honest "no component registered" notice when unroutable. Default true. */
646
+ showRoutingNote?: boolean;
647
+ /**
648
+ * What to render when the routing decision lands on "no component exists for
649
+ * this kind". The universal document view is the right answer almost
650
+ * everywhere — it reads well and hides nothing. It is still the wrong answer
651
+ * when the raw value is an internal ENVELOPE rather than content: an
652
+ * `agent_result` dumped the verbatim prompt, the model id and the token bill
653
+ * into the box a learner was waiting on. Passing a fallback lets that caller
654
+ * show what the reader actually wants WITHOUT anyone second-guessing the
655
+ * routing decision — this component stays the ONE place that decides whether
656
+ * a kind has a component.
657
+ *
658
+ * Omitted → the host's floor, exactly as before.
659
+ */
660
+ unroutableFallback?: ReactNode;
661
+ /**
662
+ * Chrome, per THE WRAPPER LAW: a host frame either IS the chrome or has none.
663
+ * "card" (default) keeps a bordered surface for preview surfaces. "bare"
664
+ * renders with NO border/background/pad — for a host that already draws a
665
+ * titled card, where the default produced a two-tone box-in-a-box with a dead
666
+ * band around it.
667
+ */
668
+ variant?: "card" | "bare";
669
+ className?: string;
670
+ }
671
+ declare function KindInstanceRender({ kind, value, showRoutingNote, unroutableFallback, variant, className, }: KindInstanceRenderProps): react.JSX.Element;
672
+
673
+ /**
674
+ * The safety net + the "still arriving" affordance for a provisional kind
675
+ * render (streaming partial kinds — see `route/partial-kind-route.ts` and
676
+ * `common-docs/systems/content-ir-system/STREAMING_PARTIAL_KINDS.md`).
677
+ *
678
+ * TWO JOBS
679
+ * --------
680
+ * 1. **Never let a component throw mid-stream.** A provisional value may be
681
+ * missing required fields. The routed kind opted in to tolerating that
682
+ * (`partialReady`), but an opt-in is a claim, not a proof — so a throw is
683
+ * caught here, SCREAMS through the host's error reporter, drops the kind
684
+ * back to withhold for the session (`markKindPartialUnsafe`), and falls back
685
+ * to the kind's own loading skeleton. The user sees the pre-partial
686
+ * behavior, not a broken message.
687
+ * 2. **Say it is still arriving.** The user must be able to tell a live fill-in
688
+ * from a finished render, and it must not read as an error. A quiet chip
689
+ * rides the block's top edge — absolutely positioned and
690
+ * `pointer-events-none`, so it costs the content no layout and cannot shift
691
+ * the page when it disappears. It sits ON the border rather than inside the
692
+ * block: a routed kind often renders its own chrome, and a chip inside the
693
+ * box lands on top of those controls.
694
+ *
695
+ * No wrapper chrome: no border, no background, no padding. The kind component
696
+ * already carries its own (THE WRAPPER LAW).
697
+ */
698
+
699
+ interface ProvisionalKindBoundaryOwnProps {
700
+ kind: string;
701
+ /** Rendered instead of the children when the provisional render throws. */
702
+ fallback: ReactNode;
703
+ children: ReactNode;
704
+ }
705
+ declare function ProvisionalKindBoundary(props: ProvisionalKindBoundaryOwnProps): react__default.JSX.Element;
706
+ /**
707
+ * The "still arriving" frame. `aria-busy` carries the same fact to assistive
708
+ * tech that the chip carries visually. The chip's own rendering is a host seam
709
+ * (`renderShimmer`) so an app with a shimmer primitive uses it and one without
710
+ * still says the true thing, plainly.
711
+ */
712
+ declare function ProvisionalKindFrame({ children }: {
713
+ children: ReactNode;
714
+ }): react__default.JSX.Element;
715
+
716
+ interface GenericStructuredViewProps {
717
+ /** The raw region source — the zero-loss floor when no envelope survived. */
718
+ content: string;
719
+ /** Carries `__ir` (the parsed envelope) and `__ir_route` (the seam marker). */
720
+ metadata?: Record<string, unknown>;
721
+ /**
722
+ * What to show while the region is still streaming. Hosts with a shimmer or
723
+ * an icon set pass theirs; the default is the same sentence, plainly.
724
+ */
725
+ streamingIndicator?: ReactNode;
726
+ className?: string;
727
+ }
728
+ declare function GenericStructuredView({ content, metadata, streamingIndicator, className, }: GenericStructuredViewProps): react.JSX.Element;
729
+
730
+ interface DelegatedOutputProps {
731
+ output: unknown;
732
+ /** The wrapper's `output_kind` — the node's DECLARATION, the fallback. */
733
+ declaredKind: string | null;
734
+ /**
735
+ * What to draw for a value with no kind at all, and as the unroutable
736
+ * fallback. Hosts with a settled-output body (the same one their readout
737
+ * uses — never a second reader) pass it; otherwise the floor draws it.
738
+ *
739
+ * A RENDER FUNCTION, not a node: the fallback needs the payload, and the only
740
+ * component that has read it is this one. Handing back a static node would
741
+ * force every host to re-read the wrapper itself — a second reader, which is
742
+ * exactly what this family exists to prevent.
743
+ */
744
+ fallback?: (output: unknown) => ReactNode;
745
+ /** What to say when the step produced nothing. */
746
+ emptyLabel?: string;
747
+ }
748
+ /**
749
+ * The delegation seam — the ONLY thing these components do with a payload.
750
+ *
751
+ * In-band `__kind` wins over the node's DECLARATION, the same law a run reducer
752
+ * follows: the discriminator inside the value describes what we are actually
753
+ * holding, so it is what routes. With no kind at all there is nothing to route
754
+ * to, and the host's fallback (or the floor) shows what the step produced.
755
+ */
756
+ declare function DelegatedOutput({ output, declaredKind, fallback, emptyLabel, }: DelegatedOutputProps): react.JSX.Element;
757
+ interface NodeOutcomeViewProps {
758
+ serverData?: unknown;
759
+ /** Passed through to {@link DelegatedOutput}. */
760
+ fallback?: (output: unknown) => ReactNode;
761
+ }
762
+ /** THE renderer for the `node_outcome` runtime wrapper kind. */
763
+ declare function NodeOutcomeView({ serverData, fallback }: NodeOutcomeViewProps): react.JSX.Element | null;
764
+ interface RunResultViewProps {
765
+ serverData?: unknown;
766
+ fallback?: (output: unknown) => ReactNode;
767
+ }
768
+ /**
769
+ * THE renderer for the `run_result` runtime wrapper kind.
770
+ *
771
+ * One finished run: one `node_outcome` per TERMINAL node — each delegated to
772
+ * {@link NodeOutcomeView}, which delegates the payload inside it to the data
773
+ * kind's own component. Recursion all the way down; no payload is rendered
774
+ * here, and no `final_text` is read here.
775
+ *
776
+ * The run's own `output` is rendered ONLY when the run declared no terminal
777
+ * outcomes — otherwise it is the same content the outcomes already carry, and
778
+ * showing both is the duplication the wrapper exists to prevent.
779
+ */
780
+ declare function RunResultView({ serverData, fallback }: RunResultViewProps): react.JSX.Element | null;
781
+
782
+ export { type ComponentResolution, type ComponentResolutionSource, ComponentResolver, type ComponentResolverOptions, type ComponentRole, type ContentIrErrorReport, type ContentIrErrorReporter, type ContentIrHost, ContentIrRenderProvider, type ContentIrRenderProviderProps, type ContentIrRenderSeams, DB_KIND_COMPONENT_KEY, DelegatedOutput, type DelegatedOutputProps, GENERIC_STRUCTURED_COMPONENT_KEY, type GenericFallbackReason, GenericStructuredView, type GenericStructuredViewProps, IR_PROVISIONAL_KEY, IR_ROUTE_KEY, type IrRenderBlock, type IrRoutableBlock, type IrRouteMarker, type JsonObject, type KindComponentRow, type KindDefinitionSource, KindInstanceRender, type KindInstanceRenderProps, type KindRouteEnv, type KindRouteOptions, type KindVersionSources, NodeOutcomeView, type NodeOutcomeViewProps, type PartialRenderOptions, ProvisionalKindBoundary, ProvisionalKindFrame, type ProvisionalKindRender, RunResultView, type RunResultViewProps, type StructuredValueRenderProps, type SystemComponentEntry, applyIrKindRoute, consoleErrorReporter, envelopeFromPartialKind, isPartialReadyKind, isProvisionalBlock, isRecordValue, kindIsRoutable, kindServerDataFromStoredValue, markKindPartialUnsafe, readIrRouteMarker, resetPartialUnsafeKinds, resetSourcelessDbRowReports, resolveAnnouncedKindLoading, resolveProvisionalKindRender, routeEnvOf, useContentIrHost, useContentIrHostOrNull, useContentIrKindVersion, useKindRouteEnv };