@ai-matrx/rich-content 0.0.0-stage → 0.2.2

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 (247) hide show
  1. package/CHANGELOG.md +72 -0
  2. package/LICENSE +21 -0
  3. package/README.md +61 -2
  4. package/dist/display/blocks/csv/CsvBlock.d.ts +10 -0
  5. package/dist/display/blocks/csv/CsvBlock.js +245 -0
  6. package/dist/display/blocks/table/parseMarkdownTable.d.ts +20 -0
  7. package/dist/display/blocks/table/parseMarkdownTable.js +35 -0
  8. package/dist/display/chat-markdown/citations/remarkMatrxCite.d.ts +33 -0
  9. package/dist/display/chat-markdown/citations/remarkMatrxCite.js +71 -0
  10. package/dist/display/chat-markdown/matrx-variables/remarkMatrxVariable.d.ts +29 -0
  11. package/dist/display/chat-markdown/matrx-variables/remarkMatrxVariable.js +71 -0
  12. package/dist/display/chat-markdown/page-break/remarkMatrxPageBreak.d.ts +55 -0
  13. package/dist/display/chat-markdown/page-break/remarkMatrxPageBreak.js +108 -0
  14. package/dist/display/chat-markdown/rehypeSafeRawHtml.d.ts +59 -0
  15. package/dist/display/chat-markdown/rehypeSafeRawHtml.js +140 -0
  16. package/dist/display/markdown-classification/processors/bock-processors/parse-markdown-table.d.ts +14 -0
  17. package/dist/display/markdown-classification/processors/bock-processors/parse-markdown-table.js +171 -0
  18. package/dist/display/markdown-classification/processors/types.d.ts +120 -0
  19. package/dist/display/markdown-classification/processors/types.js +10 -0
  20. package/dist/display/markdown-classification/processors/utils/client-blocks.d.ts +169 -0
  21. package/dist/display/markdown-classification/processors/utils/client-blocks.js +0 -0
  22. package/dist/display/markdown-classification/processors/utils/content-splitter-core.d.ts +223 -0
  23. package/dist/display/markdown-classification/processors/utils/content-splitter-core.js +1791 -0
  24. package/dist/display/markdown-classification/processors/utils/content-splitter-v2.d.ts +15 -0
  25. package/dist/display/markdown-classification/processors/utils/content-splitter-v2.js +19 -0
  26. package/dist/display/markdown-classification/processors/utils/expand-text-blocks.d.ts +9 -0
  27. package/dist/display/markdown-classification/processors/utils/expand-text-blocks.js +36 -0
  28. package/dist/display/markdown-classification/processors/utils/gfm-table-lines.d.ts +5 -0
  29. package/dist/display/markdown-classification/processors/utils/gfm-table-lines.js +40 -0
  30. package/dist/display/markdown-classification/processors/utils/gfm-table-vector-inputs.d.ts +16 -0
  31. package/dist/display/markdown-classification/processors/utils/gfm-table-vector-inputs.js +385 -0
  32. package/dist/display/markdown-classification/processors/utils/gfm-table-vectors.d.ts +43 -0
  33. package/dist/display/markdown-classification/processors/utils/gfm-table-vectors.js +33 -0
  34. package/dist/display/markdown-classification/processors/utils/table-data-parser.d.ts +9 -0
  35. package/dist/display/markdown-classification/processors/utils/table-data-parser.js +30 -0
  36. package/dist/display/markdown-classification/processors/utils/thinking-parser.d.ts +7 -0
  37. package/dist/display/markdown-classification/processors/utils/thinking-parser.js +70 -0
  38. package/dist/display/render-block.d.ts +23 -0
  39. package/dist/display/render-block.js +0 -0
  40. package/dist/display/themes.d.ts +1023 -0
  41. package/dist/display/themes.js +1105 -0
  42. package/dist/display/types.d.ts +32 -0
  43. package/dist/display/types.js +0 -0
  44. package/dist/host/ContentIrHostBoundary.d.ts +8 -0
  45. package/dist/host/ContentIrHostBoundary.js +15 -0
  46. package/dist/host/ErrorActions.d.ts +4 -0
  47. package/dist/host/ErrorActions.js +11 -0
  48. package/dist/host/NestedContent.d.ts +3 -0
  49. package/dist/host/NestedContent.js +12 -0
  50. package/dist/host/ResourcePeek.d.ts +6 -0
  51. package/dist/host/ResourcePeek.js +14 -0
  52. package/dist/host/component-registry.d.ts +2 -0
  53. package/dist/host/component-registry.js +25 -0
  54. package/dist/host/diagnostics.d.ts +2 -0
  55. package/dist/host/diagnostics.js +15 -0
  56. package/dist/host/index.d.ts +3 -0
  57. package/dist/host/index.js +18 -0
  58. package/dist/host/kind-incident.d.ts +3 -0
  59. package/dist/host/kind-incident.js +12 -0
  60. package/dist/host/kind-registry.d.ts +2 -0
  61. package/dist/host/kind-registry.js +35 -0
  62. package/dist/host/people.d.ts +3 -0
  63. package/dist/host/people.js +12 -0
  64. package/dist/host/registry.d.ts +27 -0
  65. package/dist/host/registry.js +55 -0
  66. package/dist/host/splitter-envelopes.d.ts +2 -0
  67. package/dist/host/splitter-envelopes.js +7 -0
  68. package/dist/host/tables.d.ts +6 -0
  69. package/dist/host/tables.js +8 -0
  70. package/dist/host/toast.d.ts +2 -0
  71. package/dist/host/toast.js +57 -0
  72. package/dist/host/types.d.ts +157 -0
  73. package/dist/host/types.js +0 -0
  74. package/dist/host/wikilinks.d.ts +15 -0
  75. package/dist/host/wikilinks.js +23 -0
  76. package/dist/kinds/host/route-env.d.ts +33 -0
  77. package/dist/kinds/host/route-env.js +16 -0
  78. package/dist/kinds/react/KindEscapedNotice.d.ts +14 -0
  79. package/dist/kinds/react/KindEscapedNotice.js +72 -0
  80. package/dist/kinds/react/ProvisionalKindBoundary.d.ts +19 -0
  81. package/dist/kinds/react/ProvisionalKindBoundary.js +17 -0
  82. package/dist/kinds/react/ensure-kind-renderable.d.ts +14 -0
  83. package/dist/kinds/react/ensure-kind-renderable.js +45 -0
  84. package/dist/kinds/react/kind-problems.d.ts +62 -0
  85. package/dist/kinds/react/kind-problems.js +134 -0
  86. package/dist/kinds/react/kind-route.d.ts +23 -0
  87. package/dist/kinds/react/kind-route.js +24 -0
  88. package/dist/kinds/react/loading/infer-loading-slug.d.ts +58 -0
  89. package/dist/kinds/react/loading/infer-loading-slug.js +100 -0
  90. package/dist/kinds/react/loading/kind-loading-components.d.ts +48 -0
  91. package/dist/kinds/react/loading/kind-loading-components.js +447 -0
  92. package/dist/kinds/react/loading/kind-loading-registry.d.ts +21 -0
  93. package/dist/kinds/react/loading/kind-loading-registry.js +62 -0
  94. package/dist/kinds/react/loading/kind-loading-slugs.d.ts +18 -0
  95. package/dist/kinds/react/loading/kind-loading-slugs.js +34 -0
  96. package/dist/kinds/react/loading/kind-loading.types.d.ts +79 -0
  97. package/dist/kinds/react/loading/kind-loading.types.js +31 -0
  98. package/dist/kinds/react/loading/resolve-loading-slug.d.ts +29 -0
  99. package/dist/kinds/react/loading/resolve-loading-slug.js +51 -0
  100. package/dist/kinds/react/partial-kind-route.d.ts +32 -0
  101. package/dist/kinds/react/partial-kind-route.js +27 -0
  102. package/dist/kinds/react/registry-versioned.d.ts +54 -0
  103. package/dist/kinds/react/registry-versioned.js +18 -0
  104. package/dist/kinds/react/route-at-version.d.ts +38 -0
  105. package/dist/kinds/react/route-at-version.js +78 -0
  106. package/dist/kinds/react/slot/KindSlot.d.ts +87 -0
  107. package/dist/kinds/react/slot/KindSlot.js +65 -0
  108. package/dist/kinds/react/use-registry-repaint.d.ts +6 -0
  109. package/dist/kinds/react/use-registry-repaint.js +36 -0
  110. package/dist/kinds/react/useIrNode.d.ts +9 -0
  111. package/dist/kinds/react/useIrNode.js +46 -0
  112. package/dist/kinds/react/useLiveJsonRegion.d.ts +15 -0
  113. package/dist/kinds/react/useLiveJsonRegion.js +84 -0
  114. package/dist/kinds/redux/render-block-envelope.d.ts +14 -0
  115. package/dist/kinds/redux/render-block-envelope.js +26 -0
  116. package/dist/kinds/registry/kind-correctors.d.ts +63 -0
  117. package/dist/kinds/registry/kind-correctors.js +94 -0
  118. package/dist/kinds/registry/legacy-quiz-envelope.d.ts +1 -0
  119. package/dist/kinds/registry/legacy-quiz-envelope.js +1 -0
  120. package/dist/kinds/registry/region-envelope-memo.d.ts +45 -0
  121. package/dist/kinds/registry/region-envelope-memo.js +94 -0
  122. package/dist/kinds/registry/registry-debug.d.ts +38 -0
  123. package/dist/kinds/registry/registry-debug.js +39 -0
  124. package/dist/markdown-core/MarkdownCore.d.ts +6 -0
  125. package/dist/markdown-core/MarkdownCore.js +32 -0
  126. package/dist/markdown-core/MarkdownCoreImpl.d.ts +3 -0
  127. package/dist/markdown-core/MarkdownCoreImpl.js +27 -0
  128. package/dist/markdown-core/MarkdownCoreServer.d.ts +4 -0
  129. package/dist/markdown-core/MarkdownCoreServer.js +26 -0
  130. package/dist/markdown-core/heading-anchors-context.d.ts +2 -0
  131. package/dist/markdown-core/heading-anchors-context.js +11 -0
  132. package/dist/markdown-core/heading-anchors-props.d.ts +2 -0
  133. package/dist/markdown-core/heading-anchors-props.js +6 -0
  134. package/dist/markdown-core/markdown-core-html.d.ts +3 -0
  135. package/dist/markdown-core/markdown-core-html.js +33 -0
  136. package/dist/markdown-core/markdown-core-presets.d.ts +22 -0
  137. package/dist/markdown-core/markdown-core-presets.js +118 -0
  138. package/dist/markdown-core/markdown-core-types.d.ts +43 -0
  139. package/dist/markdown-core/markdown-core-types.js +0 -0
  140. package/dist/markdown-core/math/vendor/micromark-math-math-flow.d.ts +15 -0
  141. package/dist/markdown-core/math/vendor/micromark-math-math-flow.js +143 -0
  142. package/dist/markdown-core/math/vendor/micromark-math-math-text.d.ts +24 -0
  143. package/dist/markdown-core/math/vendor/micromark-math-math-text.js +127 -0
  144. package/dist/markdown-core/math/vendor/micromark-math-syntax.d.ts +30 -0
  145. package/dist/markdown-core/math/vendor/micromark-math-syntax.js +15 -0
  146. package/dist/markdown-core/math/vendor/rehype-katex.d.ts +15 -0
  147. package/dist/markdown-core/math/vendor/rehype-katex.js +83 -0
  148. package/dist/markdown-core/math/vendor/remark-math.d.ts +9 -0
  149. package/dist/markdown-core/math/vendor/remark-math.js +20 -0
  150. package/dist/markdown-core/math-normalizer.d.ts +57 -0
  151. package/dist/markdown-core/math-normalizer.js +315 -0
  152. package/dist/markdown-core/plain-title.d.ts +2 -0
  153. package/dist/markdown-core/plain-title.js +1 -0
  154. package/dist/markdown-core/stream-heal.d.ts +2 -0
  155. package/dist/markdown-core/stream-heal.js +184 -0
  156. package/dist/markdown-core/streaming-context.d.ts +2 -0
  157. package/dist/markdown-core/streaming-context.js +11 -0
  158. package/dist/markdown-core/syntax/callout-types.d.ts +9 -0
  159. package/dist/markdown-core/syntax/callout-types.js +101 -0
  160. package/dist/markdown-core/syntax/containers.d.ts +17 -0
  161. package/dist/markdown-core/syntax/containers.js +353 -0
  162. package/dist/markdown-core/syntax/document-numbering.d.ts +52 -0
  163. package/dist/markdown-core/syntax/document-numbering.js +184 -0
  164. package/dist/markdown-core/syntax/elements/CalloutIcon.d.ts +3 -0
  165. package/dist/markdown-core/syntax/elements/CalloutIcon.js +41 -0
  166. package/dist/markdown-core/syntax/elements/CrossRef.d.ts +12 -0
  167. package/dist/markdown-core/syntax/elements/CrossRef.js +57 -0
  168. package/dist/markdown-core/syntax/elements/CsvFence.d.ts +4 -0
  169. package/dist/markdown-core/syntax/elements/CsvFence.js +18 -0
  170. package/dist/markdown-core/syntax/elements/DetailsElements.d.ts +12 -0
  171. package/dist/markdown-core/syntax/elements/DetailsElements.js +38 -0
  172. package/dist/markdown-core/syntax/elements/DocumentNumbering.d.ts +20 -0
  173. package/dist/markdown-core/syntax/elements/DocumentNumbering.js +37 -0
  174. package/dist/markdown-core/syntax/elements/DocumentPropertiesPanel.d.ts +4 -0
  175. package/dist/markdown-core/syntax/elements/DocumentPropertiesPanel.js +46 -0
  176. package/dist/markdown-core/syntax/elements/InDocAnchor.d.ts +11 -0
  177. package/dist/markdown-core/syntax/elements/InDocAnchor.js +87 -0
  178. package/dist/markdown-core/syntax/elements/MarkdownSourceEdit.d.ts +24 -0
  179. package/dist/markdown-core/syntax/elements/MarkdownSourceEdit.js +28 -0
  180. package/dist/markdown-core/syntax/elements/MatrxTabs.d.ts +10 -0
  181. package/dist/markdown-core/syntax/elements/MatrxTabs.js +59 -0
  182. package/dist/markdown-core/syntax/elements/MentionChip.d.ts +7 -0
  183. package/dist/markdown-core/syntax/elements/MentionChip.js +69 -0
  184. package/dist/markdown-core/syntax/elements/NestedBody.d.ts +3 -0
  185. package/dist/markdown-core/syntax/elements/NestedBody.js +13 -0
  186. package/dist/markdown-core/syntax/elements/TableOfContents.d.ts +5 -0
  187. package/dist/markdown-core/syntax/elements/TableOfContents.js +44 -0
  188. package/dist/markdown-core/syntax/elements/TaskCheckbox.d.ts +7 -0
  189. package/dist/markdown-core/syntax/elements/TaskCheckbox.js +63 -0
  190. package/dist/markdown-core/syntax/elements/WikiEmbed.d.ts +7 -0
  191. package/dist/markdown-core/syntax/elements/WikiEmbed.js +68 -0
  192. package/dist/markdown-core/syntax/elements/WikiLink.d.ts +10 -0
  193. package/dist/markdown-core/syntax/elements/WikiLink.js +114 -0
  194. package/dist/markdown-core/syntax/elements/core-syntax-elements.d.ts +22 -0
  195. package/dist/markdown-core/syntax/elements/core-syntax-elements.js +70 -0
  196. package/dist/markdown-core/syntax/elements/find-in-document.d.ts +3 -0
  197. package/dist/markdown-core/syntax/elements/find-in-document.js +20 -0
  198. package/dist/markdown-core/syntax/elements/wiki-target.d.ts +5 -0
  199. package/dist/markdown-core/syntax/elements/wiki-target.js +8 -0
  200. package/dist/markdown-core/syntax/frontmatter.d.ts +26 -0
  201. package/dist/markdown-core/syntax/frontmatter.js +72 -0
  202. package/dist/markdown-core/syntax/gfm-cell-pipes.d.ts +11 -0
  203. package/dist/markdown-core/syntax/gfm-cell-pipes.js +4 -0
  204. package/dist/markdown-core/syntax/inline-syntax.d.ts +26 -0
  205. package/dist/markdown-core/syntax/inline-syntax.js +163 -0
  206. package/dist/markdown-core/syntax/linear-scan.d.ts +46 -0
  207. package/dist/markdown-core/syntax/linear-scan.js +129 -0
  208. package/dist/markdown-core/syntax/mdast-helpers.d.ts +48 -0
  209. package/dist/markdown-core/syntax/mdast-helpers.js +48 -0
  210. package/dist/markdown-core/syntax/mentions.d.ts +2 -0
  211. package/dist/markdown-core/syntax/mentions.js +42 -0
  212. package/dist/markdown-core/syntax/names.d.ts +6 -0
  213. package/dist/markdown-core/syntax/names.js +18 -0
  214. package/dist/markdown-core/syntax/prepare-syntax-source.d.ts +1 -0
  215. package/dist/markdown-core/syntax/prepare-syntax-source.js +78 -0
  216. package/dist/markdown-core/syntax/rehype-matrx-syntax.d.ts +9 -0
  217. package/dist/markdown-core/syntax/rehype-matrx-syntax.js +180 -0
  218. package/dist/markdown-core/syntax/remark-inline-only.d.ts +23 -0
  219. package/dist/markdown-core/syntax/remark-inline-only.js +25 -0
  220. package/dist/markdown-core/syntax/remark-matrx-syntax.d.ts +7 -0
  221. package/dist/markdown-core/syntax/remark-matrx-syntax.js +351 -0
  222. package/dist/markdown-core/syntax/remark-table-code-pipes.d.ts +7 -0
  223. package/dist/markdown-core/syntax/remark-table-code-pipes.js +23 -0
  224. package/dist/markdown-core/syntax/stream-heal-syntax.d.ts +2 -0
  225. package/dist/markdown-core/syntax/stream-heal-syntax.js +108 -0
  226. package/dist/markdown-core/syntax/task-source.d.ts +10 -0
  227. package/dist/markdown-core/syntax/task-source.js +34 -0
  228. package/dist/markdown-core/syntax/useDocumentProperties.d.ts +3 -0
  229. package/dist/markdown-core/syntax/useDocumentProperties.js +8 -0
  230. package/dist/styles.css +0 -0
  231. package/dist/utils/addressWithoutNavigating.d.ts +68 -0
  232. package/dist/utils/addressWithoutNavigating.js +60 -0
  233. package/dist/utils/client-lazy.d.ts +13 -0
  234. package/dist/utils/client-lazy.js +24 -0
  235. package/dist/utils/decision-options.d.ts +21 -0
  236. package/dist/utils/decision-options.js +32 -0
  237. package/dist/utils/gfm-lexer.d.ts +5 -0
  238. package/dist/utils/gfm-lexer.js +10 -0
  239. package/dist/utils/json.d.ts +63 -0
  240. package/dist/utils/json.js +22 -0
  241. package/dist/utils/plain-title.d.ts +25 -0
  242. package/dist/utils/plain-title.js +51 -0
  243. package/dist/utils/table-source.d.ts +62 -0
  244. package/dist/utils/table-source.js +191 -0
  245. package/dist/utils/youtube.d.ts +52 -0
  246. package/dist/utils/youtube.js +137 -0
  247. package/package.json +134 -4
