@ai-matrx/content-ir-react 0.8.0 → 0.9.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.
Files changed (38) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/{component-resolution.types-BS1ySIg-.d.cts → component-resolution.types-C1MzCf2s.d.cts} +13 -0
  3. package/dist/{component-resolution.types-BS1ySIg-.d.ts → component-resolution.types-C1MzCf2s.d.ts} +13 -0
  4. package/dist/{component-resolution.types-fvR92hW7.d.cts → component-resolution.types-DLO2w-0n.d.cts} +13 -0
  5. package/dist/{component-resolution.types-fvR92hW7.d.ts → component-resolution.types-DLO2w-0n.d.ts} +13 -0
  6. package/dist/db-component.d.cts +1 -1
  7. package/dist/db-component.d.ts +1 -1
  8. package/dist/{host-types-DvGv8s9L.d.cts → host-types-CDcLW0TD.d.cts} +7 -2
  9. package/dist/{host-types-CZ_Bkp4R.d.ts → host-types-CpItjcYh.d.ts} +7 -2
  10. package/dist/host.cjs.map +1 -1
  11. package/dist/host.d.cts +3 -3
  12. package/dist/host.d.ts +3 -3
  13. package/dist/host.js.map +1 -1
  14. package/dist/index.cjs +16 -0
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +4 -4
  17. package/dist/index.d.ts +4 -4
  18. package/dist/index.js +16 -0
  19. package/dist/index.js.map +1 -1
  20. package/dist/react.cjs.map +1 -1
  21. package/dist/react.d.cts +2 -2
  22. package/dist/react.d.ts +2 -2
  23. package/dist/react.js.map +1 -1
  24. package/dist/resolver.cjs +14 -0
  25. package/dist/resolver.cjs.map +1 -1
  26. package/dist/resolver.d.cts +11 -2
  27. package/dist/resolver.d.ts +11 -2
  28. package/dist/resolver.js +14 -0
  29. package/dist/resolver.js.map +1 -1
  30. package/dist/{route-C1XNcubB.d.ts → route-PUuEuEug.d.ts} +7 -2
  31. package/dist/{route-C55jsF4B.d.cts → route-QL2Vqf2e.d.cts} +7 -2
  32. package/dist/route.cjs +2 -0
  33. package/dist/route.cjs.map +1 -1
  34. package/dist/route.d.cts +2 -2
  35. package/dist/route.d.ts +2 -2
  36. package/dist/route.js +2 -0
  37. package/dist/route.js.map +1 -1
  38. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,56 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.9.0 — 2026-08-31
4
+
5
+ - **THE COLD-VERDICT RULE — a registry that has not looked says nothing.**
6
+ `ComponentResolutionSource` gains optional `hasSettled()`, `ComponentResolver`
7
+ implements it, and `applyIrKindRoute` holds a block (exactly as
8
+ `pending_schema` does) instead of publishing `unregistered` / `no-component`
9
+ while the resolver's list load has not completed and nothing has been
10
+ ingested.
11
+
12
+ WHY: every generic-fallback reason is a durable, user-visible claim written
13
+ into the block's `metadata.__ir_route`. On the FIRST PAINT of a fresh tab the
14
+ resolver has fetched nothing, so `resolve()` returning null meant both "no
15
+ such component" and "I haven't looked" — and the route could not tell them
16
+ apart. Live report (2026-08-31): `agent_mandate_specification`, registered +
17
+ active with an active `source='db'` component, rendered on /chat as a
18
+ key/value dump captioned "this shape isn't registered on this platform".
19
+ The same conversation rendered correctly in a window panel whose registries
20
+ were already warm.
21
+
22
+ A POSITIVE answer is never suppressed (compiled floor and already-ingested
23
+ rows route immediately), a FAILED list load still settles (blocks are never
24
+ held forever), and a resolver with no `loadAll` is settled from birth. Once
25
+ settled, a genuinely unknown kind still reaches the generic floor with
26
+ `unregistered` exactly as before.
27
+
28
+ Pinned by `__tests__/cold-verdict-rule.test.ts` (5 tests, built from the
29
+ live row that failed).
30
+
31
+ ## 0.8.1 — 2026-08-30
32
+
33
+ - **Republished against `@ai-matrx/content-ir` 0.10.0.** The 0.8.0 tarball
34
+ declares `"@ai-matrx/content-ir": "^0.9.0"`, and on a `0.x` line that caret
35
+ range EXCLUDES 0.10.0 — so a host installing both packages at `"latest"`
36
+ resolved content-ir 0.10.0 at the top level and a NESTED 0.9.0 underneath
37
+ this one: two copies of the kernel in one graph. This release carries the
38
+ 0.10.0 spec so one version serves both.
39
+
40
+ No source change. This package's imports stay on the content-ir ROOT
41
+ export, which 0.10.0 keeps as the full surface; the new area subpaths
42
+ (`/core`, `/session`, `/registry`, `/convert`, `/wire`) would only split
43
+ this package's mixed-area import statements, since it reaches four of the
44
+ five areas anyway.
45
+
46
+ In-monorepo the spec is `workspace:*` (THE LATEST LAW's monorepo form); pnpm
47
+ substitutes the local content-ir version at pack time. Do NOT hand-write a
48
+ published range here — `^0.10.0` written into the source manifest is an
49
+ unresolvable spec until that version exists, and it breaks
50
+ `pnpm install --frozen-lockfile` for ALL 17 workspace projects, which is the
51
+ first step of every package's publish workflow (it briefly broke the release
52
+ lane for print, content-ir, and this package on 2026-08-30).
53
+
3
54
  ## 0.8.0 — 2026-08-30
