@ai-matrx/content-ir-react 0.8.1 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/dist/{component-resolution.types-BS1ySIg-.d.cts → component-resolution.types-C1MzCf2s.d.cts} +13 -0
- package/dist/{component-resolution.types-BS1ySIg-.d.ts → component-resolution.types-C1MzCf2s.d.ts} +13 -0
- package/dist/{component-resolution.types-fvR92hW7.d.cts → component-resolution.types-DLO2w-0n.d.cts} +13 -0
- package/dist/{component-resolution.types-fvR92hW7.d.ts → component-resolution.types-DLO2w-0n.d.ts} +13 -0
- package/dist/db-component.d.cts +1 -1
- package/dist/db-component.d.ts +1 -1
- package/dist/{host-types-DvGv8s9L.d.cts → host-types-CDcLW0TD.d.cts} +7 -2
- package/dist/{host-types-CZ_Bkp4R.d.ts → host-types-CpItjcYh.d.ts} +7 -2
- package/dist/host.cjs.map +1 -1
- package/dist/host.d.cts +3 -3
- package/dist/host.d.ts +3 -3
- package/dist/host.js.map +1 -1
- package/dist/index.cjs +17 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -1
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js.map +1 -1
- package/dist/resolver.cjs +15 -0
- package/dist/resolver.cjs.map +1 -1
- package/dist/resolver.d.cts +11 -2
- package/dist/resolver.d.ts +11 -2
- package/dist/resolver.js +15 -0
- package/dist/resolver.js.map +1 -1
- package/dist/{route-C1XNcubB.d.ts → route-PUuEuEug.d.ts} +7 -2
- package/dist/{route-C55jsF4B.d.cts → route-QL2Vqf2e.d.cts} +7 -2
- package/dist/route.cjs +2 -0
- package/dist/route.cjs.map +1 -1
- package/dist/route.d.cts +2 -2
- package/dist/route.d.ts +2 -2
- package/dist/route.js +2 -0
- package/dist/route.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.9.1 — 2026-08-31
|
|
4
|
+
|
|
5
|
+
- `replaceDbRows` now settles the resolver. It is the refresh landing point —
|
|
6
|
+
a completed wholesale list load — and the seam a host or test uses to
|
|
7
|
+
declare "the list loaded". Without it, a host that warms through
|
|
8
|
+
`refresh()` instead of `ensureWarm()` would have every block held by THE
|
|
9
|
+
COLD-VERDICT RULE indefinitely.
|
|
10
|
+
|
|
11
|
+
## 0.9.0 — 2026-08-31
|
|
12
|
+
|
|
13
|
+
- **THE COLD-VERDICT RULE — a registry that has not looked says nothing.**
|
|
14
|
+
`ComponentResolutionSource` gains optional `hasSettled()`, `ComponentResolver`
|
|
15
|
+
implements it, and `applyIrKindRoute` holds a block (exactly as
|
|
16
|
+
`pending_schema` does) instead of publishing `unregistered` / `no-component`
|
|
17
|
+
while the resolver's list load has not completed and nothing has been
|
|
18
|
+
ingested.
|
|
19
|
+
|
|
20
|
+
WHY: every generic-fallback reason is a durable, user-visible claim written
|
|
21
|
+
into the block's `metadata.__ir_route`. On the FIRST PAINT of a fresh tab the
|
|
22
|
+
resolver has fetched nothing, so `resolve()` returning null meant both "no
|
|
23
|
+
such component" and "I haven't looked" — and the route could not tell them
|
|
24
|
+
apart. Live report (2026-08-31): `agent_mandate_specification`, registered +
|
|
25
|
+
active with an active `source='db'` component, rendered on /chat as a
|
|
26
|
+
key/value dump captioned "this shape isn't registered on this platform".
|
|
27
|
+
The same conversation rendered correctly in a window panel whose registries
|
|
28
|
+
were already warm.
|
|
29
|
+
|
|
30
|
+
A POSITIVE answer is never suppressed (compiled floor and already-ingested
|
|
31
|
+
rows route immediately), a FAILED list load still settles (blocks are never
|
|
32
|
+
held forever), and a resolver with no `loadAll` is settled from birth. Once
|
|
33
|
+
settled, a genuinely unknown kind still reaches the generic floor with
|
|
34
|
+
`unregistered` exactly as before.
|
|
35
|
+
|
|
36
|
+
Pinned by `__tests__/cold-verdict-rule.test.ts` (5 tests, built from the
|
|
37
|
+
live row that failed).
|
|
38
|
+
|
|
3
39
|
## 0.8.1 — 2026-08-30
|
|
4
40
|
|
|
5
41
|
- **Republished against `@ai-matrx/content-ir` 0.10.0.** The 0.8.0 tarball
|
package/dist/{component-resolution.types-BS1ySIg-.d.cts → component-resolution.types-C1MzCf2s.d.cts}
RENAMED
|
@@ -91,6 +91,19 @@ interface ComponentResolutionSource {
|
|
|
91
91
|
requestComponent(kind: string, platform: string, role: ComponentRole): void;
|
|
92
92
|
/** One list fetch per session. */
|
|
93
93
|
ensureWarm(): Promise<void>;
|
|
94
|
+
/**
|
|
95
|
+
* Has the session's list load COMPLETED (successfully or not)?
|
|
96
|
+
*
|
|
97
|
+
* 🚨 THE COLD-VERDICT RULE. Before this existed, `resolve()` answering null
|
|
98
|
+
* was ambiguous: it meant BOTH "this kind genuinely has no component" and
|
|
99
|
+
* "I have not looked yet". The render route could not tell them apart, so a
|
|
100
|
+
* block routed during the first paint of a fresh tab got stamped
|
|
101
|
+
* `unregistered` — a durable, user-visible claim that the shape does not
|
|
102
|
+
* exist — produced by a registry that had loaded nothing. Optional so an
|
|
103
|
+
* existing host satisfies the interface unchanged; absent reads as settled,
|
|
104
|
+
* which is the pre-existing behavior.
|
|
105
|
+
*/
|
|
106
|
+
hasSettled?(): boolean;
|
|
94
107
|
/** Refresh-on-view; rate-limited and deduped by the implementation. */
|
|
95
108
|
refresh(maxAgeMs?: number): Promise<void>;
|
|
96
109
|
/** Monotonic tier version — has anything at all changed? */
|
package/dist/{component-resolution.types-BS1ySIg-.d.ts → component-resolution.types-C1MzCf2s.d.ts}
RENAMED
|
@@ -91,6 +91,19 @@ interface ComponentResolutionSource {
|
|
|
91
91
|
requestComponent(kind: string, platform: string, role: ComponentRole): void;
|
|
92
92
|
/** One list fetch per session. */
|
|
93
93
|
ensureWarm(): Promise<void>;
|
|
94
|
+
/**
|
|
95
|
+
* Has the session's list load COMPLETED (successfully or not)?
|
|
96
|
+
*
|
|
97
|
+
* 🚨 THE COLD-VERDICT RULE. Before this existed, `resolve()` answering null
|
|
98
|
+
* was ambiguous: it meant BOTH "this kind genuinely has no component" and
|
|
99
|
+
* "I have not looked yet". The render route could not tell them apart, so a
|
|
100
|
+
* block routed during the first paint of a fresh tab got stamped
|
|
101
|
+
* `unregistered` — a durable, user-visible claim that the shape does not
|
|
102
|
+
* exist — produced by a registry that had loaded nothing. Optional so an
|
|
103
|
+
* existing host satisfies the interface unchanged; absent reads as settled,
|
|
104
|
+
* which is the pre-existing behavior.
|
|
105
|
+
*/
|
|
106
|
+
hasSettled?(): boolean;
|
|
94
107
|
/** Refresh-on-view; rate-limited and deduped by the implementation. */
|
|
95
108
|
refresh(maxAgeMs?: number): Promise<void>;
|
|
96
109
|
/** Monotonic tier version — has anything at all changed? */
|
package/dist/{component-resolution.types-fvR92hW7.d.cts → component-resolution.types-DLO2w-0n.d.cts}
RENAMED
|
@@ -129,6 +129,19 @@ interface ComponentResolutionSource {
|
|
|
129
129
|
requestComponent(kind: string, platform: string, role: ComponentRole): void;
|
|
130
130
|
/** One list fetch per session. */
|
|
131
131
|
ensureWarm(): Promise<void>;
|
|
132
|
+
/**
|
|
133
|
+
* Has the session's list load COMPLETED (successfully or not)?
|
|
134
|
+
*
|
|
135
|
+
* 🚨 THE COLD-VERDICT RULE. Before this existed, `resolve()` answering null
|
|
136
|
+
* was ambiguous: it meant BOTH "this kind genuinely has no component" and
|
|
137
|
+
* "I have not looked yet". The render route could not tell them apart, so a
|
|
138
|
+
* block routed during the first paint of a fresh tab got stamped
|
|
139
|
+
* `unregistered` — a durable, user-visible claim that the shape does not
|
|
140
|
+
* exist — produced by a registry that had loaded nothing. Optional so an
|
|
141
|
+
* existing host satisfies the interface unchanged; absent reads as settled,
|
|
142
|
+
* which is the pre-existing behavior.
|
|
143
|
+
*/
|
|
144
|
+
hasSettled?(): boolean;
|
|
132
145
|
/** Refresh-on-view; rate-limited and deduped by the implementation. */
|
|
133
146
|
refresh(maxAgeMs?: number): Promise<void>;
|
|
134
147
|
/** Monotonic tier version — has anything at all changed? */
|
package/dist/{component-resolution.types-fvR92hW7.d.ts → component-resolution.types-DLO2w-0n.d.ts}
RENAMED
|
@@ -129,6 +129,19 @@ interface ComponentResolutionSource {
|
|
|
129
129
|
requestComponent(kind: string, platform: string, role: ComponentRole): void;
|
|
130
130
|
/** One list fetch per session. */
|
|
131
131
|
ensureWarm(): Promise<void>;
|
|
132
|
+
/**
|
|
133
|
+
* Has the session's list load COMPLETED (successfully or not)?
|
|
134
|
+
*
|
|
135
|
+
* 🚨 THE COLD-VERDICT RULE. Before this existed, `resolve()` answering null
|
|
136
|
+
* was ambiguous: it meant BOTH "this kind genuinely has no component" and
|
|
137
|
+
* "I have not looked yet". The render route could not tell them apart, so a
|
|
138
|
+
* block routed during the first paint of a fresh tab got stamped
|
|
139
|
+
* `unregistered` — a durable, user-visible claim that the shape does not
|
|
140
|
+
* exist — produced by a registry that had loaded nothing. Optional so an
|
|
141
|
+
* existing host satisfies the interface unchanged; absent reads as settled,
|
|
142
|
+
* which is the pre-existing behavior.
|
|
143
|
+
*/
|
|
144
|
+
hasSettled?(): boolean;
|
|
132
145
|
/** Refresh-on-view; rate-limited and deduped by the implementation. */
|
|
133
146
|
refresh(maxAgeMs?: number): Promise<void>;
|
|
134
147
|
/** Monotonic tier version — has anything at all changed? */
|
package/dist/db-component.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { C as ComponentResolution, a as ContentIrErrorReporter } from './component-resolution.types-
|
|
2
|
+
import { C as ComponentResolution, a as ContentIrErrorReporter } from './component-resolution.types-C1MzCf2s.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* The DB-component COMPILE CACHE — session-scoped, keyed per winning row
|
package/dist/db-component.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { C as ComponentResolution, a as ContentIrErrorReporter } from './component-resolution.types-
|
|
2
|
+
import { C as ComponentResolution, a as ContentIrErrorReporter } from './component-resolution.types-C1MzCf2s.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* The DB-component COMPILE CACHE — session-scoped, keyed per winning row
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
import { KindDefinition } from '@ai-matrx/content-ir';
|
|
3
|
-
import { d as ComponentResolutionSource, a as ContentIrErrorReporter } from './component-resolution.types-
|
|
3
|
+
import { d as ComponentResolutionSource, a as ContentIrErrorReporter } from './component-resolution.types-C1MzCf2s.cjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* THE HOST CONTRACT — everything this package refuses to decide.
|
|
@@ -121,7 +121,12 @@ interface ContentIrHost extends ContentIrRenderSeams {
|
|
|
121
121
|
*/
|
|
122
122
|
interface KindRouteEnv {
|
|
123
123
|
kinds: Pick<KindDefinitionSource, "getDefinition">;
|
|
124
|
-
|
|
124
|
+
/**
|
|
125
|
+
* `hasSettled` is optional and read ONLY to suppress a negative verdict from
|
|
126
|
+
* a registry that has not loaded yet — see THE COLD-VERDICT RULE on
|
|
127
|
+
* `ComponentResolutionSource`.
|
|
128
|
+
*/
|
|
129
|
+
components: Pick<ComponentResolutionSource, "resolve"> & Partial<Pick<ComponentResolutionSource, "hasSettled">>;
|
|
125
130
|
reportError: ContentIrErrorReporter;
|
|
126
131
|
platform: string;
|
|
127
132
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
import { KindDefinition } from '@ai-matrx/content-ir';
|
|
3
|
-
import { d as ComponentResolutionSource, a as ContentIrErrorReporter } from './component-resolution.types-
|
|
3
|
+
import { d as ComponentResolutionSource, a as ContentIrErrorReporter } from './component-resolution.types-C1MzCf2s.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* THE HOST CONTRACT — everything this package refuses to decide.
|
|
@@ -121,7 +121,12 @@ interface ContentIrHost extends ContentIrRenderSeams {
|
|
|
121
121
|
*/
|
|
122
122
|
interface KindRouteEnv {
|
|
123
123
|
kinds: Pick<KindDefinitionSource, "getDefinition">;
|
|
124
|
-
|
|
124
|
+
/**
|
|
125
|
+
* `hasSettled` is optional and read ONLY to suppress a negative verdict from
|
|
126
|
+
* a registry that has not loaded yet — see THE COLD-VERDICT RULE on
|
|
127
|
+
* `ComponentResolutionSource`.
|
|
128
|
+
*/
|
|
129
|
+
components: Pick<ComponentResolutionSource, "resolve"> & Partial<Pick<ComponentResolutionSource, "hasSettled">>;
|
|
125
130
|
reportError: ContentIrErrorReporter;
|
|
126
131
|
platform: string;
|
|
127
132
|
}
|
package/dist/host.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../host.ts","../host/error-report.ts","../host/host-types.ts","../host/ContentIrProvider.tsx"],"sourcesContent":["/**\n * `@ai-matrx/content-ir-react/host` — the contract every consumer wires once:\n * the scream seam, the host/seam types, and the React provider.\n *\n * NOTE: this entry is stamped \"use client\" (it carries the provider). The\n * TYPES here are importable from anywhere; a server-side module that needs\n * only pure route logic imports `/route` instead.\n */\nexport * from \"./host/error-report\";\nexport * from \"./host/host-types\";\nexport * from \"./host/ContentIrProvider\";\n","/**\n * THE SCREAM SEAM.\n *\n * Every recovery path in this package is loud: a defective component row, a\n * failed resolver load, a kind whose component throws on a provisional value.\n * The package refuses to own where those screams land — matrx-frontend routes\n * them to the Error Inspector, the dashboard to its own log, the extension to\n * its background page. Each host binds one function.\n *\n * A host that binds a no-op has chosen silence, which is a defect in itself;\n * {@link consoleErrorReporter} is the honest default.\n */\n\nexport interface ContentIrErrorReport {\n /** Always `\"content-ir\"` — hosts key their capture stores on it. */\n source: \"content-ir\";\n message: string;\n name?: string;\n stack?: string;\n /** Free-form grouping key (the host's `relation`), e.g. `\"partial-kind\"`. */\n relation?: string;\n raw?: unknown;\n}\n\nexport type ContentIrErrorReporter = (report: ContentIrErrorReport) => void;\n\n/** The default when a host binds nothing: never silent. */\nexport const consoleErrorReporter: ContentIrErrorReporter = (report) => {\n console.error(`[content-ir] ${report.message}`, report.raw ?? \"\");\n};\n","/**\n * THE HOST CONTRACT — everything this package refuses to decide.\n *\n * The kernel (`@ai-matrx/content-ir`) proved the shape: extract the portable\n * part, let host capability enter through explicit named seams. The render\n * layer needs four things it must never own:\n *\n * 1. WHERE KIND DEFINITIONS COME FROM (a bundled table, `content_ir`, a REST\n * call). The route only asks \"is this kind registered, and does it carry a\n * legacy bridge / a partial-ready opt-in\".\n * 2. WHERE COMPONENT ROWS COME FROM — {@link ComponentResolutionSource}. The\n * package ships `ComponentResolver`, which any host can construct with its\n * own loaders; a host with its own resolver only has to satisfy the type.\n * 3. HOW A ROUTED BLOCK ACTUALLY DRAWS. `applyIrKindRoute` decides a block's\n * TYPE; turning that type into pixels is the host's dispatch table\n * (matrx-frontend's `BlockRenderer`, the dashboard's small map). The\n * package never imports a component library.\n * 4. WHERE SCREAMS LAND — {@link ContentIrErrorReporter}.\n *\n * No Next.js, no Redux, no Supabase, no router, no host error capture. If a\n * seam is missing, ADD A SEAM — never an import.\n */\n\nimport type { ReactNode } from \"react\";\nimport type { KindDefinition } from \"@ai-matrx/content-ir\";\nimport type { ContentIrErrorReporter } from \"./error-report\";\nimport type { ComponentResolutionSource } from \"../resolver/component-resolution.types\";\n\n/**\n * The minimum a render block must expose for the kind route to work. Hosts\n * pass their own richer block type through; the route is generic over `T` and\n * preserves every extra field.\n */\nexport interface IrRoutableBlock {\n type: string;\n serverData?: Record<string, unknown>;\n metadata?: Record<string, unknown>;\n}\n\n/** A routable block that also carries its source text (the raw region). */\nexport interface IrRenderBlock extends IrRoutableBlock {\n content: string;\n language?: string;\n}\n\n/**\n * Where registered kinds come from. `getDefinition` is the only method the\n * pure route needs; the rest drive the granular repaint and the warm-up tick\n * that keeps a cold registry from being mistaken for \"this kind has no\n * component\".\n */\nexport interface KindDefinitionSource {\n getDefinition(kind: string): KindDefinition | undefined;\n /** Monotonic per-kind version — the repaint snapshot key. */\n getKindVersion(kind: string): number;\n subscribeKind(kind: string, listener: () => void): () => void;\n /** One definition load per app session. */\n ensureWarm(): Promise<void>;\n}\n\n/**\n * The rendering seams. Everything here returns host UI; the package supplies\n * the DECISIONS and the chrome-free structure around them.\n */\nexport interface ContentIrRenderSeams {\n /**\n * Draw a block the kind route has already typed. This is the host's dispatch\n * table — the single place a component key becomes a component.\n */\n renderBlock(block: IrRenderBlock): ReactNode;\n /**\n * THE FLOOR: render ANY JSON value as a human document. Reached when a kind\n * has no render-trusted component, when the value is not an object at all,\n * and by the generic structured view.\n *\n * This is deliberately a seam and not a bundled component. Rendering a value\n * WELL means prose through the host's markdown renderer, media through the\n * host's file handler, and uniform arrays through the host's data table —\n * all of which are host property. A host that has none of those can pass a\n * `<pre>`; it will be honest, just plain.\n */\n renderValue(props: StructuredValueRenderProps): ReactNode;\n /**\n * The \"still arriving\" indicator used by the provisional frame. Optional —\n * hosts without a shimmer get plain text.\n */\n renderShimmer?(text: string): ReactNode;\n /**\n * The honest \"this shape has no custom component yet\" notice. Optional: the\n * package draws a plain amber line when a host supplies nothing, and a host\n * with an icon set or its own callout component supplies that instead. It is\n * a seam and not a bundled component because this package depends on no icon\n * library.\n */\n renderNotice?(text: string): ReactNode;\n}\n\nexport interface StructuredValueRenderProps {\n value: unknown;\n /** The kind slug this value claims, when known. Honesty line only — never a renderer choice. */\n kind?: string;\n /** Why this shape has no custom view, in human words. */\n note?: string;\n /** Show the \"what this is / raw data\" footer. Default true. */\n footer?: boolean;\n}\n\n/**\n * One host, wired once, read by every component in this package through\n * {@link ContentIrRenderProvider}.\n */\nexport interface ContentIrHost extends ContentIrRenderSeams {\n kinds: KindDefinitionSource;\n components: ComponentResolutionSource;\n reportError: ContentIrErrorReporter;\n /**\n * The `kind_component.platform` this host resolves as. \"web\" for every\n * browser UI; the column already models \"react-native\" and friends, and a\n * host that lies here renders the wrong component everywhere.\n */\n platform: string;\n}\n\n/**\n * The pure route's dependencies — a strict subset of {@link ContentIrHost},\n * because `applyIrKindRoute` is called OUTSIDE React (reducers, stream\n * accumulators, tests) where there is no provider to read.\n */\nexport interface KindRouteEnv {\n kinds: Pick<KindDefinitionSource, \"getDefinition\">;\n components: Pick<ComponentResolutionSource, \"resolve\">;\n reportError: ContentIrErrorReporter;\n platform: string;\n}\n\n/** Narrow a host (or anything host-shaped) to what the pure route needs. */\nexport function routeEnvOf(host: ContentIrHost): KindRouteEnv {\n return {\n kinds: host.kinds,\n components: host.components,\n reportError: host.reportError,\n platform: host.platform,\n };\n}\n","\"use client\";\n\n/**\n * The one place a host is wired in. Everything React in this package reads its\n * capability from here — no module singleton, no import into an app.\n *\n * A host mounts this ONCE, high enough that every kind-rendering surface is\n * inside it:\n *\n * ```tsx\n * <ContentIrRenderProvider host={matrxContentIrHost}>\n * <App />\n * </ContentIrRenderProvider>\n * ```\n *\n * Reading it outside a provider THROWS rather than falling back to a default.\n * A silent default would render the wrong component for every kind in the app\n * and look like a data problem for weeks.\n */\n\nimport { createContext, useContext, useMemo, type ReactNode } from \"react\";\nimport type { ContentIrHost, KindRouteEnv } from \"./host-types\";\nimport { routeEnvOf } from \"./host-types\";\n\nconst ContentIrHostContext = createContext<ContentIrHost | null>(null);\n\nexport interface ContentIrRenderProviderProps {\n host: ContentIrHost;\n children: ReactNode;\n}\n\nexport function ContentIrRenderProvider({\n host,\n children,\n}: ContentIrRenderProviderProps) {\n return (\n <ContentIrHostContext.Provider value={host}>\n {children}\n </ContentIrHostContext.Provider>\n );\n}\n\n/**\n * The wired host, or null. For the rare consumer that can legitimately run\n * without a provider because it was handed its sources explicitly (see\n * `useContentIrKindVersion`). Everything else uses {@link useContentIrHost}.\n */\nexport function useContentIrHostOrNull(): ContentIrHost | null {\n return useContext(ContentIrHostContext);\n}\n\n/** The wired host. Throws outside a provider — see the module doc. */\nexport function useContentIrHost(): ContentIrHost {\n const host = useContentIrHostOrNull();\n if (!host) {\n throw new Error(\n \"[content-ir-react] No ContentIrRenderProvider above this component. \" +\n \"Mount one at the app root with your host adapter (kind definitions, \" +\n \"component resolver, renderBlock, renderValue, reportError).\",\n );\n }\n return host;\n}\n\n/** The wired host narrowed to what the pure route functions take. */\nexport function useKindRouteEnv(): KindRouteEnv {\n const host = useContentIrHost();\n return useMemo(() => routeEnvOf(host), [host]);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC2BO,IAAM,uBAA+C,CAAC,WAAW;AACtE,UAAQ,MAAM,gBAAgB,OAAO,OAAO,IAAI,OAAO,OAAO,EAAE;AAClE;;;AC2GO,SAAS,WAAW,MAAmC;AAC5D,SAAO;AAAA,IACL,OAAO,KAAK;AAAA,IACZ,YAAY,KAAK;AAAA,IACjB,aAAa,KAAK;AAAA,IAClB,UAAU,KAAK;AAAA,EACjB;AACF;;;AC3HA,mBAAmE;AAgB/D;AAZJ,IAAM,2BAAuB,4BAAoC,IAAI;AAO9D,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA;AACF,GAAiC;AAC/B,SACE,4CAAC,qBAAqB,UAArB,EAA8B,OAAO,MACnC,UACH;AAEJ;AAOO,SAAS,yBAA+C;AAC7D,aAAO,yBAAW,oBAAoB;AACxC;AAGO,SAAS,mBAAkC;AAChD,QAAM,OAAO,uBAAuB;AACpC,MAAI,CAAC,MAAM;AACT,UAAM,IAAI;AAAA,MACR;AAAA,IAGF;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,kBAAgC;AAC9C,QAAM,OAAO,iBAAiB;AAC9B,aAAO,sBAAQ,MAAM,WAAW,IAAI,GAAG,CAAC,IAAI,CAAC;AAC/C;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../host.ts","../host/error-report.ts","../host/host-types.ts","../host/ContentIrProvider.tsx"],"sourcesContent":["/**\n * `@ai-matrx/content-ir-react/host` — the contract every consumer wires once:\n * the scream seam, the host/seam types, and the React provider.\n *\n * NOTE: this entry is stamped \"use client\" (it carries the provider). The\n * TYPES here are importable from anywhere; a server-side module that needs\n * only pure route logic imports `/route` instead.\n */\nexport * from \"./host/error-report\";\nexport * from \"./host/host-types\";\nexport * from \"./host/ContentIrProvider\";\n","/**\n * THE SCREAM SEAM.\n *\n * Every recovery path in this package is loud: a defective component row, a\n * failed resolver load, a kind whose component throws on a provisional value.\n * The package refuses to own where those screams land — matrx-frontend routes\n * them to the Error Inspector, the dashboard to its own log, the extension to\n * its background page. Each host binds one function.\n *\n * A host that binds a no-op has chosen silence, which is a defect in itself;\n * {@link consoleErrorReporter} is the honest default.\n */\n\nexport interface ContentIrErrorReport {\n /** Always `\"content-ir\"` — hosts key their capture stores on it. */\n source: \"content-ir\";\n message: string;\n name?: string;\n stack?: string;\n /** Free-form grouping key (the host's `relation`), e.g. `\"partial-kind\"`. */\n relation?: string;\n raw?: unknown;\n}\n\nexport type ContentIrErrorReporter = (report: ContentIrErrorReport) => void;\n\n/** The default when a host binds nothing: never silent. */\nexport const consoleErrorReporter: ContentIrErrorReporter = (report) => {\n console.error(`[content-ir] ${report.message}`, report.raw ?? \"\");\n};\n","/**\n * THE HOST CONTRACT — everything this package refuses to decide.\n *\n * The kernel (`@ai-matrx/content-ir`) proved the shape: extract the portable\n * part, let host capability enter through explicit named seams. The render\n * layer needs four things it must never own:\n *\n * 1. WHERE KIND DEFINITIONS COME FROM (a bundled table, `content_ir`, a REST\n * call). The route only asks \"is this kind registered, and does it carry a\n * legacy bridge / a partial-ready opt-in\".\n * 2. WHERE COMPONENT ROWS COME FROM — {@link ComponentResolutionSource}. The\n * package ships `ComponentResolver`, which any host can construct with its\n * own loaders; a host with its own resolver only has to satisfy the type.\n * 3. HOW A ROUTED BLOCK ACTUALLY DRAWS. `applyIrKindRoute` decides a block's\n * TYPE; turning that type into pixels is the host's dispatch table\n * (matrx-frontend's `BlockRenderer`, the dashboard's small map). The\n * package never imports a component library.\n * 4. WHERE SCREAMS LAND — {@link ContentIrErrorReporter}.\n *\n * No Next.js, no Redux, no Supabase, no router, no host error capture. If a\n * seam is missing, ADD A SEAM — never an import.\n */\n\nimport type { ReactNode } from \"react\";\nimport type { KindDefinition } from \"@ai-matrx/content-ir\";\nimport type { ContentIrErrorReporter } from \"./error-report\";\nimport type { ComponentResolutionSource } from \"../resolver/component-resolution.types\";\n\n/**\n * The minimum a render block must expose for the kind route to work. Hosts\n * pass their own richer block type through; the route is generic over `T` and\n * preserves every extra field.\n */\nexport interface IrRoutableBlock {\n type: string;\n serverData?: Record<string, unknown>;\n metadata?: Record<string, unknown>;\n}\n\n/** A routable block that also carries its source text (the raw region). */\nexport interface IrRenderBlock extends IrRoutableBlock {\n content: string;\n language?: string;\n}\n\n/**\n * Where registered kinds come from. `getDefinition` is the only method the\n * pure route needs; the rest drive the granular repaint and the warm-up tick\n * that keeps a cold registry from being mistaken for \"this kind has no\n * component\".\n */\nexport interface KindDefinitionSource {\n getDefinition(kind: string): KindDefinition | undefined;\n /** Monotonic per-kind version — the repaint snapshot key. */\n getKindVersion(kind: string): number;\n subscribeKind(kind: string, listener: () => void): () => void;\n /** One definition load per app session. */\n ensureWarm(): Promise<void>;\n}\n\n/**\n * The rendering seams. Everything here returns host UI; the package supplies\n * the DECISIONS and the chrome-free structure around them.\n */\nexport interface ContentIrRenderSeams {\n /**\n * Draw a block the kind route has already typed. This is the host's dispatch\n * table — the single place a component key becomes a component.\n */\n renderBlock(block: IrRenderBlock): ReactNode;\n /**\n * THE FLOOR: render ANY JSON value as a human document. Reached when a kind\n * has no render-trusted component, when the value is not an object at all,\n * and by the generic structured view.\n *\n * This is deliberately a seam and not a bundled component. Rendering a value\n * WELL means prose through the host's markdown renderer, media through the\n * host's file handler, and uniform arrays through the host's data table —\n * all of which are host property. A host that has none of those can pass a\n * `<pre>`; it will be honest, just plain.\n */\n renderValue(props: StructuredValueRenderProps): ReactNode;\n /**\n * The \"still arriving\" indicator used by the provisional frame. Optional —\n * hosts without a shimmer get plain text.\n */\n renderShimmer?(text: string): ReactNode;\n /**\n * The honest \"this shape has no custom component yet\" notice. Optional: the\n * package draws a plain amber line when a host supplies nothing, and a host\n * with an icon set or its own callout component supplies that instead. It is\n * a seam and not a bundled component because this package depends on no icon\n * library.\n */\n renderNotice?(text: string): ReactNode;\n}\n\nexport interface StructuredValueRenderProps {\n value: unknown;\n /** The kind slug this value claims, when known. Honesty line only — never a renderer choice. */\n kind?: string;\n /** Why this shape has no custom view, in human words. */\n note?: string;\n /** Show the \"what this is / raw data\" footer. Default true. */\n footer?: boolean;\n}\n\n/**\n * One host, wired once, read by every component in this package through\n * {@link ContentIrRenderProvider}.\n */\nexport interface ContentIrHost extends ContentIrRenderSeams {\n kinds: KindDefinitionSource;\n components: ComponentResolutionSource;\n reportError: ContentIrErrorReporter;\n /**\n * The `kind_component.platform` this host resolves as. \"web\" for every\n * browser UI; the column already models \"react-native\" and friends, and a\n * host that lies here renders the wrong component everywhere.\n */\n platform: string;\n}\n\n/**\n * The pure route's dependencies — a strict subset of {@link ContentIrHost},\n * because `applyIrKindRoute` is called OUTSIDE React (reducers, stream\n * accumulators, tests) where there is no provider to read.\n */\nexport interface KindRouteEnv {\n kinds: Pick<KindDefinitionSource, \"getDefinition\">;\n /**\n * `hasSettled` is optional and read ONLY to suppress a negative verdict from\n * a registry that has not loaded yet — see THE COLD-VERDICT RULE on\n * `ComponentResolutionSource`.\n */\n components: Pick<ComponentResolutionSource, \"resolve\"> &\n Partial<Pick<ComponentResolutionSource, \"hasSettled\">>;\n reportError: ContentIrErrorReporter;\n platform: string;\n}\n\n/** Narrow a host (or anything host-shaped) to what the pure route needs. */\nexport function routeEnvOf(host: ContentIrHost): KindRouteEnv {\n return {\n kinds: host.kinds,\n components: host.components,\n reportError: host.reportError,\n platform: host.platform,\n };\n}\n","\"use client\";\n\n/**\n * The one place a host is wired in. Everything React in this package reads its\n * capability from here — no module singleton, no import into an app.\n *\n * A host mounts this ONCE, high enough that every kind-rendering surface is\n * inside it:\n *\n * ```tsx\n * <ContentIrRenderProvider host={matrxContentIrHost}>\n * <App />\n * </ContentIrRenderProvider>\n * ```\n *\n * Reading it outside a provider THROWS rather than falling back to a default.\n * A silent default would render the wrong component for every kind in the app\n * and look like a data problem for weeks.\n */\n\nimport { createContext, useContext, useMemo, type ReactNode } from \"react\";\nimport type { ContentIrHost, KindRouteEnv } from \"./host-types\";\nimport { routeEnvOf } from \"./host-types\";\n\nconst ContentIrHostContext = createContext<ContentIrHost | null>(null);\n\nexport interface ContentIrRenderProviderProps {\n host: ContentIrHost;\n children: ReactNode;\n}\n\nexport function ContentIrRenderProvider({\n host,\n children,\n}: ContentIrRenderProviderProps) {\n return (\n <ContentIrHostContext.Provider value={host}>\n {children}\n </ContentIrHostContext.Provider>\n );\n}\n\n/**\n * The wired host, or null. For the rare consumer that can legitimately run\n * without a provider because it was handed its sources explicitly (see\n * `useContentIrKindVersion`). Everything else uses {@link useContentIrHost}.\n */\nexport function useContentIrHostOrNull(): ContentIrHost | null {\n return useContext(ContentIrHostContext);\n}\n\n/** The wired host. Throws outside a provider — see the module doc. */\nexport function useContentIrHost(): ContentIrHost {\n const host = useContentIrHostOrNull();\n if (!host) {\n throw new Error(\n \"[content-ir-react] No ContentIrRenderProvider above this component. \" +\n \"Mount one at the app root with your host adapter (kind definitions, \" +\n \"component resolver, renderBlock, renderValue, reportError).\",\n );\n }\n return host;\n}\n\n/** The wired host narrowed to what the pure route functions take. */\nexport function useKindRouteEnv(): KindRouteEnv {\n const host = useContentIrHost();\n return useMemo(() => routeEnvOf(host), [host]);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC2BO,IAAM,uBAA+C,CAAC,WAAW;AACtE,UAAQ,MAAM,gBAAgB,OAAO,OAAO,IAAI,OAAO,OAAO,EAAE;AAClE;;;ACiHO,SAAS,WAAW,MAAmC;AAC5D,SAAO;AAAA,IACL,OAAO,KAAK;AAAA,IACZ,YAAY,KAAK;AAAA,IACjB,aAAa,KAAK;AAAA,IAClB,UAAU,KAAK;AAAA,EACjB;AACF;;;ACjIA,mBAAmE;AAgB/D;AAZJ,IAAM,2BAAuB,4BAAoC,IAAI;AAO9D,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA;AACF,GAAiC;AAC/B,SACE,4CAAC,qBAAqB,UAArB,EAA8B,OAAO,MACnC,UACH;AAEJ;AAOO,SAAS,yBAA+C;AAC7D,aAAO,yBAAW,oBAAoB;AACxC;AAGO,SAAS,mBAAkC;AAChD,QAAM,OAAO,uBAAuB;AACpC,MAAI,CAAC,MAAM;AACT,UAAM,IAAI;AAAA,MACR;AAAA,IAGF;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,kBAAgC;AAC9C,QAAM,OAAO,iBAAiB;AAC9B,aAAO,sBAAQ,MAAM,WAAW,IAAI,GAAG,CAAC,IAAI,CAAC;AAC/C;","names":[]}
|
package/dist/host.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { b as ContentIrErrorReport, a as ContentIrErrorReporter, c as consoleErrorReporter } from './component-resolution.types-
|
|
2
|
-
import { C as ContentIrHost, K as KindRouteEnv } from './host-types-
|
|
3
|
-
export { a as ContentIrRenderSeams, I as IrRenderBlock, b as IrRoutableBlock, c as KindDefinitionSource, S as StructuredValueRenderProps, r as routeEnvOf } from './host-types-
|
|
1
|
+
export { b as ContentIrErrorReport, a as ContentIrErrorReporter, c as consoleErrorReporter } from './component-resolution.types-C1MzCf2s.cjs';
|
|
2
|
+
import { C as ContentIrHost, K as KindRouteEnv } from './host-types-CDcLW0TD.cjs';
|
|
3
|
+
export { a as ContentIrRenderSeams, I as IrRenderBlock, b as IrRoutableBlock, c as KindDefinitionSource, S as StructuredValueRenderProps, r as routeEnvOf } from './host-types-CDcLW0TD.cjs';
|
|
4
4
|
import * as React from 'react';
|
|
5
5
|
import { ReactNode } from 'react';
|
|
6
6
|
import '@ai-matrx/content-ir';
|
package/dist/host.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { b as ContentIrErrorReport, a as ContentIrErrorReporter, c as consoleErrorReporter } from './component-resolution.types-
|
|
2
|
-
import { C as ContentIrHost, K as KindRouteEnv } from './host-types-
|
|
3
|
-
export { a as ContentIrRenderSeams, I as IrRenderBlock, b as IrRoutableBlock, c as KindDefinitionSource, S as StructuredValueRenderProps, r as routeEnvOf } from './host-types-
|
|
1
|
+
export { b as ContentIrErrorReport, a as ContentIrErrorReporter, c as consoleErrorReporter } from './component-resolution.types-C1MzCf2s.js';
|
|
2
|
+
import { C as ContentIrHost, K as KindRouteEnv } from './host-types-CpItjcYh.js';
|
|
3
|
+
export { a as ContentIrRenderSeams, I as IrRenderBlock, b as IrRoutableBlock, c as KindDefinitionSource, S as StructuredValueRenderProps, r as routeEnvOf } from './host-types-CpItjcYh.js';
|
|
4
4
|
import * as React from 'react';
|
|
5
5
|
import { ReactNode } from 'react';
|
|
6
6
|
import '@ai-matrx/content-ir';
|
package/dist/host.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../host/error-report.ts","../host/host-types.ts","../host/ContentIrProvider.tsx"],"sourcesContent":["/**\n * THE SCREAM SEAM.\n *\n * Every recovery path in this package is loud: a defective component row, a\n * failed resolver load, a kind whose component throws on a provisional value.\n * The package refuses to own where those screams land — matrx-frontend routes\n * them to the Error Inspector, the dashboard to its own log, the extension to\n * its background page. Each host binds one function.\n *\n * A host that binds a no-op has chosen silence, which is a defect in itself;\n * {@link consoleErrorReporter} is the honest default.\n */\n\nexport interface ContentIrErrorReport {\n /** Always `\"content-ir\"` — hosts key their capture stores on it. */\n source: \"content-ir\";\n message: string;\n name?: string;\n stack?: string;\n /** Free-form grouping key (the host's `relation`), e.g. `\"partial-kind\"`. */\n relation?: string;\n raw?: unknown;\n}\n\nexport type ContentIrErrorReporter = (report: ContentIrErrorReport) => void;\n\n/** The default when a host binds nothing: never silent. */\nexport const consoleErrorReporter: ContentIrErrorReporter = (report) => {\n console.error(`[content-ir] ${report.message}`, report.raw ?? \"\");\n};\n","/**\n * THE HOST CONTRACT — everything this package refuses to decide.\n *\n * The kernel (`@ai-matrx/content-ir`) proved the shape: extract the portable\n * part, let host capability enter through explicit named seams. The render\n * layer needs four things it must never own:\n *\n * 1. WHERE KIND DEFINITIONS COME FROM (a bundled table, `content_ir`, a REST\n * call). The route only asks \"is this kind registered, and does it carry a\n * legacy bridge / a partial-ready opt-in\".\n * 2. WHERE COMPONENT ROWS COME FROM — {@link ComponentResolutionSource}. The\n * package ships `ComponentResolver`, which any host can construct with its\n * own loaders; a host with its own resolver only has to satisfy the type.\n * 3. HOW A ROUTED BLOCK ACTUALLY DRAWS. `applyIrKindRoute` decides a block's\n * TYPE; turning that type into pixels is the host's dispatch table\n * (matrx-frontend's `BlockRenderer`, the dashboard's small map). The\n * package never imports a component library.\n * 4. WHERE SCREAMS LAND — {@link ContentIrErrorReporter}.\n *\n * No Next.js, no Redux, no Supabase, no router, no host error capture. If a\n * seam is missing, ADD A SEAM — never an import.\n */\n\nimport type { ReactNode } from \"react\";\nimport type { KindDefinition } from \"@ai-matrx/content-ir\";\nimport type { ContentIrErrorReporter } from \"./error-report\";\nimport type { ComponentResolutionSource } from \"../resolver/component-resolution.types\";\n\n/**\n * The minimum a render block must expose for the kind route to work. Hosts\n * pass their own richer block type through; the route is generic over `T` and\n * preserves every extra field.\n */\nexport interface IrRoutableBlock {\n type: string;\n serverData?: Record<string, unknown>;\n metadata?: Record<string, unknown>;\n}\n\n/** A routable block that also carries its source text (the raw region). */\nexport interface IrRenderBlock extends IrRoutableBlock {\n content: string;\n language?: string;\n}\n\n/**\n * Where registered kinds come from. `getDefinition` is the only method the\n * pure route needs; the rest drive the granular repaint and the warm-up tick\n * that keeps a cold registry from being mistaken for \"this kind has no\n * component\".\n */\nexport interface KindDefinitionSource {\n getDefinition(kind: string): KindDefinition | undefined;\n /** Monotonic per-kind version — the repaint snapshot key. */\n getKindVersion(kind: string): number;\n subscribeKind(kind: string, listener: () => void): () => void;\n /** One definition load per app session. */\n ensureWarm(): Promise<void>;\n}\n\n/**\n * The rendering seams. Everything here returns host UI; the package supplies\n * the DECISIONS and the chrome-free structure around them.\n */\nexport interface ContentIrRenderSeams {\n /**\n * Draw a block the kind route has already typed. This is the host's dispatch\n * table — the single place a component key becomes a component.\n */\n renderBlock(block: IrRenderBlock): ReactNode;\n /**\n * THE FLOOR: render ANY JSON value as a human document. Reached when a kind\n * has no render-trusted component, when the value is not an object at all,\n * and by the generic structured view.\n *\n * This is deliberately a seam and not a bundled component. Rendering a value\n * WELL means prose through the host's markdown renderer, media through the\n * host's file handler, and uniform arrays through the host's data table —\n * all of which are host property. A host that has none of those can pass a\n * `<pre>`; it will be honest, just plain.\n */\n renderValue(props: StructuredValueRenderProps): ReactNode;\n /**\n * The \"still arriving\" indicator used by the provisional frame. Optional —\n * hosts without a shimmer get plain text.\n */\n renderShimmer?(text: string): ReactNode;\n /**\n * The honest \"this shape has no custom component yet\" notice. Optional: the\n * package draws a plain amber line when a host supplies nothing, and a host\n * with an icon set or its own callout component supplies that instead. It is\n * a seam and not a bundled component because this package depends on no icon\n * library.\n */\n renderNotice?(text: string): ReactNode;\n}\n\nexport interface StructuredValueRenderProps {\n value: unknown;\n /** The kind slug this value claims, when known. Honesty line only — never a renderer choice. */\n kind?: string;\n /** Why this shape has no custom view, in human words. */\n note?: string;\n /** Show the \"what this is / raw data\" footer. Default true. */\n footer?: boolean;\n}\n\n/**\n * One host, wired once, read by every component in this package through\n * {@link ContentIrRenderProvider}.\n */\nexport interface ContentIrHost extends ContentIrRenderSeams {\n kinds: KindDefinitionSource;\n components: ComponentResolutionSource;\n reportError: ContentIrErrorReporter;\n /**\n * The `kind_component.platform` this host resolves as. \"web\" for every\n * browser UI; the column already models \"react-native\" and friends, and a\n * host that lies here renders the wrong component everywhere.\n */\n platform: string;\n}\n\n/**\n * The pure route's dependencies — a strict subset of {@link ContentIrHost},\n * because `applyIrKindRoute` is called OUTSIDE React (reducers, stream\n * accumulators, tests) where there is no provider to read.\n */\nexport interface KindRouteEnv {\n kinds: Pick<KindDefinitionSource, \"getDefinition\">;\n components: Pick<ComponentResolutionSource, \"resolve\">;\n reportError: ContentIrErrorReporter;\n platform: string;\n}\n\n/** Narrow a host (or anything host-shaped) to what the pure route needs. */\nexport function routeEnvOf(host: ContentIrHost): KindRouteEnv {\n return {\n kinds: host.kinds,\n components: host.components,\n reportError: host.reportError,\n platform: host.platform,\n };\n}\n","\"use client\";\n\n/**\n * The one place a host is wired in. Everything React in this package reads its\n * capability from here — no module singleton, no import into an app.\n *\n * A host mounts this ONCE, high enough that every kind-rendering surface is\n * inside it:\n *\n * ```tsx\n * <ContentIrRenderProvider host={matrxContentIrHost}>\n * <App />\n * </ContentIrRenderProvider>\n * ```\n *\n * Reading it outside a provider THROWS rather than falling back to a default.\n * A silent default would render the wrong component for every kind in the app\n * and look like a data problem for weeks.\n */\n\nimport { createContext, useContext, useMemo, type ReactNode } from \"react\";\nimport type { ContentIrHost, KindRouteEnv } from \"./host-types\";\nimport { routeEnvOf } from \"./host-types\";\n\nconst ContentIrHostContext = createContext<ContentIrHost | null>(null);\n\nexport interface ContentIrRenderProviderProps {\n host: ContentIrHost;\n children: ReactNode;\n}\n\nexport function ContentIrRenderProvider({\n host,\n children,\n}: ContentIrRenderProviderProps) {\n return (\n <ContentIrHostContext.Provider value={host}>\n {children}\n </ContentIrHostContext.Provider>\n );\n}\n\n/**\n * The wired host, or null. For the rare consumer that can legitimately run\n * without a provider because it was handed its sources explicitly (see\n * `useContentIrKindVersion`). Everything else uses {@link useContentIrHost}.\n */\nexport function useContentIrHostOrNull(): ContentIrHost | null {\n return useContext(ContentIrHostContext);\n}\n\n/** The wired host. Throws outside a provider — see the module doc. */\nexport function useContentIrHost(): ContentIrHost {\n const host = useContentIrHostOrNull();\n if (!host) {\n throw new Error(\n \"[content-ir-react] No ContentIrRenderProvider above this component. \" +\n \"Mount one at the app root with your host adapter (kind definitions, \" +\n \"component resolver, renderBlock, renderValue, reportError).\",\n );\n }\n return host;\n}\n\n/** The wired host narrowed to what the pure route functions take. */\nexport function useKindRouteEnv(): KindRouteEnv {\n const host = useContentIrHost();\n return useMemo(() => routeEnvOf(host), [host]);\n}\n"],"mappings":";;;AA2BO,IAAM,uBAA+C,CAAC,WAAW;AACtE,UAAQ,MAAM,gBAAgB,OAAO,OAAO,IAAI,OAAO,OAAO,EAAE;AAClE;;;AC2GO,SAAS,WAAW,MAAmC;AAC5D,SAAO;AAAA,IACL,OAAO,KAAK;AAAA,IACZ,YAAY,KAAK;AAAA,IACjB,aAAa,KAAK;AAAA,IAClB,UAAU,KAAK;AAAA,EACjB;AACF;;;AC3HA,SAAS,eAAe,YAAY,eAA+B;AAgB/D;AAZJ,IAAM,uBAAuB,cAAoC,IAAI;AAO9D,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA;AACF,GAAiC;AAC/B,SACE,oBAAC,qBAAqB,UAArB,EAA8B,OAAO,MACnC,UACH;AAEJ;AAOO,SAAS,yBAA+C;AAC7D,SAAO,WAAW,oBAAoB;AACxC;AAGO,SAAS,mBAAkC;AAChD,QAAM,OAAO,uBAAuB;AACpC,MAAI,CAAC,MAAM;AACT,UAAM,IAAI;AAAA,MACR;AAAA,IAGF;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,kBAAgC;AAC9C,QAAM,OAAO,iBAAiB;AAC9B,SAAO,QAAQ,MAAM,WAAW,IAAI,GAAG,CAAC,IAAI,CAAC;AAC/C;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../host/error-report.ts","../host/host-types.ts","../host/ContentIrProvider.tsx"],"sourcesContent":["/**\n * THE SCREAM SEAM.\n *\n * Every recovery path in this package is loud: a defective component row, a\n * failed resolver load, a kind whose component throws on a provisional value.\n * The package refuses to own where those screams land — matrx-frontend routes\n * them to the Error Inspector, the dashboard to its own log, the extension to\n * its background page. Each host binds one function.\n *\n * A host that binds a no-op has chosen silence, which is a defect in itself;\n * {@link consoleErrorReporter} is the honest default.\n */\n\nexport interface ContentIrErrorReport {\n /** Always `\"content-ir\"` — hosts key their capture stores on it. */\n source: \"content-ir\";\n message: string;\n name?: string;\n stack?: string;\n /** Free-form grouping key (the host's `relation`), e.g. `\"partial-kind\"`. */\n relation?: string;\n raw?: unknown;\n}\n\nexport type ContentIrErrorReporter = (report: ContentIrErrorReport) => void;\n\n/** The default when a host binds nothing: never silent. */\nexport const consoleErrorReporter: ContentIrErrorReporter = (report) => {\n console.error(`[content-ir] ${report.message}`, report.raw ?? \"\");\n};\n","/**\n * THE HOST CONTRACT — everything this package refuses to decide.\n *\n * The kernel (`@ai-matrx/content-ir`) proved the shape: extract the portable\n * part, let host capability enter through explicit named seams. The render\n * layer needs four things it must never own:\n *\n * 1. WHERE KIND DEFINITIONS COME FROM (a bundled table, `content_ir`, a REST\n * call). The route only asks \"is this kind registered, and does it carry a\n * legacy bridge / a partial-ready opt-in\".\n * 2. WHERE COMPONENT ROWS COME FROM — {@link ComponentResolutionSource}. The\n * package ships `ComponentResolver`, which any host can construct with its\n * own loaders; a host with its own resolver only has to satisfy the type.\n * 3. HOW A ROUTED BLOCK ACTUALLY DRAWS. `applyIrKindRoute` decides a block's\n * TYPE; turning that type into pixels is the host's dispatch table\n * (matrx-frontend's `BlockRenderer`, the dashboard's small map). The\n * package never imports a component library.\n * 4. WHERE SCREAMS LAND — {@link ContentIrErrorReporter}.\n *\n * No Next.js, no Redux, no Supabase, no router, no host error capture. If a\n * seam is missing, ADD A SEAM — never an import.\n */\n\nimport type { ReactNode } from \"react\";\nimport type { KindDefinition } from \"@ai-matrx/content-ir\";\nimport type { ContentIrErrorReporter } from \"./error-report\";\nimport type { ComponentResolutionSource } from \"../resolver/component-resolution.types\";\n\n/**\n * The minimum a render block must expose for the kind route to work. Hosts\n * pass their own richer block type through; the route is generic over `T` and\n * preserves every extra field.\n */\nexport interface IrRoutableBlock {\n type: string;\n serverData?: Record<string, unknown>;\n metadata?: Record<string, unknown>;\n}\n\n/** A routable block that also carries its source text (the raw region). */\nexport interface IrRenderBlock extends IrRoutableBlock {\n content: string;\n language?: string;\n}\n\n/**\n * Where registered kinds come from. `getDefinition` is the only method the\n * pure route needs; the rest drive the granular repaint and the warm-up tick\n * that keeps a cold registry from being mistaken for \"this kind has no\n * component\".\n */\nexport interface KindDefinitionSource {\n getDefinition(kind: string): KindDefinition | undefined;\n /** Monotonic per-kind version — the repaint snapshot key. */\n getKindVersion(kind: string): number;\n subscribeKind(kind: string, listener: () => void): () => void;\n /** One definition load per app session. */\n ensureWarm(): Promise<void>;\n}\n\n/**\n * The rendering seams. Everything here returns host UI; the package supplies\n * the DECISIONS and the chrome-free structure around them.\n */\nexport interface ContentIrRenderSeams {\n /**\n * Draw a block the kind route has already typed. This is the host's dispatch\n * table — the single place a component key becomes a component.\n */\n renderBlock(block: IrRenderBlock): ReactNode;\n /**\n * THE FLOOR: render ANY JSON value as a human document. Reached when a kind\n * has no render-trusted component, when the value is not an object at all,\n * and by the generic structured view.\n *\n * This is deliberately a seam and not a bundled component. Rendering a value\n * WELL means prose through the host's markdown renderer, media through the\n * host's file handler, and uniform arrays through the host's data table —\n * all of which are host property. A host that has none of those can pass a\n * `<pre>`; it will be honest, just plain.\n */\n renderValue(props: StructuredValueRenderProps): ReactNode;\n /**\n * The \"still arriving\" indicator used by the provisional frame. Optional —\n * hosts without a shimmer get plain text.\n */\n renderShimmer?(text: string): ReactNode;\n /**\n * The honest \"this shape has no custom component yet\" notice. Optional: the\n * package draws a plain amber line when a host supplies nothing, and a host\n * with an icon set or its own callout component supplies that instead. It is\n * a seam and not a bundled component because this package depends on no icon\n * library.\n */\n renderNotice?(text: string): ReactNode;\n}\n\nexport interface StructuredValueRenderProps {\n value: unknown;\n /** The kind slug this value claims, when known. Honesty line only — never a renderer choice. */\n kind?: string;\n /** Why this shape has no custom view, in human words. */\n note?: string;\n /** Show the \"what this is / raw data\" footer. Default true. */\n footer?: boolean;\n}\n\n/**\n * One host, wired once, read by every component in this package through\n * {@link ContentIrRenderProvider}.\n */\nexport interface ContentIrHost extends ContentIrRenderSeams {\n kinds: KindDefinitionSource;\n components: ComponentResolutionSource;\n reportError: ContentIrErrorReporter;\n /**\n * The `kind_component.platform` this host resolves as. \"web\" for every\n * browser UI; the column already models \"react-native\" and friends, and a\n * host that lies here renders the wrong component everywhere.\n */\n platform: string;\n}\n\n/**\n * The pure route's dependencies — a strict subset of {@link ContentIrHost},\n * because `applyIrKindRoute` is called OUTSIDE React (reducers, stream\n * accumulators, tests) where there is no provider to read.\n */\nexport interface KindRouteEnv {\n kinds: Pick<KindDefinitionSource, \"getDefinition\">;\n /**\n * `hasSettled` is optional and read ONLY to suppress a negative verdict from\n * a registry that has not loaded yet — see THE COLD-VERDICT RULE on\n * `ComponentResolutionSource`.\n */\n components: Pick<ComponentResolutionSource, \"resolve\"> &\n Partial<Pick<ComponentResolutionSource, \"hasSettled\">>;\n reportError: ContentIrErrorReporter;\n platform: string;\n}\n\n/** Narrow a host (or anything host-shaped) to what the pure route needs. */\nexport function routeEnvOf(host: ContentIrHost): KindRouteEnv {\n return {\n kinds: host.kinds,\n components: host.components,\n reportError: host.reportError,\n platform: host.platform,\n };\n}\n","\"use client\";\n\n/**\n * The one place a host is wired in. Everything React in this package reads its\n * capability from here — no module singleton, no import into an app.\n *\n * A host mounts this ONCE, high enough that every kind-rendering surface is\n * inside it:\n *\n * ```tsx\n * <ContentIrRenderProvider host={matrxContentIrHost}>\n * <App />\n * </ContentIrRenderProvider>\n * ```\n *\n * Reading it outside a provider THROWS rather than falling back to a default.\n * A silent default would render the wrong component for every kind in the app\n * and look like a data problem for weeks.\n */\n\nimport { createContext, useContext, useMemo, type ReactNode } from \"react\";\nimport type { ContentIrHost, KindRouteEnv } from \"./host-types\";\nimport { routeEnvOf } from \"./host-types\";\n\nconst ContentIrHostContext = createContext<ContentIrHost | null>(null);\n\nexport interface ContentIrRenderProviderProps {\n host: ContentIrHost;\n children: ReactNode;\n}\n\nexport function ContentIrRenderProvider({\n host,\n children,\n}: ContentIrRenderProviderProps) {\n return (\n <ContentIrHostContext.Provider value={host}>\n {children}\n </ContentIrHostContext.Provider>\n );\n}\n\n/**\n * The wired host, or null. For the rare consumer that can legitimately run\n * without a provider because it was handed its sources explicitly (see\n * `useContentIrKindVersion`). Everything else uses {@link useContentIrHost}.\n */\nexport function useContentIrHostOrNull(): ContentIrHost | null {\n return useContext(ContentIrHostContext);\n}\n\n/** The wired host. Throws outside a provider — see the module doc. */\nexport function useContentIrHost(): ContentIrHost {\n const host = useContentIrHostOrNull();\n if (!host) {\n throw new Error(\n \"[content-ir-react] No ContentIrRenderProvider above this component. \" +\n \"Mount one at the app root with your host adapter (kind definitions, \" +\n \"component resolver, renderBlock, renderValue, reportError).\",\n );\n }\n return host;\n}\n\n/** The wired host narrowed to what the pure route functions take. */\nexport function useKindRouteEnv(): KindRouteEnv {\n const host = useContentIrHost();\n return useMemo(() => routeEnvOf(host), [host]);\n}\n"],"mappings":";;;AA2BO,IAAM,uBAA+C,CAAC,WAAW;AACtE,UAAQ,MAAM,gBAAgB,OAAO,OAAO,IAAI,OAAO,OAAO,EAAE;AAClE;;;ACiHO,SAAS,WAAW,MAAmC;AAC5D,SAAO;AAAA,IACL,OAAO,KAAK;AAAA,IACZ,YAAY,KAAK;AAAA,IACjB,aAAa,KAAK;AAAA,IAClB,UAAU,KAAK;AAAA,EACjB;AACF;;;ACjIA,SAAS,eAAe,YAAY,eAA+B;AAgB/D;AAZJ,IAAM,uBAAuB,cAAoC,IAAI;AAO9D,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA;AACF,GAAiC;AAC/B,SACE,oBAAC,qBAAqB,UAArB,EAA8B,OAAO,MACnC,UACH;AAEJ;AAOO,SAAS,yBAA+C;AAC7D,SAAO,WAAW,oBAAoB;AACxC;AAGO,SAAS,mBAAkC;AAChD,QAAM,OAAO,uBAAuB;AACpC,MAAI,CAAC,MAAM;AACT,UAAM,IAAI;AAAA,MACR;AAAA,IAGF;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,kBAAgC;AAC9C,QAAM,OAAO,iBAAiB;AAC9B,SAAO,QAAQ,MAAM,WAAW,IAAI,GAAG,CAAC,IAAI,CAAC;AAC/C;","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -131,6 +131,13 @@ var ComponentResolver = class {
|
|
|
131
131
|
db = /* @__PURE__ */ new Map();
|
|
132
132
|
warmPromise = null;
|
|
133
133
|
warmFailureLogged = false;
|
|
134
|
+
/**
|
|
135
|
+
* True once a list load has RUN TO COMPLETION (success or failure), or once
|
|
136
|
+
* any rows have been ingested by any tier. Until then `resolve()` answering
|
|
137
|
+
* null means "I have not looked yet" — never "no such component". See THE
|
|
138
|
+
* COLD-VERDICT RULE on `ComponentResolutionSource.hasSettled`.
|
|
139
|
+
*/
|
|
140
|
+
settled = false;
|
|
134
141
|
/**
|
|
135
142
|
* When the last successful wholesale refresh landed, or null for "never".
|
|
136
143
|
* Explicitly nullable rather than 0: with a host-supplied clock that starts
|
|
@@ -244,6 +251,7 @@ var ComponentResolver = class {
|
|
|
244
251
|
* and is_active flips all take effect. Always notifies.
|
|
245
252
|
*/
|
|
246
253
|
replaceDbRows(rows) {
|
|
254
|
+
this.settled = true;
|
|
247
255
|
this.db.clear();
|
|
248
256
|
this.coldMisses.clear();
|
|
249
257
|
for (const row of rows) {
|
|
@@ -388,6 +396,7 @@ var ComponentResolver = class {
|
|
|
388
396
|
if (!this.warmPromise) {
|
|
389
397
|
this.warmPromise = loadAll().then((rows) => {
|
|
390
398
|
this.ingestDbRows(rows);
|
|
399
|
+
this.settled = true;
|
|
391
400
|
}).catch((error) => {
|
|
392
401
|
const message = `component-resolver warm load failed (compiled bootstrap still serving): ${describe(error)}`;
|
|
393
402
|
if (!this.warmFailureLogged) {
|
|
@@ -400,11 +409,17 @@ var ComponentResolver = class {
|
|
|
400
409
|
...errorFields(error),
|
|
401
410
|
raw: error
|
|
402
411
|
});
|
|
412
|
+
this.settled = true;
|
|
403
413
|
this.warmPromise = null;
|
|
404
414
|
});
|
|
405
415
|
}
|
|
406
416
|
return this.warmPromise;
|
|
407
417
|
}
|
|
418
|
+
/** @see ComponentResolutionSource.hasSettled */
|
|
419
|
+
hasSettled() {
|
|
420
|
+
if (!this.options.loadAll) return true;
|
|
421
|
+
return this.settled || this.db.size > 0;
|
|
422
|
+
}
|
|
408
423
|
};
|
|
409
424
|
|
|
410
425
|
// route/kind-route.ts
|
|
@@ -491,6 +506,8 @@ function applyIrKindRoute(block, env, options) {
|
|
|
491
506
|
if (envelope.root.kindState === "pending_schema") return block;
|
|
492
507
|
const def = env.kinds.getDefinition(kind);
|
|
493
508
|
const resolution = env.components.resolve(kind, env.platform, "output");
|
|
509
|
+
const componentsSettled = env.components.hasSettled?.() ?? true;
|
|
510
|
+
if (!componentsSettled && !resolution && !def) return block;
|
|
494
511
|
if (envelope.root.kindState === "raw") {
|
|
495
512
|
return routeToGeneric(
|
|
496
513
|
block,
|