@@ -0,0 +1,79 @@
1
+ /**
2
+ * The kind loading-component contract — the EARLY-KEY interface between a
3
+ * streaming `__kind` payload and the hardcoded loading library.
4
+ *
5
+ * THE EARLY-KEY CONTRACT (teach emitters to send these FIRST):
6
+ * While a kind instance streams — and especially while its schema/component
7
+ * are still cold-fetching — the parser surfaces the region's top-level
8
+ * SCALAR values as they arrive. The loading layer reads this default key set
9
+ * from the envelope's early value:
10
+ *
11
+ * - `title` string — the instance's display title
12
+ * - `description` string — one-line summary of the content
13
+ * - `loading_message` string — what to show while the rest streams
14
+ * (e.g. "Pouring your wine tasting…")
15
+ * - `loading_subtext` string — secondary line under the message
16
+ * - `icon` string — icon hint (a slug from ICON_HINTS; unknown
17
+ * hints fall back to the component's default)
18
+ * - `count` number — expected item count (drives how many
19
+ * skeleton rows/cells render)
20
+ *
21
+ * A kind that wants a meaningful loading state should order these keys FIRST
22
+ * in its schema/sample so they stream in before the heavy fields. All keys
23
+ * are optional — every loader renders sensibly with none of them.
24
+ *
25
+ * WHICH LOADER RENDERS: `kind_definition.metadata.loading_component` names a
26
+ * slug from the library (see kind-loading-registry.ts). Missing/unknown slug
27
+ * → the `generic` skeleton. The library is hardcoded (zero fetch delay) and
28
+ * intentionally light — no heavy deps, semantic tokens, Lucide only.
29
+ */
30
+ /**
31
+ * THE TWO PHASES of a loading silhouette (Arman, 2026-08-25).
32
+ *
33
+ * - `reserved` — the PLACEHOLDER. The slot exists and holds the footprint its
34
+ * content will need, but nothing has happened yet: no spinner, no shimmer,
35
+ * one slow breath on the icon. "It looks like a loading one, but it's
36
+ * fairly steady… without looking like it's actively, instantly loading."
37
+ * Modelled on `PodcastCompositionPlaceholder`, which proved the look.
38
+ * - `arriving` — the LOADING state. Same silhouette, now visibly working:
39
+ * spinner, shimmering bars, live early keys filling in as they stream.
40
+ *
41
+ * Same component, same footprint, so the placeholder→loading transition moves
42
+ * nothing on screen. Defaults to `arriving`, which is what every pre-2026-08-25
43
+ * call site meant.
44
+ */
45
+ export type KindLoadingPhase = "reserved" | "arriving";
46
+ export interface KindLoadingProps {
47
+ /** The identified kind slug (shown as a subtle chip when no title yet). */
48
+ kind?: string;
49
+ /** Placeholder (footprint only) vs actively loading. Default `arriving`. */
50
+ phase?: KindLoadingPhase;
51
+ /**
52
+ * `full` (default) draws the loader's own frame and header — the right
53
+ * thing when it stands alone in a chat stream. `bare` draws ONLY the
54
+ * skeleton body, for a host that already renders the frame, icon, and
55
+ * title: a component never repeats chrome its host provides. Mirrors
56
+ * `LiveRunDisplay variant="bare"`.
57
+ */
58
+ chrome?: "full" | "bare";
59
+ title?: string;
60
+ description?: string;
61
+ loadingMessage?: string;
62
+ loadingSubtext?: string;
63
+ /** Icon hint slug (ICON_HINTS key); unknown → the loader's default. */
64
+ icon?: string;
65
+ /** Expected item count — clamped by each loader to a sane skeleton count. */
66
+ count?: number;
67
+ /**
68
+ * THE SMART-LOADER FEED: the region's full partial value, exactly as it
69
+ * stands this frame (grows monotonically, never rewrites). Library
70
+ * skeletons ignore it; a data-fed loader reads it to PERFORM the arrival —
71
+ * surface real text as it lands, step counts up, soft-fade each piece in
72
+ * (Arman, 2026-08-24: animated, intelligent, never generic). Always
73
+ * provided by the pending render path; optional so static previews can
74
+ * render a loader with no stream behind it.
75
+ */
76
+ value?: Record<string, unknown> | null;
77
+ }
78
+ /** Read the early-key set out of an envelope's (partial) root value. */
79
+ export declare function earlyKeysFromValue(value: Record<string, unknown> | null | undefined, kind?: string): KindLoadingProps;
@@ -0,0 +1,31 @@
1
+ function earlyKeysFromValue(value, kind) {
2
+ const v = value ?? {};
3
+ const str = (k) => typeof v[k] === "string" && v[k].length > 0 ? v[k] : void 0;
4
+ const num = (k) => typeof v[k] === "number" && Number.isFinite(v[k]) ? v[k] : void 0;
5
+ const props = {};
6
+ if (kind) props.kind = kind;
7
+ const title = str("title");
8
+ if (title) props.title = title;
9
+ const description = str("description");
10
+ if (description) props.description = description;
11
+ const loadingMessage = str("loading_message");
12
+ if (loadingMessage) props.loadingMessage = loadingMessage;
13
+ const loadingSubtext = str("loading_subtext");
14
+ if (loadingSubtext) props.loadingSubtext = loadingSubtext;
15
+ const icon = str("icon");
16
+ if (icon) props.icon = icon;
17
+ const count = num("count");
18
+ if (count !== void 0) {
19
+ props.count = count;
20
+ } else {
21
+ let largest = 0;
22
+ for (const item of Object.values(v)) {
23
+ if (Array.isArray(item) && item.length > largest) largest = item.length;
24
+ }
25
+ if (largest > 0) props.count = largest;
26
+ }
27
+ return props;
28
+ }
29
+ export {
30
+ earlyKeysFromValue
31
+ };
@@ -0,0 +1,29 @@
1
+ import { type KindLoadingSlug } from "./kind-loading-slugs.js";
2
+ /** Where the answer came from — surfaced so the Stream tab / doctor can say. */
3
+ export type LoadingSlugOrigin = "declared" | "derived" | "generic";
4
+ export interface LoadingSlugResolution {
5
+ /** The library slug, or null when nothing beat the generic skeleton. */
6
+ slug: KindLoadingSlug | null;
7
+ origin: LoadingSlugOrigin;
8
+ /**
9
+ * The declared value when it was NOT a library slug — a data defect that
10
+ * resolution routed around. Present means "this kind declares a lie".
11
+ */
12
+ invalidDeclared?: string;
13
+ }
14
+ /** Test seam — resets the once-per-kind scream dedupe. */
15
+ export declare function resetInvalidLoadingDeclarationReports(): void;
16
+ /**
17
+ * Which loading silhouette does this kind get?
18
+ *
19
+ * 1. DECLARED — `metadata.loading_component` (read through the registry, not
20
+ * off the definition: a Python-owned kind never produces a definition, so
21
+ * its owner's choice lives only in the catalog side map) when it names a
22
+ * real library slug.
23
+ * 2. DERIVED — from the kind's own parser schema, else from its emitted JSON
24
+ * Schema (the only shape description most kinds carry). Costs nothing to
25
+ * author and gives 857-of-868 undeclared kinds a shaped loader.
26
+ * 3. GENERIC — nothing distinctive enough; `null` lets the registry's own
27
+ * default answer.
28
+ */
29
+ export declare function resolveLoadingSlugForKind(kind: string | null | undefined): LoadingSlugResolution;
@@ -0,0 +1,51 @@
1
+ "use client";
2
+ import { captureError } from "../../../host/diagnostics.js";
3
+ import { kindRegistry } from "../../../host/kind-registry.js";
4
+ import {
5
+ inferLoadingSlug,
6
+ inferLoadingSlugFromJsonSchema
7
+ } from "./infer-loading-slug.js";
8
+ import { isKnownKindLoadingSlug } from "./kind-loading-slugs.js";
9
+ const GENERIC = { slug: null, origin: "generic" };
10
+ const reportedInvalidDeclarations = /* @__PURE__ */ new Set();
11
+ function reportInvalidDeclaration(kind, declared) {
12
+ const seenKey = `${kind}\0${declared}`;
13
+ if (reportedInvalidDeclarations.has(seenKey)) return;
14
+ reportedInvalidDeclarations.add(seenKey);
15
+ const message = `[content-ir] kind "${kind}" declares loading_component "${declared}", which is not in the loading library (kind-loading-slugs.ts). Falling back to the DERIVED loader so the declaration cannot make the render worse \u2014 but the declaration is a defect: fix the row or add "${declared}" to the library.`;
16
+ console.error(message);
17
+ try {
18
+ captureError({
19
+ source: "content-ir",
20
+ message,
21
+ relation: kind,
22
+ callSite: "resolveLoadingSlugForKind",
23
+ hint: "kind_definition.metadata.loading_component must name a slug from KIND_LOADING_SLUGS.",
24
+ raw: { kind, declared }
25
+ });
26
+ } catch {
27
+ }
28
+ }
29
+ function resetInvalidLoadingDeclarationReports() {
30
+ reportedInvalidDeclarations.clear();
31
+ }
32
+ function resolveLoadingSlugForKind(kind) {
33
+ if (!kind) return GENERIC;
34
+ const raw = kindRegistry.getDeclaredLoadingComponent(kind)?.trim() ?? "";
35
+ if (raw && isKnownKindLoadingSlug(raw)) {
36
+ return { slug: raw, origin: "declared" };
37
+ }
38
+ const invalidDeclared = raw || void 0;
39
+ if (invalidDeclared !== void 0) {
40
+ reportInvalidDeclaration(kind, invalidDeclared);
41
+ }
42
+ const derived = inferLoadingSlug(kindRegistry.getDefinition(kind)?.schema) ?? inferLoadingSlugFromJsonSchema(kindRegistry.getEmittedJsonSchema(kind));
43
+ if (derived) {
44
+ return invalidDeclared === void 0 ? { slug: derived, origin: "derived" } : { slug: derived, origin: "derived", invalidDeclared };
45
+ }
46
+ return invalidDeclared === void 0 ? GENERIC : { slug: null, origin: "generic", invalidDeclared };
47
+ }
48
+ export {
49
+ resetInvalidLoadingDeclarationReports,
50
+ resolveLoadingSlugForKind
51
+ };
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The Matrix binding of the PROVISIONAL (streaming partial kinds) route.
3
+ *
4
+ * Contract: `common-docs/systems/architecture/content-ir/FEATURE.md`.
5
+ * The reader/validator half is `@ai-matrx/content-ir` (`wire/partial-kind`);
6
+ * the ROUTE half — withhold-by-default, the per-kind opt-in, the
7
+ * anti-stuck-skeleton backstop, the terminal rules — is
8
+ * `@ai-matrx/content-ir-react` (`route/partial-kind-route.ts`), and since
9
+ * 0.8.0 the per-host partial application is `createKindRouteBinding`. Read
10
+ * the semantics there; this module only injects our registries.
11
+ *
12
+ * The wire gate runs in the execution system's `process-stream.ts`.
13
+ */
14
+ export { IR_PROVISIONAL_KEY, envelopeFromPartialKind, isProvisionalBlock, markKindPartialUnsafe, resetPartialUnsafeKinds, resolveAnnouncedKindLoading, type ProvisionalKindRender, } from "@ai-matrx/content-ir-react";
15
+ /** Has this kind opted in to being handed a provisional value? */
16
+ export declare const isPartialReadyKind: (kind: string) => boolean;
17
+ /**
18
+ * Resolve a block's provisional render, or null when there is nothing to show
19
+ * provisionally (no event, a terminal event, a withheld kind, a kind nothing
20
+ * can route, or a verified envelope that already won).
21
+ */
22
+ export declare const resolveProvisionalKindRender: <T extends import("@ai-matrx/content-ir-react").IrRoutableBlock & {
23
+ metadata?: Record<string, unknown>;
24
+ }>(block: T, options?: Pick<import("@ai-matrx/content-ir-react").PartialRenderOptions, "streamActive">) => import("@ai-matrx/content-ir-react").ProvisionalKindRender<T> | null;
25
+ /**
26
+ * Route the completed JSON already present on a workflow block when its
27
+ * partial-kind channel closes before the canonical envelope is attached.
28
+ */
29
+ export declare const resolveSupersededKindRender: <T extends import("@ai-matrx/content-ir-react").IrRoutableBlock & {
30
+ content: string;
31
+ metadata?: Record<string, unknown>;
32
+ }>(block: T) => import("@ai-matrx/content-ir-react").SupersededKindRender<T> | null;
@@ -0,0 +1,27 @@
1
+ import { createKindRouteBinding } from "@ai-matrx/content-ir-react";
2
+ import { MATRX_OWNED_BLOCK_TYPES, matrxKindRouteEnv } from "../host/route-env.js";
3
+ import {
4
+ IR_PROVISIONAL_KEY,
5
+ envelopeFromPartialKind,
6
+ isProvisionalBlock,
7
+ markKindPartialUnsafe,
8
+ resetPartialUnsafeKinds,
9
+ resolveAnnouncedKindLoading
10
+ } from "@ai-matrx/content-ir-react";
11
+ const binding = createKindRouteBinding(matrxKindRouteEnv, {
12
+ ownedTypes: MATRX_OWNED_BLOCK_TYPES
13
+ });
14
+ const isPartialReadyKind = binding.isPartialReadyKind;
15
+ const resolveProvisionalKindRender = binding.resolveProvisionalKindRender;
16
+ const resolveSupersededKindRender = binding.resolveSupersededKindRender;
17
+ export {
18
+ IR_PROVISIONAL_KEY,
19
+ envelopeFromPartialKind,
20
+ isPartialReadyKind,
21
+ isProvisionalBlock,
22
+ markKindPartialUnsafe,
23
+ resetPartialUnsafeKinds,
24
+ resolveAnnouncedKindLoading,
25
+ resolveProvisionalKindRender,
26
+ resolveSupersededKindRender
27
+ };
@@ -0,0 +1,54 @@
1
+ /**
2
+ * THE REGISTRY-VERSIONED READ — the primitive that survives the React Compiler.
3
+ *
4
+ * 🚨 THE DEFECT THIS CLOSES (DD-215c, observed on production 2026-09-14).
5
+ *
6
+ * Kind rendering reads MODULE SINGLETONS during render (`componentRegistry`,
7
+ * `kindRegistry`). Nothing in React state changes when a row lands, so every
8
+ * such reader pairs its read with `useContentIrKindVersion(kind)`, which
9
+ * subscribes to that kind's counter and returns it. The counter was then used
10
+ * as a memo INVALIDATION KEY in the only way a number can be used when the
11
+ * computation does not need it:
12
+ *
13
+ * const block = useMemo(() => {
14
+ * void kindRouteVersion; // registry-arrival invalidation key
15
+ * return applyIrKindRoute(rawBlock);
16
+ * }, [rawBlock, kindRouteVersion]);
17
+ *
18
+ * That idiom is correct without the React Compiler and WRONG with it — and
19
+ * `next.config.js` sets `reactCompiler: true`. The compiler re-infers
20
+ * memoization from data flow: `void kindRouteVersion;` produces nothing, so the
21
+ * version is not an input, and the emitted cache is keyed on the block alone:
22
+ *
23
+ * if ($[13] !== rawBlock) { t6 = applyIrKindRoute(rawBlock); $[13] = rawBlock; ... }
24
+ *
25
+ * The subscription still fires and the component still re-renders — the route
26
+ * simply comes back out of the cache, so a block that mounted before its
27
+ * organization's component row landed keeps the platform's bundled component
28
+ * for the life of the mount. Jest does not run the compiler, so every test of
29
+ * that code passes on source semantics production does not have. Three lanes
30
+ * shipped fixes proven that way and production disproved each one.
31
+ *
32
+ * THE RULE, therefore: a registry read that must follow a registry version
33
+ * takes that version AS AN ARGUMENT, through this module. The version is a real
34
+ * input to a real cache key here, so no compiler pass can decide it is dead —
35
+ * and if the compiler memoizes the call site too, it memoizes on the same two
36
+ * values and the answer is identical. Guard: `pnpm check:registry-repaint`.
37
+ */
38
+ interface VersionedEntry<T> {
39
+ version: number;
40
+ value: T;
41
+ }
42
+ /**
43
+ * Read `compute()` for an OBJECT subject, re-running it whenever the registry
44
+ * version moves. One entry per subject; the WeakMap lets the subject (a block,
45
+ * a node) be collected with its answer.
46
+ */
47
+ export declare function readAtVersionFor<K extends object, T>(cache: WeakMap<K, VersionedEntry<T>>, subject: K, version: number, compute: () => T): T;
48
+ /**
49
+ * Read `compute()` for a STRING subject (a kind slug), re-running it whenever
50
+ * the registry version moves. One entry per key — the map is bounded by the
51
+ * number of distinct kinds a tab renders, never by version churn.
52
+ */
53
+ export declare function readAtVersionForKey<T>(cache: Map<string, VersionedEntry<T>>, key: string, version: number, compute: () => T): T;
54
+ export {};
@@ -0,0 +1,18 @@
1
+ function readAtVersionFor(cache, subject, version, compute) {
2
+ const hit = cache.get(subject);
3
+ if (hit !== void 0 && hit.version === version) return hit.value;
4
+ const value = compute();
5
+ cache.set(subject, { version, value });
6
+ return value;
7
+ }
8
+ function readAtVersionForKey(cache, key, version, compute) {
9
+ const hit = cache.get(key);
10
+ if (hit !== void 0 && hit.version === version) return hit.value;
11
+ const value = compute();
12
+ cache.set(key, { version, value });
13
+ return value;
14
+ }
15
+ export {
16
+ readAtVersionFor,
17
+ readAtVersionForKey
18
+ };
@@ -0,0 +1,38 @@
1
+ /**
2
+ * THE ROUTE, KEYED ON THE REGISTRY STATE THAT PRODUCED IT (DD-215c).
3
+ *
4
+ * A block's route is not a function of the block alone — it is a function of
5
+ * the block AND of what the component resolver held when the decision was
6
+ * made. Writing it as `f(block)` and hanging the registry version off a memo
7
+ * dependency array is what froze `/shapes/<kind>/instances` on the platform's
8
+ * bundled component for a reader whose organization had authored its own: the
9
+ * React Compiler re-infers memo inputs from data flow, the version was only
10
+ * ever `void`-ed, and the emitted cache was keyed on the block alone. The whole
11
+ * story, and the rule, are in `registry-versioned.ts`.
12
+ *
13
+ * So the version is an ARGUMENT here. Call it with
14
+ * `useContentIrKindVersion(envelopeKind)` and the route follows every arrival;
15
+ * there is no way to call it and silently lose the invalidation.
16
+ */
17
+ import { type IrRoutableBlock } from "./kind-route.js";
18
+ /**
19
+ * Route one block at a known registry version — the seam every render path
20
+ * calls instead of `applyIrKindRoute` directly.
21
+ *
22
+ * `resolveSupersededKindRender` runs first for the same reason it always has:
23
+ * a block whose partial channel was superseded routes off the completed value,
24
+ * not off the partial envelope.
25
+ */
26
+ /**
27
+ * The route itself, uncached — what `routeBlockAtRegistryVersion` computes and
28
+ * memoises. For pure callers that ask the renderer's question without a
29
+ * registry version (the frame judge, `draws-raw-kind-json.ts`).
30
+ */
31
+ export declare function routeBlockNow<T extends IrRoutableBlock & {
32
+ content: string;
33
+ }>(block: T): T;
34
+ export declare function routeBlockAtRegistryVersion<T extends IrRoutableBlock & {
35
+ content: string;
36
+ }>(block: T, registryVersion: number): T;
37
+ /** Test seam — drops the per-session dedupe. */
38
+ export declare function resetStaleRouteReports(): void;
@@ -0,0 +1,78 @@
1
+ "use client";
2
+ import {
3
+ applyIrKindRoute,
4
+ DB_KIND_COMPONENT_KEY,
5
+ readIrRouteMarker
6
+ } from "./kind-route.js";
7
+ import { resolveSupersededKindRender } from "./partial-kind-route.js";
8
+ import { readAtVersionFor } from "./registry-versioned.js";
9
+ import { readEnvelope } from "../redux/render-block-envelope.js";
10
+ import { componentRegistry } from "../../host/component-registry.js";
11
+ import {
12
+ MATRX_CONTENT_IR_PLATFORM,
13
+ MATRX_OWNED_BLOCK_TYPES
14
+ } from "../host/route-env.js";
15
+ const routed = /* @__PURE__ */ new WeakMap();
16
+ function routeBlockNow(block) {
17
+ return resolveSupersededKindRender(block)?.block ?? applyIrKindRoute(block);
18
+ }
19
+ function routeBlockAtRegistryVersion(block, registryVersion) {
20
+ const answer = readAtVersionFor(
21
+ routed,
22
+ block,
23
+ registryVersion,
24
+ () => routeBlockNow(block)
25
+ );
26
+ announceStaleRoute(answer);
27
+ return answer;
28
+ }
29
+ const announced = /* @__PURE__ */ new Set();
30
+ function resetStaleRouteReports() {
31
+ announced.clear();
32
+ }
33
+ function announceStaleRoute(block) {
34
+ const marker = readIrRouteMarker(block.metadata);
35
+ if (marker && (marker.by === "generic" || marker.by === "directive")) return;
36
+ const envelope = readEnvelope(block.metadata);
37
+ const kind = envelope?.root.kind;
38
+ if (!kind) return;
39
+ const resolution = componentRegistry.resolve(
40
+ kind,
41
+ MATRX_CONTENT_IR_PLATFORM,
42
+ "output"
43
+ );
44
+ if (!resolution) return;
45
+ if (marker && marker.by === resolution.resolvedBy && marker.key === resolution.componentKey) {
46
+ return;
47
+ }
48
+ if (!marker) {
49
+ const routable = resolution.resolvedBy === "db" && resolution.source === "db" && resolution.isActive && resolution.hasComponentSource;
50
+ const exempt = MATRX_OWNED_BLOCK_TYPES.includes(block.type) || envelope?.root.kindState === "raw" || envelope?.root.kindState === "pending_schema";
51
+ if (!routable || exempt || block.type === DB_KIND_COMPONENT_KEY) return;
52
+ }
53
+ const renderedBy = marker?.by ?? "no route marker";
54
+ const renderedKey = marker?.key ?? block.type;
55
+ const seen = `${kind}|${renderedBy}:${renderedKey}|${resolution.resolvedBy}:${resolution.componentKey}`;
56
+ if (announced.has(seen)) return;
57
+ announced.add(seen);
58
+ void (async () => {
59
+ try {
60
+ const { reportKindComponentIncident } = await import("../../host/kind-incident.js");
61
+ reportKindComponentIncident({
62
+ kind,
63
+ errorType: "stale_route_render",
64
+ platform: MATRX_CONTENT_IR_PLATFORM,
65
+ role: "output",
66
+ componentKey: resolution.componentKey,
67
+ componentUpdatedAt: resolution.updatedAt,
68
+ message: `The reader is being shown "${renderedKey}" (resolved by ${renderedBy}) for kind "${kind}", but this browser's resolver already answers "${resolution.componentKey}" (resolved by ${resolution.resolvedBy}${resolution.hasComponentSource ? ", body present" : ", no body"}). The rendered block is a STALE route decision: the component row arrived after the block mounted and the route was not recomputed. Nothing on screen says so \u2014 the wrong component looks like the right one. Rendered at ${block.type}.`
69
+ });
70
+ } catch {
71
+ }
72
+ })();
73
+ }
74
+ export {
75
+ resetStaleRouteReports,
76
+ routeBlockAtRegistryVersion,
77
+ routeBlockNow
78
+ };
@@ -0,0 +1,87 @@
1
+ /**
2
+ * THE KIND SLOT — one reserved place on a surface, from first paint to final
3
+ * content, without ever moving anything above it.
4
+ *
5
+ * Ratified by Arman 2026-08-25, from the podcast run page: a slot "takes up
6
+ * the space… it's sort of animated, but it's fairly steady, and it tries to
7
+ * look a little bit like it's gonna look eventually, but without looking like
8
+ * it's actively, instantly loading. And then when the content actually starts
9
+ * coming, boom — that's when it switches to the loading component."
10
+ *
11
+ * ─── The four phases ────────────────────────────────────────────────────────
12
+ * reserved the kind's silhouette, STILL — holds the footprint, nothing has
13
+ * started. (`PodcastCompositionPlaceholder` is the reference look.)
14
+ * arriving the same silhouette, now working — spinner, shimmer, live early
15
+ * keys. The switch moves nothing: same component, same footprint.
16
+ * settled the real kind component, growing downward from its first
17
+ * renderable unit (THE ONE LOADING SEQUENCE).
18
+ * failed an honest failure, inside the same reserved footprint.
19
+ *
20
+ * ─── Why the placeholder is a PHASE, not a third component ──────────────────
21
+ * A separately-authored loader would mean a second artifact per kind to keep
22
+ * in sync with the schema (868 of them), and — worse — swapping between two
23
+ * components unmounts and remounts, so the layout jumps and animations
24
+ * restart at exactly the moment we are trying to keep calm. One silhouette in
25
+ * two moods keeps the transition continuous, and every kind gets a
26
+ * shape-appropriate placeholder for free via the declared-or-derived slug
27
+ * (`resolveLoadingSlugForKind`) — including the 857 that declare nothing.
28
+ *
29
+ * ─── Who owns the footprint ─────────────────────────────────────────────────
30
+ * The slot owns the SHAPE; the HOST owns the floor. A surface that knows how
31
+ * much room a region deserves already applies it to its own box — see
32
+ * `ReadoutTile`'s authored `minHeight` in `RunSurfaceView.tsx` ("the zero
33
+ * page-shift law") — and a second floor inside the slot would fight it, or
34
+ * silently lose to an `overflow-y-auto` ancestor. So there is deliberately no
35
+ * `minHeight` prop here: the silhouette's own height does the reserving, and
36
+ * content longer than it grows DOWNWARD, the one direction that disturbs
37
+ * nothing the reader is already looking at.
38
+ *
39
+ * ─── Identity ───────────────────────────────────────────────────────────────
40
+ * `slotKey` is the slot's OWN identity and must be stable from first paint —
41
+ * it exists before any producer does, which is exactly why it cannot be a
42
+ * request id (there is no request yet when the slot is reserved). A producer
43
+ * id (a streaming lane's requestId, a workflow `invocationKeyOf(...)`) is a
44
+ * BINDING the caller resolves later and feeds in as `phase` + `children`.
45
+ */
46
+ import React from "react";
47
+ import type { KindLoadingProps } from "../loading/kind-loading.types.js";
48
+ export type KindSlotPhase = "reserved" | "arriving" | "settled" | "failed";
49
+ export interface KindSlotProps {
50
+ /**
51
+ * Stable identity for this slot, known at first paint and never changing.
52
+ * Surfaces derive it from their own structure (a workflow invocation key, a
53
+ * podcast asset index, an authored slot id) — never from a producer id.
54
+ */
55
+ slotKey: string;
56
+ /** The kind expected here, when known. Drives which silhouette reserves. */
57
+ kind?: string | null;
58
+ phase: KindSlotPhase;
59
+ /**
60
+ * Early keys for the arriving phase (title / count / loading_message …) and
61
+ * the partial value a data-fed smart loader performs. Ignored when settled.
62
+ */
63
+ early?: KindLoadingProps;
64
+ /** The settled content — the real kind component. */
65
+ children?: React.ReactNode;
66
+ /** Rendered in the `failed` phase. */
67
+ error?: React.ReactNode;
68
+ /**
69
+ * `bare` when the host already draws the frame/icon/title around this slot
70
+ * (a workflow deliverable card does) — the silhouette then contributes only
71
+ * its body, never a second header.
72
+ */
73
+ chrome?: "full" | "bare";
74
+ className?: string;
75
+ }
76
+ export declare function KindSlot({ slotKey, kind, phase, early, children, error, chrome, className, }: KindSlotProps): React.JSX.Element;
77
+ /**
78
+ * The phase a slot is in, from the two facts every producer surface has: has
79
+ * anything started, and has it finished. Kept here so a surface never invents
80
+ * its own phase vocabulary — the workflow run board, a podcast slot, and an
81
+ * authored page all map into the SAME four phases.
82
+ */
83
+ export declare function kindSlotPhase(input: {
84
+ started: boolean;
85
+ settled: boolean;
86
+ failed?: boolean;
87
+ }): KindSlotPhase;
@@ -0,0 +1,65 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import React from "react";
4
+ import { resolveKindLoadingComponent } from "../loading/kind-loading-registry.js";
5
+ import { resolveLoadingSlugForKind } from "../loading/resolve-loading-slug.js";
6
+ import { useContentIrKindVersion } from "../use-registry-repaint.js";
7
+ import { readAtVersionForKey } from "../registry-versioned.js";
8
+ import { useEnsureKindRenderable } from "../ensure-kind-renderable.js";
9
+ const loadingSlugCache = /* @__PURE__ */ new Map();
10
+ function KindSlot({
11
+ slotKey,
12
+ kind,
13
+ phase,
14
+ early,
15
+ children,
16
+ error,
17
+ chrome,
18
+ className
19
+ }) {
20
+ useEnsureKindRenderable(kind ?? null);
21
+ const kindVersion = useContentIrKindVersion(kind ?? null);
22
+ const slug = readAtVersionForKey(
23
+ loadingSlugCache,
24
+ kind ?? "",
25
+ kindVersion,
26
+ () => resolveLoadingSlugForKind(kind).slug
27
+ );
28
+ return /* @__PURE__ */ jsx(
29
+ "div",
30
+ {
31
+ "data-kind-slot": slotKey,
32
+ "data-kind-slot-phase": phase,
33
+ "data-kind-slot-kind": kind ?? void 0,
34
+ className,
35
+ children: phase === "settled" ? children : phase === "failed" ? error : /* @__PURE__ */ jsx(
36
+ PendingSilhouette,
37
+ {
38
+ slug,
39
+ kind,
40
+ phase,
41
+ early,
42
+ chrome
43
+ }
44
+ )
45
+ }
46
+ );
47
+ }
48
+ const PendingSilhouette = ({ slug, kind, phase, early, chrome }) => {
49
+ const Loader = resolveKindLoadingComponent(slug);
50
+ return React.createElement(Loader, {
51
+ ...early,
52
+ kind: kind ?? early?.kind,
53
+ phase,
54
+ chrome
55
+ });
56
+ };
57
+ function kindSlotPhase(input) {
58
+ if (input.failed) return "failed";
59
+ if (input.settled) return "settled";
60
+ return input.started ? "arriving" : "reserved";
61
+ }
62
+ export {
63
+ KindSlot,
64
+ kindSlotPhase
65
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Subscribes the caller to registry changes FOR ONE KIND and returns that
3
+ * kind's combined version. Pass null for blocks with no envelope kind —
4
+ * they never repaint from registries (nothing to learn about them).
5
+ */
6
+ export declare function useContentIrKindVersion(kind: string | null): number;
@@ -0,0 +1,36 @@
1
+ "use client";
2
+ import { useCallback, useSyncExternalStore } from "react";
3
+ import { kindRegistry } from "../../host/kind-registry.js";
4
+ import { componentRegistry } from "../../host/component-registry.js";
5
+ const noopSubscribe = () => () => {
6
+ };
7
+ const zero = () => 0;
8
+ function useContentIrKindVersion(kind) {
9
+ const subscribe = useCallback(
10
+ (onStoreChange) => {
11
+ if (!kind) return noopSubscribe();
12
+ const unsubKinds = kindRegistry.subscribeKind(kind, onStoreChange);
13
+ const unsubComponents = componentRegistry.subscribeKind(
14
+ kind,
15
+ onStoreChange
16
+ );
17
+ return () => {
18
+ unsubKinds();
19
+ unsubComponents();
20
+ };
21
+ },
22
+ [kind]
23
+ );
24
+ const getSnapshot = useCallback(
25
+ () => kind ? (
26
+ // Both counters are monotonic, so the sum is monotonic — a change
27
+ // in either registry produces a new snapshot value for this kind.
28
+ kindRegistry.getKindVersion(kind) + componentRegistry.getKindVersion(kind)
29
+ ) : 0,
30
+ [kind]
31
+ );
32
+ return useSyncExternalStore(subscribe, getSnapshot, zero);
33
+ }
34
+ export {
35
+ useContentIrKindVersion
36
+ };
@@ -0,0 +1,9 @@
1
+ import { type IrPath } from "@ai-matrx/content-ir";
2
+ import type { IrTreeNode } from "@ai-matrx/content-ir";
3
+ export declare function useIrNode(identity: string | null, path: IrPath | string): IrTreeNode | null;
4
+ /**
5
+ * Structural subscription: the list of node pathKeys for a session, updated
6
+ * when nodes are added/removed/changed. Containers use this to know which
7
+ * children to mount without subscribing to every child's data.
8
+ */
9
+ export declare function useIrNodePaths(identity: string | null): string[];