4
55
 
5
56
  The CONTENT-IR-REACT row of the C23 all-inclusive retrofit register: the
@@ -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? */
@@ -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? */
@@ -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? */
@@ -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? */
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { C as ComponentResolution, a as ContentIrErrorReporter } from './component-resolution.types-BS1ySIg-.cjs';
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
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { C as ComponentResolution, a as ContentIrErrorReporter } from './component-resolution.types-BS1ySIg-.js';
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-BS1ySIg-.cjs';
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
- components: Pick<ComponentResolutionSource, "resolve">;
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-BS1ySIg-.js';
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
- components: Pick<ComponentResolutionSource, "resolve">;
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-BS1ySIg-.cjs';
2
- import { C as ContentIrHost, K as KindRouteEnv } from './host-types-DvGv8s9L.cjs';
3
- export { a as ContentIrRenderSeams, I as IrRenderBlock, b as IrRoutableBlock, c as KindDefinitionSource, S as StructuredValueRenderProps, r as routeEnvOf } from './host-types-DvGv8s9L.cjs';
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-BS1ySIg-.js';
2
- import { C as ContentIrHost, K as KindRouteEnv } from './host-types-CZ_Bkp4R.js';
3
- export { a as ContentIrRenderSeams, I as IrRenderBlock, b as IrRoutableBlock, c as KindDefinitionSource, S as StructuredValueRenderProps, r as routeEnvOf } from './host-types-CZ_Bkp4R.js';
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
@@ -388,6 +395,7 @@ var ComponentResolver = class {
388
395
  if (!this.warmPromise) {
389
396
  this.warmPromise = loadAll().then((rows) => {
390
397
  this.ingestDbRows(rows);
398
+ this.settled = true;
391
399
  }).catch((error) => {
392
400
  const message = `component-resolver warm load failed (compiled bootstrap still serving): ${describe(error)}`;
393
401
  if (!this.warmFailureLogged) {
@@ -400,11 +408,17 @@ var ComponentResolver = class {
400
408
  ...errorFields(error),
401
409
  raw: error
402
410
  });
411
+ this.settled = true;
403
412
  this.warmPromise = null;
404
413
  });
405
414
  }
406
415
  return this.warmPromise;
407
416
  }
417
+ /** @see ComponentResolutionSource.hasSettled */
418
+ hasSettled() {
419
+ if (!this.options.loadAll) return true;
420
+ return this.settled || this.db.size > 0;
421
+ }
408
422
  };
409
423
 
410
424
  // route/kind-route.ts
@@ -491,6 +505,8 @@ function applyIrKindRoute(block, env, options) {
491
505
  if (envelope.root.kindState === "pending_schema") return block;
492
506
  const def = env.kinds.getDefinition(kind);
493
507
  const resolution = env.components.resolve(kind, env.platform, "output");
508
+ const componentsSettled = env.components.hasSettled?.() ?? true;
509
+ if (!componentsSettled && !resolution && !def) return block;
494
510
  if (envelope.root.kindState === "raw") {
495
511
  return routeToGeneric(
496
512
  block,