@assistant-ui/react-generative-ui 0.0.6 → 0.0.8

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 (201) hide show
  1. package/dist/JSONGenerativeUI.client.d.ts +4 -2
  2. package/dist/JSONGenerativeUI.client.d.ts.map +1 -1
  3. package/dist/JSONGenerativeUI.client.js +9 -2
  4. package/dist/JSONGenerativeUI.client.js.map +1 -1
  5. package/dist/JSONGenerativeUI.server.d.ts +0 -1
  6. package/dist/JSONGenerativeUI.server.d.ts.map +1 -1
  7. package/dist/JSONGenerativeUI.shared.d.ts +8 -1
  8. package/dist/JSONGenerativeUI.shared.d.ts.map +1 -1
  9. package/dist/JSONGenerativeUI.shared.js.map +1 -1
  10. package/dist/actionRegistry.d.ts +32 -0
  11. package/dist/actionRegistry.d.ts.map +1 -0
  12. package/dist/actionRegistry.js +41 -0
  13. package/dist/actionRegistry.js.map +1 -0
  14. package/dist/buildPresentParameters.d.ts +5 -5
  15. package/dist/buildPresentParameters.d.ts.map +1 -1
  16. package/dist/buildPresentParameters.js +20 -6
  17. package/dist/buildPresentParameters.js.map +1 -1
  18. package/dist/constants.d.ts.map +1 -1
  19. package/dist/defineGenerativeComponents.d.ts +0 -1
  20. package/dist/defineGenerativeComponents.d.ts.map +1 -1
  21. package/dist/generativeUIToJSX.d.ts +15 -10
  22. package/dist/generativeUIToJSX.d.ts.map +1 -1
  23. package/dist/generativeUIToJSX.js +47 -17
  24. package/dist/generativeUIToJSX.js.map +1 -1
  25. package/dist/index.d.ts +8 -4
  26. package/dist/index.js +5 -2
  27. package/dist/index.server.d.ts +13 -0
  28. package/dist/index.server.js +10 -0
  29. package/dist/index.shared.d.ts +11 -0
  30. package/dist/index.shared.js +9 -0
  31. package/dist/ir.d.ts +115 -0
  32. package/dist/ir.d.ts.map +1 -0
  33. package/dist/ir.js +175 -0
  34. package/dist/ir.js.map +1 -0
  35. package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts +3 -3
  36. package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts.map +1 -1
  37. package/dist/renderGenerativeUI.d.ts +5 -5
  38. package/dist/renderGenerativeUI.d.ts.map +1 -1
  39. package/dist/renderGenerativeUI.js +18 -45
  40. package/dist/renderGenerativeUI.js.map +1 -1
  41. package/dist/slack/constants.d.ts +111 -0
  42. package/dist/slack/constants.d.ts.map +1 -0
  43. package/dist/slack/constants.js +168 -0
  44. package/dist/slack/constants.js.map +1 -0
  45. package/dist/slack/decodeBlockAction.d.ts +11 -0
  46. package/dist/slack/decodeBlockAction.d.ts.map +1 -0
  47. package/dist/slack/decodeBlockAction.js +40 -0
  48. package/dist/slack/decodeBlockAction.js.map +1 -0
  49. package/dist/slack/fromSlackBlocks.d.ts +30 -0
  50. package/dist/slack/fromSlackBlocks.d.ts.map +1 -0
  51. package/dist/slack/fromSlackBlocks.js +447 -0
  52. package/dist/slack/fromSlackBlocks.js.map +1 -0
  53. package/dist/slack/toSlackBlocks.d.ts +7 -0
  54. package/dist/slack/toSlackBlocks.d.ts.map +1 -0
  55. package/dist/slack/toSlackBlocks.js +649 -0
  56. package/dist/slack/toSlackBlocks.js.map +1 -0
  57. package/dist/slack/types.d.ts +178 -0
  58. package/dist/slack/types.d.ts.map +1 -0
  59. package/dist/slack/types.js +0 -0
  60. package/dist/slack.d.ts +5 -0
  61. package/dist/slack.js +4 -0
  62. package/dist/teams/boundSpec.d.ts +20 -0
  63. package/dist/teams/boundSpec.d.ts.map +1 -0
  64. package/dist/teams/boundSpec.js +67 -0
  65. package/dist/teams/boundSpec.js.map +1 -0
  66. package/dist/teams/constants.d.ts +57 -0
  67. package/dist/teams/constants.d.ts.map +1 -0
  68. package/dist/teams/constants.js +92 -0
  69. package/dist/teams/constants.js.map +1 -0
  70. package/dist/teams/decodeSubmitData.d.ts +25 -0
  71. package/dist/teams/decodeSubmitData.d.ts.map +1 -0
  72. package/dist/teams/decodeSubmitData.js +44 -0
  73. package/dist/teams/decodeSubmitData.js.map +1 -0
  74. package/dist/teams/toAdaptiveCard.d.ts +39 -0
  75. package/dist/teams/toAdaptiveCard.d.ts.map +1 -0
  76. package/dist/teams/toAdaptiveCard.js +496 -0
  77. package/dist/teams/toAdaptiveCard.js.map +1 -0
  78. package/dist/teams/toTeamsAttachments.d.ts +13 -0
  79. package/dist/teams/toTeamsAttachments.d.ts.map +1 -0
  80. package/dist/teams/toTeamsAttachments.js +95 -0
  81. package/dist/teams/toTeamsAttachments.js.map +1 -0
  82. package/dist/teams/types.d.ts +196 -0
  83. package/dist/teams/types.d.ts.map +1 -0
  84. package/dist/teams/types.js +0 -0
  85. package/dist/teams.d.ts +5 -0
  86. package/dist/teams.js +4 -0
  87. package/dist/types.d.ts +41 -34
  88. package/dist/types.d.ts.map +1 -1
  89. package/dist/vocabulary/alert.d.ts +28 -0
  90. package/dist/vocabulary/alert.d.ts.map +1 -0
  91. package/dist/vocabulary/alert.js +58 -0
  92. package/dist/vocabulary/alert.js.map +1 -0
  93. package/dist/vocabulary/collectFormValues.d.ts +23 -0
  94. package/dist/vocabulary/collectFormValues.d.ts.map +1 -0
  95. package/dist/vocabulary/collectFormValues.js +32 -0
  96. package/dist/vocabulary/collectFormValues.js.map +1 -0
  97. package/dist/vocabulary/data.d.ts +52 -0
  98. package/dist/vocabulary/data.d.ts.map +1 -0
  99. package/dist/vocabulary/data.js +294 -0
  100. package/dist/vocabulary/data.js.map +1 -0
  101. package/dist/vocabulary/dispatch.d.ts +11 -0
  102. package/dist/vocabulary/dispatch.d.ts.map +1 -0
  103. package/dist/vocabulary/dispatch.js +21 -0
  104. package/dist/vocabulary/dispatch.js.map +1 -0
  105. package/dist/vocabulary/fact.d.ts +15 -0
  106. package/dist/vocabulary/fact.d.ts.map +1 -0
  107. package/dist/vocabulary/fact.js +24 -0
  108. package/dist/vocabulary/fact.js.map +1 -0
  109. package/dist/vocabulary/form.d.ts +14 -0
  110. package/dist/vocabulary/form.d.ts.map +1 -0
  111. package/dist/vocabulary/form.js +23 -0
  112. package/dist/vocabulary/form.js.map +1 -0
  113. package/dist/vocabulary/icon.d.ts +44 -0
  114. package/dist/vocabulary/icon.d.ts.map +1 -0
  115. package/dist/vocabulary/icon.js +272 -0
  116. package/dist/vocabulary/icon.js.map +1 -0
  117. package/dist/vocabulary/index.d.ts +15 -0
  118. package/dist/vocabulary/index.d.ts.map +1 -0
  119. package/dist/vocabulary/index.js +36 -0
  120. package/dist/vocabulary/index.js.map +1 -0
  121. package/dist/vocabulary/interactive.d.ts +93 -0
  122. package/dist/vocabulary/interactive.d.ts.map +1 -0
  123. package/dist/vocabulary/interactive.js +172 -0
  124. package/dist/vocabulary/interactive.js.map +1 -0
  125. package/dist/vocabulary/layout.d.ts +82 -0
  126. package/dist/vocabulary/layout.d.ts.map +1 -0
  127. package/dist/vocabulary/layout.js +136 -0
  128. package/dist/vocabulary/layout.js.map +1 -0
  129. package/dist/vocabulary/list.d.ts +17 -0
  130. package/dist/vocabulary/list.d.ts.map +1 -0
  131. package/dist/vocabulary/list.js +48 -0
  132. package/dist/vocabulary/list.js.map +1 -0
  133. package/dist/vocabulary/media.d.ts +28 -0
  134. package/dist/vocabulary/media.d.ts.map +1 -0
  135. package/dist/vocabulary/media.js +42 -0
  136. package/dist/vocabulary/media.js.map +1 -0
  137. package/dist/vocabulary/text.d.ts +60 -0
  138. package/dist/vocabulary/text.d.ts.map +1 -0
  139. package/dist/vocabulary/text.js +48 -0
  140. package/dist/vocabulary/text.js.map +1 -0
  141. package/package.json +21 -13
  142. package/src/JSONGenerativeUI.client.tsx +10 -2
  143. package/src/JSONGenerativeUI.shared.ts +8 -0
  144. package/src/actionRegistry.test.ts +90 -0
  145. package/src/actionRegistry.ts +88 -0
  146. package/src/buildPresentParameters.ts +38 -16
  147. package/src/generativeUIToJSX.test.ts +186 -0
  148. package/src/generativeUIToJSX.ts +112 -21
  149. package/src/index.server.ts +2 -0
  150. package/src/index.shared.ts +61 -0
  151. package/src/index.ts +2 -26
  152. package/src/ir.test.ts +203 -0
  153. package/src/ir.ts +279 -0
  154. package/src/renderGenerativeUI.test.tsx +69 -2
  155. package/src/renderGenerativeUI.tsx +49 -82
  156. package/src/slack/constants.ts +217 -0
  157. package/src/slack/decodeBlockAction.test.ts +135 -0
  158. package/src/slack/decodeBlockAction.ts +66 -0
  159. package/src/slack/fromSlackBlocks.test.ts +1145 -0
  160. package/src/slack/fromSlackBlocks.ts +709 -0
  161. package/src/slack/toSlackBlocks.test.ts +1936 -0
  162. package/src/slack/toSlackBlocks.ts +1319 -0
  163. package/src/slack/types.ts +230 -0
  164. package/src/slack.ts +37 -0
  165. package/src/teams/boundSpec.ts +102 -0
  166. package/src/teams/constants.ts +127 -0
  167. package/src/teams/decodeSubmitData.test.ts +148 -0
  168. package/src/teams/decodeSubmitData.ts +57 -0
  169. package/src/teams/toAdaptiveCard.test.ts +1410 -0
  170. package/src/teams/toAdaptiveCard.ts +762 -0
  171. package/src/teams/toTeamsAttachments.test.ts +29 -0
  172. package/src/teams/toTeamsAttachments.ts +137 -0
  173. package/src/teams/types.ts +237 -0
  174. package/src/teams.ts +34 -0
  175. package/src/types.ts +57 -42
  176. package/src/vocabulary/alert.test.tsx +136 -0
  177. package/src/vocabulary/alert.tsx +66 -0
  178. package/src/vocabulary/collectFormValues.test.ts +127 -0
  179. package/src/vocabulary/collectFormValues.ts +58 -0
  180. package/src/vocabulary/data.test.tsx +567 -0
  181. package/src/vocabulary/data.tsx +494 -0
  182. package/src/vocabulary/dispatch.ts +22 -0
  183. package/src/vocabulary/fact.test.tsx +15 -0
  184. package/src/vocabulary/fact.tsx +22 -0
  185. package/src/vocabulary/form.test.tsx +112 -0
  186. package/src/vocabulary/form.tsx +34 -0
  187. package/src/vocabulary/icon.test.tsx +64 -0
  188. package/src/vocabulary/icon.tsx +174 -0
  189. package/src/vocabulary/index.test.ts +63 -0
  190. package/src/vocabulary/index.ts +33 -0
  191. package/src/vocabulary/interactive.dispatch.test.tsx +352 -0
  192. package/src/vocabulary/interactive.test.tsx +248 -0
  193. package/src/vocabulary/interactive.tsx +269 -0
  194. package/src/vocabulary/layout.test.tsx +289 -0
  195. package/src/vocabulary/layout.tsx +229 -0
  196. package/src/vocabulary/list.test.tsx +195 -0
  197. package/src/vocabulary/list.tsx +48 -0
  198. package/src/vocabulary/media.test.tsx +85 -0
  199. package/src/vocabulary/media.tsx +56 -0
  200. package/src/vocabulary/text.test.tsx +73 -0
  201. package/src/vocabulary/text.tsx +59 -0
@@ -0,0 +1,11 @@
1
+ import { ALERT_TONES, ALIGNS, Action, AlertTone, Align, BUTTON_STYLES, ButtonStyle, COLORS, Color, ICON_NAMES, IMAGE_SIZE_TOKENS, IconName, ImageSize, JUSTIFIES, Justify, LegacyComponentNode, NormalizedUIElement, NormalizedUINode, TEXT_SIZES, TextSize, UIChildren, UIElement, UINode, UISpec, WEIGHTS, Weight, normalizeSpec, normalizeUINode } from "./ir.js";
2
+ import { ActionDispatchContext, ActionHandler, ActionRegistry, createActionRegistry, emptyActionRegistry } from "./actionRegistry.js";
3
+ import { GenerativeUIAction, GenerativeUIComponent, GenerativeUIDispatch, GenerativeUIElement, GenerativeUILibrary, GenerativeUINode, GenerativeUIProps, GenerativeUIRenderContext, GenerativeUIStatus } from "./types.js";
4
+ import { JSONGenerativeUIOptions, PresentTool, PresentToolOptions, PromptUserTool } from "./JSONGenerativeUI.shared.js";
5
+ import { buildPresentParameters } from "./buildPresentParameters.js";
6
+ import { TYPE_KEY } from "./constants.js";
7
+ import { defineGenerativeComponents } from "./defineGenerativeComponents.js";
8
+ import { GenerativeUIToJSXOptions, generativeUIToJSX } from "./generativeUIToJSX.js";
9
+ import { renderGenerativeUI } from "./renderGenerativeUI.js";
10
+ import { defaultGenerativeUILibrary } from "./vocabulary/index.js";
11
+ export { ALERT_TONES, ALIGNS, type Action, type ActionDispatchContext, type ActionHandler, type ActionRegistry, type AlertTone, type Align, BUTTON_STYLES, type ButtonStyle, COLORS, type Color, type GenerativeUIAction, type GenerativeUIComponent, type GenerativeUIDispatch, type GenerativeUIElement, type GenerativeUILibrary, type GenerativeUINode, type GenerativeUIProps, type GenerativeUIRenderContext, type GenerativeUIStatus, type GenerativeUIToJSXOptions, ICON_NAMES, IMAGE_SIZE_TOKENS, type IconName, type ImageSize, type JSONGenerativeUIOptions, JUSTIFIES, type Justify, type LegacyComponentNode, type NormalizedUIElement, type NormalizedUINode, type PresentTool, type PresentToolOptions, type PromptUserTool, TEXT_SIZES, TYPE_KEY, type TextSize, type UIChildren, type UIElement, type UINode, type UISpec, WEIGHTS, type Weight, buildPresentParameters, createActionRegistry, defaultGenerativeUILibrary, defineGenerativeComponents, emptyActionRegistry, generativeUIToJSX, normalizeSpec, normalizeUINode, renderGenerativeUI };
@@ -0,0 +1,9 @@
1
+ import { TYPE_KEY } from "./constants.js";
2
+ import { buildPresentParameters } from "./buildPresentParameters.js";
3
+ import { ALERT_TONES, ALIGNS, BUTTON_STYLES, COLORS, ICON_NAMES, IMAGE_SIZE_TOKENS, JUSTIFIES, TEXT_SIZES, WEIGHTS, normalizeSpec, normalizeUINode } from "./ir.js";
4
+ import { renderGenerativeUI } from "./renderGenerativeUI.js";
5
+ import { createActionRegistry, emptyActionRegistry } from "./actionRegistry.js";
6
+ import { defineGenerativeComponents } from "./defineGenerativeComponents.js";
7
+ import { generativeUIToJSX } from "./generativeUIToJSX.js";
8
+ import { defaultGenerativeUILibrary } from "./vocabulary/index.js";
9
+ export { ALERT_TONES, ALIGNS, BUTTON_STYLES, COLORS, ICON_NAMES, IMAGE_SIZE_TOKENS, JUSTIFIES, TEXT_SIZES, TYPE_KEY, WEIGHTS, buildPresentParameters, createActionRegistry, defaultGenerativeUILibrary, defineGenerativeComponents, emptyActionRegistry, generativeUIToJSX, normalizeSpec, normalizeUINode, renderGenerativeUI };
package/dist/ir.d.ts ADDED
@@ -0,0 +1,115 @@
1
+ //#region src/ir.d.ts
2
+ /**
3
+ * The generative-ui intermediate representation: a model-emitted, cross-platform
4
+ * UI tree. React-free, so converters and non-web runtimes consume it without
5
+ * pulling React. The flat `$type` shape is the canonical form; the legacy
6
+ * `component` shape is accepted as a backward-compatible alias.
7
+ *
8
+ * Reserved keys are partitioned off from component props so the component prop
9
+ * namespace stays fully free:
10
+ *
11
+ * - `$`-prefixed keys are framework-reserved (`$type`, `$key`, `$action`,
12
+ * `$status`). Components never declare `$`-prefixed props, so a component
13
+ * can use `type`, `status`, `variant`, etc. as ordinary props without
14
+ * colliding with the framework.
15
+ * - `children` is additionally reserved (the JSX convention).
16
+ * - every other key is an inline prop passed straight to the component.
17
+ */
18
+ declare const TEXT_SIZES: readonly ["sm", "md", "lg", "xl", "2xl", "3xl"];
19
+ type TextSize = (typeof TEXT_SIZES)[number];
20
+ declare const IMAGE_SIZE_TOKENS: readonly ["sm", "md", "lg"];
21
+ type ImageSize = (typeof IMAGE_SIZE_TOKENS)[number] | number;
22
+ declare const WEIGHTS: readonly ["normal", "medium", "semibold", "bold"];
23
+ type Weight = (typeof WEIGHTS)[number];
24
+ declare const COLORS: readonly ["emphasis", "secondary", "alpha-70", "white", "white-70", "white-50"];
25
+ type Color = (typeof COLORS)[number];
26
+ declare const ALIGNS: readonly ["start", "center", "end"];
27
+ type Align = (typeof ALIGNS)[number];
28
+ declare const JUSTIFIES: readonly ["start", "center", "end", "between"];
29
+ type Justify = (typeof JUSTIFIES)[number];
30
+ declare const BUTTON_STYLES: readonly ["primary", "secondary", "outline", "ghost", "danger"];
31
+ type ButtonStyle = (typeof BUTTON_STYLES)[number];
32
+ declare const ALERT_TONES: readonly ["info", "success", "warning", "danger"];
33
+ /** A severity level, from informational to destructive. */
34
+ type AlertTone = (typeof ALERT_TONES)[number];
35
+ declare const ICON_NAMES: readonly ["sun", "moon", "cloud", "rain", "snow", "wind", "play", "pause", "check", "x", "star", "heart", "arrow-right", "arrow-up-right", "chevron-right", "calendar", "clock", "map-pin", "plane", "truck", "credit-card", "user", "search", "bell"];
36
+ /** A name from the built-in icon set; the closed enum lets the model see exactly which icons exist. */
37
+ type IconName = (typeof ICON_NAMES)[number];
38
+ /**
39
+ * Behavior payload carried by an interactive node. `type` is resolved by the host's action registry, not the renderer; keeping behavior as data keeps the tree serializable, so the same node renders on web while converters may bind the type to a native action id on other platforms.
40
+ */
41
+ interface Action {
42
+ readonly type: string;
43
+ readonly [payload: string]: unknown;
44
+ }
45
+ /**
46
+ * Anything renderable as generative UI, as the model emits it. The renderer
47
+ * also accepts `number`, `boolean`, `null`, `undefined`, and arrays at the
48
+ * input boundary (numbers render as text, falsy/boolean as nothing, arrays as
49
+ * lists); {@link normalizeUINode} accepts that full range.
50
+ */
51
+ type UINode = string | number | UIElement | LegacyComponentNode;
52
+ type UIChildren = UINode | readonly UINode[];
53
+ /** The flat node shape: inline props keep the tree compact and natural for a
54
+ * model to emit, instead of a nested `{ type, props }` bag. Reserved keys are
55
+ * stripped before props reach the component (see the module header). */
56
+ interface UIElement {
57
+ readonly $type: string;
58
+ readonly $key?: string | number;
59
+ readonly children?: UIChildren;
60
+ readonly $action?: Action;
61
+ readonly [prop: string]: unknown;
62
+ }
63
+ /**
64
+ * The legacy node shape: a `component` name plus a nested `props` bag. Kept
65
+ * for backward compatibility. New code authors the flat {@link UIElement}
66
+ * shape instead.
67
+ */
68
+ interface LegacyComponentNode {
69
+ readonly component: string;
70
+ readonly props?: Record<string, unknown>;
71
+ readonly children?: UIChildren;
72
+ readonly key?: string;
73
+ }
74
+ type UISpec = UINode | readonly UINode[];
75
+ /**
76
+ * A node normalized to a single canonical shape: a `type` string, an inline
77
+ * `props` bag, recursive `children`, an optional `key`, and an optional
78
+ * `action`. Renderers and platform converters consume this form, so they never
79
+ * branch on whether the model emitted the flat `$type` shape or the legacy
80
+ * `component` shape, and they never see the reserved `$`-prefixed keys leak
81
+ * into component props.
82
+ */
83
+ interface NormalizedUIElement {
84
+ readonly type: string;
85
+ readonly props: Readonly<Record<string, unknown>>;
86
+ readonly children?: NormalizedUINode | undefined;
87
+ readonly key?: string | number | undefined;
88
+ readonly action?: Action | undefined;
89
+ }
90
+ type NormalizedUINode = string | number | readonly NormalizedUINode[] | NormalizedUIElement | null;
91
+ /**
92
+ * Normalizes a generative-ui input to {@link NormalizedUINode}. The flat
93
+ * `$type` shape and the legacy `component` shape both map to the same canonical
94
+ * element, with reserved keys (`$type`, `$key`, `$action`, `children`) stripped
95
+ * from the prop bag. A node that carries neither a `$type` nor a `component`
96
+ * string is not renderable and resolves to `null` rather than throwing, so a
97
+ * partially-streamed or malformed node degrades to "render nothing".
98
+ *
99
+ * `partialPath` carries streaming state from the tool-args parse meta: a node
100
+ * whose `$type` is still mid-arrival is held back (resolves to `null`) until it
101
+ * completes, and the path is threaded into `children` so a nested streaming
102
+ * node is held back while completed siblings render. Omit it for a
103
+ * non-streaming (converter) normalize.
104
+ */
105
+ declare function normalizeUINode(node: unknown, partialPath?: readonly string[] | undefined, depth?: number): NormalizedUINode;
106
+ /**
107
+ * Normalizes the root of a {@link UISpec}, preserving whether the root was a
108
+ * single node or a list.
109
+ */
110
+ declare function normalizeSpec(spec: UISpec): {
111
+ readonly root: NormalizedUINode | readonly NormalizedUINode[];
112
+ };
113
+ //#endregion
114
+ export { ALERT_TONES, ALIGNS, Action, AlertTone, Align, BUTTON_STYLES, ButtonStyle, COLORS, Color, ICON_NAMES, IMAGE_SIZE_TOKENS, IconName, ImageSize, JUSTIFIES, Justify, LegacyComponentNode, NormalizedUIElement, NormalizedUINode, TEXT_SIZES, TextSize, UIChildren, UIElement, UINode, UISpec, WEIGHTS, Weight, normalizeSpec, normalizeUINode };
115
+ //# sourceMappingURL=ir.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ir.d.ts","names":[],"sources":["../src/ir.ts"],"mappings":";;;;;;;;;;;;;;;;;cAmBa;KACD,mBAAmB;cAElB;KACD,oBAAoB;cAEnB;KACD,iBAAiB;cAEhB;KAQD,gBAAgB;cAEf;KACD,gBAAgB;cAEf;KACD,kBAAkB;cAEjB;KAOD,sBAAsB;cAErB;;KAED,oBAAoB;cAEnB;;KA2BD,mBAAmB;;;;UAKd;WACN;YACC;;;;;;;;KASA,2BAA2B,YAAY;KAEvC,aAAa,kBAAkB;;;;UAK1B;WACN;WACA;WACA,WAAW;WACX,UAAU;YACT;;;;;;;UAQK;WACN;WACA,QAAQ;WACR,WAAW;WACX;;KAGC,SAAS,kBAAkB;;;;;;;;;UAUtB;WACN;WACA,OAAO,SAAS;WAChB,WAAW;WACX;WACA,SAAS;;KAGR,8CAGC,qBACT;;;;;;;;;;;;;;;iBA6CY,gBACd,eACA,6CACA,iBACC;;;;;iBAuEa,cAAc,MAAM;WACzB,MAAM,4BAA4B"}
package/dist/ir.js ADDED
@@ -0,0 +1,175 @@
1
+ import { TYPE_KEY } from "./constants.js";
2
+ //#region src/ir.ts
3
+ /**
4
+ * The generative-ui intermediate representation: a model-emitted, cross-platform
5
+ * UI tree. React-free, so converters and non-web runtimes consume it without
6
+ * pulling React. The flat `$type` shape is the canonical form; the legacy
7
+ * `component` shape is accepted as a backward-compatible alias.
8
+ *
9
+ * Reserved keys are partitioned off from component props so the component prop
10
+ * namespace stays fully free:
11
+ *
12
+ * - `$`-prefixed keys are framework-reserved (`$type`, `$key`, `$action`,
13
+ * `$status`). Components never declare `$`-prefixed props, so a component
14
+ * can use `type`, `status`, `variant`, etc. as ordinary props without
15
+ * colliding with the framework.
16
+ * - `children` is additionally reserved (the JSX convention).
17
+ * - every other key is an inline prop passed straight to the component.
18
+ */
19
+ const TEXT_SIZES = [
20
+ "sm",
21
+ "md",
22
+ "lg",
23
+ "xl",
24
+ "2xl",
25
+ "3xl"
26
+ ];
27
+ const IMAGE_SIZE_TOKENS = [
28
+ "sm",
29
+ "md",
30
+ "lg"
31
+ ];
32
+ const WEIGHTS = [
33
+ "normal",
34
+ "medium",
35
+ "semibold",
36
+ "bold"
37
+ ];
38
+ const COLORS = [
39
+ "emphasis",
40
+ "secondary",
41
+ "alpha-70",
42
+ "white",
43
+ "white-70",
44
+ "white-50"
45
+ ];
46
+ const ALIGNS = [
47
+ "start",
48
+ "center",
49
+ "end"
50
+ ];
51
+ const JUSTIFIES = [
52
+ "start",
53
+ "center",
54
+ "end",
55
+ "between"
56
+ ];
57
+ const BUTTON_STYLES = [
58
+ "primary",
59
+ "secondary",
60
+ "outline",
61
+ "ghost",
62
+ "danger"
63
+ ];
64
+ const ALERT_TONES = [
65
+ "info",
66
+ "success",
67
+ "warning",
68
+ "danger"
69
+ ];
70
+ const ICON_NAMES = [
71
+ "sun",
72
+ "moon",
73
+ "cloud",
74
+ "rain",
75
+ "snow",
76
+ "wind",
77
+ "play",
78
+ "pause",
79
+ "check",
80
+ "x",
81
+ "star",
82
+ "heart",
83
+ "arrow-right",
84
+ "arrow-up-right",
85
+ "chevron-right",
86
+ "calendar",
87
+ "clock",
88
+ "map-pin",
89
+ "plane",
90
+ "truck",
91
+ "credit-card",
92
+ "user",
93
+ "search",
94
+ "bell"
95
+ ];
96
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
97
+ const isLegacyNode = (node) => typeof node["component"] === "string";
98
+ const isTypeNode = (node) => typeof node[TYPE_KEY] === "string";
99
+ /** Bounds recursion so a runaway or adversarial model response cannot overflow
100
+ * the stack; past this depth (far beyond any real UI) we stop. */
101
+ const MAX_DEPTH = 64;
102
+ /**
103
+ * Steps a streaming partial path down into `key`. `partialPath` is the remaining
104
+ * segment of the parse meta's partial path relative to `node` (`undefined` once
105
+ * the walk leaves the partial frontier, i.e. everything below is complete).
106
+ */
107
+ function descend(partialPath, key) {
108
+ return partialPath?.[0] === key ? partialPath.slice(1) : void 0;
109
+ }
110
+ /**
111
+ * Normalizes a generative-ui input to {@link NormalizedUINode}. The flat
112
+ * `$type` shape and the legacy `component` shape both map to the same canonical
113
+ * element, with reserved keys (`$type`, `$key`, `$action`, `children`) stripped
114
+ * from the prop bag. A node that carries neither a `$type` nor a `component`
115
+ * string is not renderable and resolves to `null` rather than throwing, so a
116
+ * partially-streamed or malformed node degrades to "render nothing".
117
+ *
118
+ * `partialPath` carries streaming state from the tool-args parse meta: a node
119
+ * whose `$type` is still mid-arrival is held back (resolves to `null`) until it
120
+ * completes, and the path is threaded into `children` so a nested streaming
121
+ * node is held back while completed siblings render. Omit it for a
122
+ * non-streaming (converter) normalize.
123
+ */
124
+ function normalizeUINode(node, partialPath, depth = 0) {
125
+ if (depth > MAX_DEPTH) return null;
126
+ if (node == null || typeof node === "boolean") return null;
127
+ if (typeof node === "string" || typeof node === "number") return node;
128
+ if (Array.isArray(node)) return node.map((child, index) => normalizeUINode(child, descend(partialPath, String(index)), depth + 1));
129
+ if (!isRecord(node)) return null;
130
+ if (isTypeNode(node)) {
131
+ if (partialPath?.length === 1 && partialPath[0] === "$type") return null;
132
+ const { [TYPE_KEY]: type, $key, $action, children, ...rest } = node;
133
+ return {
134
+ type,
135
+ props: stripReservedProps(rest),
136
+ children: normalizeChildren(children, partialPath, depth),
137
+ key: $key,
138
+ action: $action
139
+ };
140
+ }
141
+ if (isLegacyNode(node)) {
142
+ const props = stripReservedProps(node.props ?? {});
143
+ return {
144
+ type: node.component,
145
+ props,
146
+ children: normalizeChildren(node.children, partialPath, depth),
147
+ key: node.key
148
+ };
149
+ }
150
+ return null;
151
+ }
152
+ function stripReservedProps(props) {
153
+ let out;
154
+ for (const key of Object.keys(props)) if (key.startsWith("$")) {
155
+ out ??= { ...props };
156
+ delete out[key];
157
+ }
158
+ return out ?? props;
159
+ }
160
+ function normalizeChildren(children, partialPath, depth) {
161
+ if (children === void 0) return void 0;
162
+ return normalizeUINode(children, descend(partialPath, "children"), depth + 1);
163
+ }
164
+ /**
165
+ * Normalizes the root of a {@link UISpec}, preserving whether the root was a
166
+ * single node or a list.
167
+ */
168
+ function normalizeSpec(spec) {
169
+ if (Array.isArray(spec)) return { root: spec.map((node) => normalizeUINode(node)) };
170
+ return { root: normalizeUINode(spec) };
171
+ }
172
+ //#endregion
173
+ export { ALERT_TONES, ALIGNS, BUTTON_STYLES, COLORS, ICON_NAMES, IMAGE_SIZE_TOKENS, JUSTIFIES, TEXT_SIZES, WEIGHTS, normalizeSpec, normalizeUINode };
174
+
175
+ //# sourceMappingURL=ir.js.map
package/dist/ir.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ir.js","names":[],"sources":["../src/ir.ts"],"sourcesContent":["/**\n * The generative-ui intermediate representation: a model-emitted, cross-platform\n * UI tree. React-free, so converters and non-web runtimes consume it without\n * pulling React. The flat `$type` shape is the canonical form; the legacy\n * `component` shape is accepted as a backward-compatible alias.\n *\n * Reserved keys are partitioned off from component props so the component prop\n * namespace stays fully free:\n *\n * - `$`-prefixed keys are framework-reserved (`$type`, `$key`, `$action`,\n * `$status`). Components never declare `$`-prefixed props, so a component\n * can use `type`, `status`, `variant`, etc. as ordinary props without\n * colliding with the framework.\n * - `children` is additionally reserved (the JSX convention).\n * - every other key is an inline prop passed straight to the component.\n */\n\nimport { TYPE_KEY } from \"./constants\";\n\nexport const TEXT_SIZES = [\"sm\", \"md\", \"lg\", \"xl\", \"2xl\", \"3xl\"] as const;\nexport type TextSize = (typeof TEXT_SIZES)[number];\n\nexport const IMAGE_SIZE_TOKENS = [\"sm\", \"md\", \"lg\"] as const;\nexport type ImageSize = (typeof IMAGE_SIZE_TOKENS)[number] | number;\n\nexport const WEIGHTS = [\"normal\", \"medium\", \"semibold\", \"bold\"] as const;\nexport type Weight = (typeof WEIGHTS)[number];\n\nexport const COLORS = [\n \"emphasis\",\n \"secondary\",\n \"alpha-70\",\n \"white\",\n \"white-70\",\n \"white-50\",\n] as const;\nexport type Color = (typeof COLORS)[number];\n\nexport const ALIGNS = [\"start\", \"center\", \"end\"] as const;\nexport type Align = (typeof ALIGNS)[number];\n\nexport const JUSTIFIES = [\"start\", \"center\", \"end\", \"between\"] as const;\nexport type Justify = (typeof JUSTIFIES)[number];\n\nexport const BUTTON_STYLES = [\n \"primary\",\n \"secondary\",\n \"outline\",\n \"ghost\",\n \"danger\",\n] as const;\nexport type ButtonStyle = (typeof BUTTON_STYLES)[number];\n\nexport const ALERT_TONES = [\"info\", \"success\", \"warning\", \"danger\"] as const;\n/** A severity level, from informational to destructive. */\nexport type AlertTone = (typeof ALERT_TONES)[number];\n\nexport const ICON_NAMES = [\n \"sun\",\n \"moon\",\n \"cloud\",\n \"rain\",\n \"snow\",\n \"wind\",\n \"play\",\n \"pause\",\n \"check\",\n \"x\",\n \"star\",\n \"heart\",\n \"arrow-right\",\n \"arrow-up-right\",\n \"chevron-right\",\n \"calendar\",\n \"clock\",\n \"map-pin\",\n \"plane\",\n \"truck\",\n \"credit-card\",\n \"user\",\n \"search\",\n \"bell\",\n] as const;\n/** A name from the built-in icon set; the closed enum lets the model see exactly which icons exist. */\nexport type IconName = (typeof ICON_NAMES)[number];\n\n/**\n * Behavior payload carried by an interactive node. `type` is resolved by the host's action registry, not the renderer; keeping behavior as data keeps the tree serializable, so the same node renders on web while converters may bind the type to a native action id on other platforms.\n */\nexport interface Action {\n readonly type: string;\n readonly [payload: string]: unknown;\n}\n\n/**\n * Anything renderable as generative UI, as the model emits it. The renderer\n * also accepts `number`, `boolean`, `null`, `undefined`, and arrays at the\n * input boundary (numbers render as text, falsy/boolean as nothing, arrays as\n * lists); {@link normalizeUINode} accepts that full range.\n */\nexport type UINode = string | number | UIElement | LegacyComponentNode;\n\nexport type UIChildren = UINode | readonly UINode[];\n\n/** The flat node shape: inline props keep the tree compact and natural for a\n * model to emit, instead of a nested `{ type, props }` bag. Reserved keys are\n * stripped before props reach the component (see the module header). */\nexport interface UIElement {\n readonly $type: string;\n readonly $key?: string | number;\n readonly children?: UIChildren;\n readonly $action?: Action;\n readonly [prop: string]: unknown;\n}\n\n/**\n * The legacy node shape: a `component` name plus a nested `props` bag. Kept\n * for backward compatibility. New code authors the flat {@link UIElement}\n * shape instead.\n */\nexport interface LegacyComponentNode {\n readonly component: string;\n readonly props?: Record<string, unknown>;\n readonly children?: UIChildren;\n readonly key?: string;\n}\n\nexport type UISpec = UINode | readonly UINode[];\n\n/**\n * A node normalized to a single canonical shape: a `type` string, an inline\n * `props` bag, recursive `children`, an optional `key`, and an optional\n * `action`. Renderers and platform converters consume this form, so they never\n * branch on whether the model emitted the flat `$type` shape or the legacy\n * `component` shape, and they never see the reserved `$`-prefixed keys leak\n * into component props.\n */\nexport interface NormalizedUIElement {\n readonly type: string;\n readonly props: Readonly<Record<string, unknown>>;\n readonly children?: NormalizedUINode | undefined;\n readonly key?: string | number | undefined;\n readonly action?: Action | undefined;\n}\n\nexport type NormalizedUINode =\n | string\n | number\n | readonly NormalizedUINode[]\n | NormalizedUIElement\n | null;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\ntype LegacyNodeRecord = { component: string } & Record<string, unknown>;\n\nconst isLegacyNode = (\n node: Record<string, unknown>,\n): node is LegacyNodeRecord => typeof node[\"component\"] === \"string\";\n\nconst isTypeNode = (node: Record<string, unknown>): node is UIElement =>\n typeof node[TYPE_KEY] === \"string\";\n\n/** Bounds recursion so a runaway or adversarial model response cannot overflow\n * the stack; past this depth (far beyond any real UI) we stop. */\nconst MAX_DEPTH = 64;\n\n/**\n * Steps a streaming partial path down into `key`. `partialPath` is the remaining\n * segment of the parse meta's partial path relative to `node` (`undefined` once\n * the walk leaves the partial frontier, i.e. everything below is complete).\n */\nfunction descend(\n partialPath: readonly string[] | undefined,\n key: string,\n): readonly string[] | undefined {\n return partialPath?.[0] === key ? partialPath.slice(1) : undefined;\n}\n\n/**\n * Normalizes a generative-ui input to {@link NormalizedUINode}. The flat\n * `$type` shape and the legacy `component` shape both map to the same canonical\n * element, with reserved keys (`$type`, `$key`, `$action`, `children`) stripped\n * from the prop bag. A node that carries neither a `$type` nor a `component`\n * string is not renderable and resolves to `null` rather than throwing, so a\n * partially-streamed or malformed node degrades to \"render nothing\".\n *\n * `partialPath` carries streaming state from the tool-args parse meta: a node\n * whose `$type` is still mid-arrival is held back (resolves to `null`) until it\n * completes, and the path is threaded into `children` so a nested streaming\n * node is held back while completed siblings render. Omit it for a\n * non-streaming (converter) normalize.\n */\nexport function normalizeUINode(\n node: unknown,\n partialPath?: readonly string[] | undefined,\n depth = 0,\n): NormalizedUINode {\n if (depth > MAX_DEPTH) return null;\n if (node == null || typeof node === \"boolean\") return null;\n if (typeof node === \"string\" || typeof node === \"number\") return node;\n if (Array.isArray(node))\n return node.map((child, index) =>\n normalizeUINode(child, descend(partialPath, String(index)), depth + 1),\n );\n if (!isRecord(node)) return null;\n\n // The flat `$type` shape is the canonical form; detect it first so a flat\n // node that happens to use `component` as an ordinary prop is not swallowed\n // by the legacy `component`-shape branch.\n if (isTypeNode(node)) {\n if (partialPath?.length === 1 && partialPath[0] === TYPE_KEY) return null;\n const { [TYPE_KEY]: type, $key, $action, children, ...rest } = node;\n // The `$`-prefixed namespace is framework-reserved (see the module header),\n // so any model-supplied `$`-prefixed key is stripped from the prop bag the\n // component sees. `$type`/`$key`/`$action` are pulled above; sweep the rest\n // (e.g. a stray `$status`) so it never leaks to converters or components.\n const props = stripReservedProps(rest);\n return {\n type,\n props,\n children: normalizeChildren(children, partialPath, depth),\n key: $key,\n action: $action,\n };\n }\n\n if (isLegacyNode(node)) {\n const props = stripReservedProps(\n (node.props ?? {}) as Record<string, unknown>,\n );\n return {\n type: node.component,\n props,\n children: normalizeChildren(node.children, partialPath, depth),\n key: node.key as string | undefined,\n };\n }\n\n return null;\n}\n\nfunction stripReservedProps(\n props: Record<string, unknown>,\n): Record<string, unknown> {\n let out: Record<string, unknown> | undefined;\n for (const key of Object.keys(props)) {\n if (key.startsWith(\"$\")) {\n out ??= { ...props };\n delete out[key];\n }\n }\n return out ?? props;\n}\n\nfunction normalizeChildren(\n children: unknown,\n partialPath: readonly string[] | undefined,\n depth: number,\n): NormalizedUINode | undefined {\n if (children === undefined) return undefined;\n return normalizeUINode(children, descend(partialPath, \"children\"), depth + 1);\n}\n\n/**\n * Normalizes the root of a {@link UISpec}, preserving whether the root was a\n * single node or a list.\n */\nexport function normalizeSpec(spec: UISpec): {\n readonly root: NormalizedUINode | readonly NormalizedUINode[];\n} {\n if (Array.isArray(spec)) {\n return {\n root: (spec as readonly UINode[]).map((node) => normalizeUINode(node)),\n };\n }\n return { root: normalizeUINode(spec) };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAmBA,MAAa,aAAa;CAAC;CAAM;CAAM;CAAM;CAAM;CAAO;AAAK;AAG/D,MAAa,oBAAoB;CAAC;CAAM;CAAM;AAAI;AAGlD,MAAa,UAAU;CAAC;CAAU;CAAU;CAAY;AAAM;AAG9D,MAAa,SAAS;CACpB;CACA;CACA;CACA;CACA;CACA;AACF;AAGA,MAAa,SAAS;CAAC;CAAS;CAAU;AAAK;AAG/C,MAAa,YAAY;CAAC;CAAS;CAAU;CAAO;AAAS;AAG7D,MAAa,gBAAgB;CAC3B;CACA;CACA;CACA;CACA;AACF;AAGA,MAAa,cAAc;CAAC;CAAQ;CAAW;CAAW;AAAQ;AAIlE,MAAa,aAAa;CACxB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAsEA,MAAM,YAAY,UAChB,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAIrE,MAAM,gBACJ,SAC6B,OAAO,KAAK,iBAAiB;AAE5D,MAAM,cAAc,SAClB,OAAO,KAAK,cAAc;;;AAI5B,MAAM,YAAY;;;;;;AAOlB,SAAS,QACP,aACA,KAC+B;CAC/B,OAAO,cAAc,OAAO,MAAM,YAAY,MAAM,CAAC,IAAI,KAAA;AAC3D;;;;;;;;;;;;;;;AAgBA,SAAgB,gBACd,MACA,aACA,QAAQ,GACU;CAClB,IAAI,QAAQ,WAAW,OAAO;CAC9B,IAAI,QAAQ,QAAQ,OAAO,SAAS,WAAW,OAAO;CACtD,IAAI,OAAO,SAAS,YAAY,OAAO,SAAS,UAAU,OAAO;CACjE,IAAI,MAAM,QAAQ,IAAI,GACpB,OAAO,KAAK,KAAK,OAAO,UACtB,gBAAgB,OAAO,QAAQ,aAAa,OAAO,KAAK,CAAC,GAAG,QAAQ,CAAC,CACvE;CACF,IAAI,CAAC,SAAS,IAAI,GAAG,OAAO;CAK5B,IAAI,WAAW,IAAI,GAAG;EACpB,IAAI,aAAa,WAAW,KAAK,YAAY,OAAA,SAAiB,OAAO;EACrE,MAAM,GAAG,WAAW,MAAM,MAAM,SAAS,UAAU,GAAG,SAAS;EAM/D,OAAO;GACL;GACA,OAHY,mBAAmB,IAG3B;GACJ,UAAU,kBAAkB,UAAU,aAAa,KAAK;GACxD,KAAK;GACL,QAAQ;EACV;CACF;CAEA,IAAI,aAAa,IAAI,GAAG;EACtB,MAAM,QAAQ,mBACX,KAAK,SAAS,CAAC,CAClB;EACA,OAAO;GACL,MAAM,KAAK;GACX;GACA,UAAU,kBAAkB,KAAK,UAAU,aAAa,KAAK;GAC7D,KAAK,KAAK;EACZ;CACF;CAEA,OAAO;AACT;AAEA,SAAS,mBACP,OACyB;CACzB,IAAI;CACJ,KAAK,MAAM,OAAO,OAAO,KAAK,KAAK,GACjC,IAAI,IAAI,WAAW,GAAG,GAAG;EACvB,QAAQ,EAAE,GAAG,MAAM;EACnB,OAAO,IAAI;CACb;CAEF,OAAO,OAAO;AAChB;AAEA,SAAS,kBACP,UACA,aACA,OAC8B;CAC9B,IAAI,aAAa,KAAA,GAAW,OAAO,KAAA;CACnC,OAAO,gBAAgB,UAAU,QAAQ,aAAa,UAAU,GAAG,QAAQ,CAAC;AAC9E;;;;;AAMA,SAAgB,cAAc,MAE5B;CACA,IAAI,MAAM,QAAQ,IAAI,GACpB,OAAO,EACL,MAAO,KAA2B,KAAK,SAAS,gBAAgB,IAAI,CAAC,EACvE;CAEF,OAAO,EAAE,MAAM,gBAAgB,IAAI,EAAE;AACvC"}
@@ -9,13 +9,13 @@
9
9
  * @see https://tools.ietf.org/html/draft-handrews-json-schema-validation-01#section-6.1.1
10
10
  */
11
11
  type JSONSchema7TypeName = "string" //
12
- | "number" | "integer" | "boolean" | "object" | "array" | "null";
12
+ | "number" | "integer" | "boolean" | "object" | "array" | "null";
13
13
  /**
14
14
  * Primitive type
15
15
  * @see https://tools.ietf.org/html/draft-handrews-json-schema-validation-01#section-6.1.1
16
16
  */
17
17
  type JSONSchema7Type = string //
18
- | number | boolean | JSONSchema7Object | JSONSchema7Array | null;
18
+ | number | boolean | JSONSchema7Object | JSONSchema7Array | null;
19
19
  // Workaround for infinite type recursion
20
20
  interface JSONSchema7Object {
21
21
  [key: string]: JSONSchema7Type;
@@ -137,5 +137,5 @@ interface JSONSchema7 {
137
137
  examples?: JSONSchema7Type | undefined;
138
138
  }
139
139
  //#endregion
140
- export { JSONSchema7 };
140
+ export { JSONSchema7, JSONSchema7Array, JSONSchema7Definition, JSONSchema7Object, JSONSchema7Type, JSONSchema7TypeName, JSONSchema7Version };
141
141
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":["JSONSchema4Object","JSONSchema4Array","key","JSONSchema4Type","Array","id","$ref","$schema","JSONSchema4Version","title","description","default","multipleOf","maximum","exclusiveMaximum","minimum","exclusiveMinimum","maxLength","minLength","pattern","additionalItems","JSONSchema4","items","maxItems","minItems","uniqueItems","maxProperties","minProperties","required","additionalProperties","definitions","k","properties","patternProperties","dependencies","enum","type","JSONSchema4TypeName","allOf","anyOf","oneOf","not","extends","format","JSONSchema6Object","JSONSchema6Array","JSONSchema6Type","JSONSchema6","$id","JSONSchema6Version","JSONSchema6Definition","contains","propertyNames","const","JSONSchema6TypeName","examples","JSONSchema7Object","JSONSchema7Array","JSONSchema7Type","JSONSchema7","JSONSchema7Version","$comment","$defs","JSONSchema7Definition","JSONSchema7TypeName","if","then","else","contentMediaType","contentEncoding","readOnly","writeOnly","valid","errors","ValidationError","property","message","instance","schema","ValidationResult","value","result"],"sources":["../../../../../../../../../node_modules/.pnpm/@types+json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts"],"x_google_ignoreList":[0],"mappings":";;;;;;;;;;KA+iBY,mBAAA;AAAA;;;;;KAaA,eAAA;AAAA,qBAIN,iBAAA,GACA,gBAAgB;AAAA;AAAA,UAIL,iBAAA;EAAA,CACZE,GAAAA,WAAc,eAAe;AAAA;AAAA;AAAA;AAAA,UAKjB,gBAAA,SAAyB,KAAK,CAAC,eAAA;;;;;;;;;;;;KAapC,kBAAA;;;;;KAMA,qBAAA,GAAwB,WAAW;AAAA,UAC9B,WAAA;EACb8C,GAAAA;EACA1C,IAAAA;EACAC,OAAAA,GAAU,kBAAA;EACVsD,QAAAA;;;;;EAMAC,KAAAA;IAAAA,CACK5D,GAAAA,WAAc,qBAAA;EAAA;;;;EAMnBkC,IAAAA,GAAO,mBAAA,GAAsB,mBAAA;EAC7BD,IAAAA,GAAO,eAAA;EACPkB,KAAAA,GAAQ,eAAA;;;;EAKRzC,UAAAA;EACAC,OAAAA;EACAC,gBAAAA;EACAC,OAAAA;EACAC,gBAAAA;;;;EAKAC,SAAAA;EACAC,SAAAA;EACAC,OAAAA;;;;EAKAG,KAAAA,GAAQ,qBAAA,GAAwB,qBAAA;EAChCF,eAAAA,GAAkB,qBAAA;EAClBG,QAAAA;EACAC,QAAAA;EACAC,WAAAA;EACA0B,QAAAA,GAAW,qBAAA;;;;EAKXzB,aAAAA;EACAC,aAAAA;EACAC,QAAAA;EACAI,UAAAA;IAAAA,CACK9B,GAAAA,WAAc,qBAAA;EAAA;EAEnB+B,iBAAAA;IAAAA,CACK/B,GAAAA,WAAc,qBAAA;EAAA;EAEnB2B,oBAAAA,GAAuB,qBAAA;EACvBK,YAAAA;IAAAA,CACKhC,GAAAA,WAAc,qBAAA;EAAA;EAEnBkD,aAAAA,GAAgB,qBAAA;;;;EAKhBa,EAAAA,GAAK,qBAAA;EACLC,IAAAA,GAAO,qBAAA;EACPC,IAAAA,GAAO,qBAAA;;;;EAKP7B,KAAAA,GAAQ,qBAAA;EACRC,KAAAA,GAAQ,qBAAA;EACRC,KAAAA,GAAQ,qBAAA;EACRC,GAAAA,GAAM,qBAAA;;;;EAKNE,MAAAA;;;;EAKAyB,gBAAAA;EACAC,eAAAA;;;;EAKAvC,WAAAA;IAAAA,CACK5B,GAAAA,WAAc,qBAAA;EAAA;;;;EAMnBO,KAAAA;EACAC,WAAAA;EACAC,OAAAA,GAAU,eAAA;EACV2D,QAAAA;EACAC,SAAAA;EACAhB,QAAAA,GAAW,eAAA;AAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../../../../../../node_modules/.pnpm/@types+json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts"],"x_google_ignoreList":[0],"mappings":";;;;;;;;;;KA+iBY;;;;;;KAaA;sBAIN,oBACA;;UAIW;GACZ,cAAc;;;;UAKF,yBAAyB,MAAM;;;;;;;;;;;;KAapC;;;;;KAMA,wBAAwB;UACnB;EACb;EACA;EACA,UAAU;EACV;;;;;EAMA;KACK,cAAc;;;;;EAMnB,OAAO,sBAAsB;EAC7B,OAAO;EACP,QAAQ;;;;EAKR;EACA;EACA;EACA;EACA;;;;EAKA;EACA;EACA;;;;EAKA,QAAQ,wBAAwB;EAChC,kBAAkB;EAClB;EACA;EACA;EACA,WAAW;;;;EAKX;EACA;EACA;EACA;KACK,cAAc;;EAEnB;KACK,cAAc;;EAEnB,uBAAuB;EACvB;KACK,cAAc;;EAEnB,gBAAgB;;;;EAKhB,KAAK;EACL,OAAO;EACP,OAAO;;;;EAKP,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,MAAM;;;;EAKN;;;;EAKA;EACA;;;;EAKA;KACK,cAAc;;;;;EAMnB;EACA;EACA,UAAU;EACV;EACA;EACA,WAAW"}
@@ -1,15 +1,15 @@
1
1
  import { GenerativeUILibrary, GenerativeUIRenderContext } from "./types.js";
2
2
  import { ReactNode } from "react";
3
-
4
3
  //#region src/renderGenerativeUI.d.ts
5
4
  /**
6
5
  * Renders a generative-ui tree against a {@link GenerativeUILibrary}.
7
6
  *
8
7
  * The model emits each node as a flat object `{ $type, ...props }`. We first
9
- * normalize that wire form into React-shaped elements (`{ type, props }`), then
10
- * render: each `type` is looked up in the library and its `props` are passed
11
- * to the component's `render(props, context)`, with `children` rendered
12
- * recursively so components can nest.
8
+ * normalize that wire form into the canonical {@link NormalizedUINode} (with
9
+ * `children` lifted to a reserved top-level key), then render: each `type` is
10
+ * looked up in the library and its `props` are passed to the component's
11
+ * `render(props, context)`, with `children` rendered recursively so components
12
+ * can nest.
13
13
  */
14
14
  declare function renderGenerativeUI(node: unknown, library: GenerativeUILibrary, context?: GenerativeUIRenderContext): ReactNode;
15
15
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"renderGenerativeUI.d.ts","names":[],"sources":["../src/renderGenerativeUI.tsx"],"mappings":";;;;;;AAqBA;;;;;;;iBAAgB,kBAAA,CACd,IAAA,WACA,OAAA,EAAS,mBAAA,EACT,OAAA,GAAS,yBAAA,GACR,SAAA"}
1
+ {"version":3,"file":"renderGenerativeUI.d.ts","names":[],"sources":["../src/renderGenerativeUI.tsx"],"mappings":";;;;;;;;;;;;;iBAwBgB,mBACd,eACA,SAAS,qBACT,UAAS,4BACR"}
@@ -1,60 +1,29 @@
1
- import { TYPE_KEY } from "./constants.js";
1
+ import { normalizeUINode } from "./ir.js";
2
2
  import { getPartialJsonObjectMeta } from "assistant-stream/utils";
3
3
  import { Fragment } from "react";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  //#region src/renderGenerativeUI.tsx
6
6
  const DEFAULT_CONTEXT = { status: "done" };
7
+ const isElement = (node) => typeof node === "object" && node !== null && !Array.isArray(node);
7
8
  /**
8
9
  * Renders a generative-ui tree against a {@link GenerativeUILibrary}.
9
10
  *
10
11
  * The model emits each node as a flat object `{ $type, ...props }`. We first
11
- * normalize that wire form into React-shaped elements (`{ type, props }`), then
12
- * render: each `type` is looked up in the library and its `props` are passed
13
- * to the component's `render(props, context)`, with `children` rendered
14
- * recursively so components can nest.
12
+ * normalize that wire form into the canonical {@link NormalizedUINode} (with
13
+ * `children` lifted to a reserved top-level key), then render: each `type` is
14
+ * looked up in the library and its `props` are passed to the component's
15
+ * `render(props, context)`, with `children` rendered recursively so components
16
+ * can nest.
15
17
  */
16
18
  function renderGenerativeUI(node, library, context = DEFAULT_CONTEXT) {
17
19
  const meta = getPartialJsonObjectMeta(node);
18
- return renderNode(normalizeNode(node, meta?.state === "partial" ? meta.partialPath : void 0), library, context);
19
- }
20
- /**
21
- * The deepest tree we normalize. The input comes from the model, so a runaway
22
- * or adversarial response could nest arbitrarily deep and overflow the stack;
23
- * past this depth we stop (far beyond any real UI). Bounding normalization
24
- * bounds rendering too, since it only walks the normalized tree.
25
- */
26
- const MAX_DEPTH = 64;
27
- /**
28
- * Converts the flat wire form into a normalized {@link GenerativeUINode}.
29
- *
30
- * `partialPath` is the remaining segment of the parse meta's partial path
31
- * relative to `node` (`undefined` once the walk leaves the partial frontier,
32
- * i.e. everything below is complete).
33
- */
34
- function normalizeNode(node, partialPath, depth = 0) {
35
- if (depth > MAX_DEPTH) return null;
36
- if (node == null || typeof node === "boolean") return null;
37
- if (typeof node === "string" || typeof node === "number") return node;
38
- if (Array.isArray(node)) return node.map((child, index) => normalizeNode(child, descend(partialPath, String(index)), depth + 1));
39
- if (typeof node !== "object") return null;
40
- const { [TYPE_KEY]: type, ...props } = node;
41
- if (typeof type !== "string") return null;
42
- if (partialPath?.length === 1 && partialPath[0] === "$type") return null;
43
- if ("children" in props) props["children"] = normalizeNode(props["children"], descend(partialPath, "children"), depth + 1);
44
- return {
45
- type,
46
- props
47
- };
48
- }
49
- /** Steps the partial path down into `key`; siblings of the path are complete. */
50
- function descend(partialPath, key) {
51
- return partialPath?.[0] === key ? partialPath.slice(1) : void 0;
20
+ return renderNode(normalizeUINode(node, meta?.state === "partial" ? meta.partialPath : void 0), library, context);
52
21
  }
53
22
  function renderNode(node, library, context) {
54
23
  if (node == null || typeof node === "boolean") return null;
55
24
  if (typeof node === "string" || typeof node === "number") return node;
56
- if (Array.isArray(node)) return node.map((child, index) => /* @__PURE__ */ jsx(Fragment, { children: renderNode(child, library, context) }, `${index}:${nodeKind(child)}`));
57
- return renderElement(node, library, context);
25
+ if (Array.isArray(node)) return node.map((child, index) => /* @__PURE__ */ jsx(Fragment, { children: renderNode(child, library, context) }, nodeKey(child, index)));
26
+ return isElement(node) ? renderElement(node, library, context) : null;
58
27
  }
59
28
  function renderElement(element, library, context) {
60
29
  const entry = library[element.type];
@@ -63,12 +32,13 @@ function renderElement(element, library, context) {
63
32
  return null;
64
33
  }
65
34
  if (!entry.streamProperties && context.status === "streaming") return null;
66
- const { children, ...rest } = element.props;
67
35
  const props = {
68
- ...rest,
36
+ ...element.props,
69
37
  $status: context.status
70
38
  };
71
- if (children !== void 0) props["children"] = renderNode(children, library, context);
39
+ if (context.dispatch !== void 0) props["$dispatch"] = context.dispatch;
40
+ if (element.action !== void 0) props["$action"] = element.action;
41
+ if (element.children !== void 0) props["children"] = renderNode(element.children, library, context);
72
42
  return /* @__PURE__ */ jsx(GenerativeUIComponentRenderer, {
73
43
  render: entry.render,
74
44
  props
@@ -87,7 +57,10 @@ function nodeKind(node) {
87
57
  if (node == null || typeof node === "boolean") return "";
88
58
  if (typeof node === "string" || typeof node === "number") return "#text";
89
59
  if (Array.isArray(node)) return "#array";
90
- return node.type;
60
+ return isElement(node) ? node.type : "";
61
+ }
62
+ function nodeKey(node, index) {
63
+ return isElement(node) && (typeof node.key === "string" || typeof node.key === "number") ? `model:${node.key}` : `${index}:${nodeKind(node)}`;
91
64
  }
92
65
  function reportUnknownComponent(type, available) {
93
66
  if (process.env["NODE_ENV"] !== "production") console.error(`[@assistant-ui/react-generative-ui] Unknown component "${type}". Available components: ${available.join(", ") || "(none)"}.`);
@@ -1 +1 @@
1
- {"version":3,"file":"renderGenerativeUI.js","names":[],"sources":["../src/renderGenerativeUI.tsx"],"sourcesContent":["import { getPartialJsonObjectMeta } from \"assistant-stream/utils\";\nimport { Fragment, type ReactNode } from \"react\";\nimport { TYPE_KEY } from \"./constants\";\nimport type {\n GenerativeUIElement,\n GenerativeUILibrary,\n GenerativeUINode,\n GenerativeUIRenderContext,\n} from \"./types\";\n\nconst DEFAULT_CONTEXT: GenerativeUIRenderContext = { status: \"done\" };\n\n/**\n * Renders a generative-ui tree against a {@link GenerativeUILibrary}.\n *\n * The model emits each node as a flat object `{ $type, ...props }`. We first\n * normalize that wire form into React-shaped elements (`{ type, props }`), then\n * render: each `type` is looked up in the library and its `props` are passed\n * to the component's `render(props, context)`, with `children` rendered\n * recursively so components can nest.\n */\nexport function renderGenerativeUI(\n node: unknown,\n library: GenerativeUILibrary,\n context: GenerativeUIRenderContext = DEFAULT_CONTEXT,\n): ReactNode {\n // Tool args are parsed incrementally, and the parse meta records which path\n // is still mid-arrival, so normalization can hold back a node whose `$type`\n // string has not finished streaming.\n const meta = getPartialJsonObjectMeta(node as Record<symbol, unknown>);\n const partialPath = meta?.state === \"partial\" ? meta.partialPath : undefined;\n return renderNode(normalizeNode(node, partialPath), library, context);\n}\n\n/**\n * The deepest tree we normalize. The input comes from the model, so a runaway\n * or adversarial response could nest arbitrarily deep and overflow the stack;\n * past this depth we stop (far beyond any real UI). Bounding normalization\n * bounds rendering too, since it only walks the normalized tree.\n */\nconst MAX_DEPTH = 64;\n\n/**\n * Converts the flat wire form into a normalized {@link GenerativeUINode}.\n *\n * `partialPath` is the remaining segment of the parse meta's partial path\n * relative to `node` (`undefined` once the walk leaves the partial frontier,\n * i.e. everything below is complete).\n */\nfunction normalizeNode(\n node: unknown,\n partialPath: readonly string[] | undefined,\n depth = 0,\n): GenerativeUINode {\n if (depth > MAX_DEPTH) return null;\n if (node == null || typeof node === \"boolean\") return null;\n if (typeof node === \"string\" || typeof node === \"number\") return node;\n if (Array.isArray(node))\n return node.map((child, index) =>\n normalizeNode(child, descend(partialPath, String(index)), depth + 1),\n );\n if (typeof node !== \"object\") return null;\n\n const { [TYPE_KEY]: type, ...props } = node as Record<string, unknown>;\n // Args stream in incrementally; a node whose `$type` has not arrived yet\n // (or whose `$type` string is still mid-arrival) is not an error, it just\n // isn't renderable.\n if (typeof type !== \"string\") return null;\n if (partialPath?.length === 1 && partialPath[0] === TYPE_KEY) return null;\n\n if (\"children\" in props) {\n props[\"children\"] = normalizeNode(\n props[\"children\"],\n descend(partialPath, \"children\"),\n depth + 1,\n );\n }\n return { type, props } as GenerativeUIElement;\n}\n\n/** Steps the partial path down into `key`; siblings of the path are complete. */\nfunction descend(\n partialPath: readonly string[] | undefined,\n key: string,\n): readonly string[] | undefined {\n return partialPath?.[0] === key ? partialPath.slice(1) : undefined;\n}\n\nfunction renderNode(\n node: GenerativeUINode,\n library: GenerativeUILibrary,\n context: GenerativeUIRenderContext,\n): ReactNode {\n if (node == null || typeof node === \"boolean\") return null;\n if (typeof node === \"string\" || typeof node === \"number\") return node;\n if (Array.isArray(node)) {\n // The wire format has no per-node id, so the key is positional. Pairing the\n // index with the node's kind means that when the model splices or reorders\n // `children` and the kind at an index changes, the key changes and React\n // remounts instead of handing a streaming node's hook state to a different\n // component.\n return node.map((child, index) => (\n <Fragment key={`${index}:${nodeKind(child)}`}>\n {renderNode(child, library, context)}\n </Fragment>\n ));\n }\n return renderElement(node, library, context);\n}\n\nfunction renderElement(\n element: GenerativeUIElement,\n library: GenerativeUILibrary,\n context: GenerativeUIRenderContext,\n): ReactNode {\n const entry = library[element.type];\n if (!entry) {\n reportUnknownComponent(element.type, Object.keys(library));\n return null;\n }\n\n // Components that opt out of prop streaming wait until their props are\n // complete rather than rendering from a partial parse.\n if (!entry.streamProperties && context.status === \"streaming\") return null;\n\n // Inject the framework props last so the model can never override them.\n const { children, ...rest } = element.props;\n const props: Record<string, unknown> = { ...rest, $status: context.status };\n if (children !== undefined) {\n props[\"children\"] = renderNode(children, library, context);\n }\n\n return <GenerativeUIComponentRenderer render={entry.render} props={props} />;\n}\n\n/**\n * Mounts a single node's `render` on its own fiber so the function may use\n * hooks and hold state independently of its siblings and parent.\n */\nfunction GenerativeUIComponentRenderer({\n render,\n props,\n}: {\n render: (props: any) => ReactNode;\n props: Record<string, unknown>;\n}): ReactNode {\n return render(props);\n}\n\n/** A coarse kind tag for a child, used in its list key so a node changing kind\n * at a given index forces a remount rather than a wrong-fiber reuse. */\nfunction nodeKind(node: GenerativeUINode): string {\n if (node == null || typeof node === \"boolean\") return \"\";\n if (typeof node === \"string\" || typeof node === \"number\") return \"#text\";\n if (Array.isArray(node)) return \"#array\";\n return node.type;\n}\n\nfunction reportUnknownComponent(type: string, available: string[]): void {\n if (process.env[\"NODE_ENV\"] !== \"production\") {\n // eslint-disable-next-line no-console\n console.error(\n `[@assistant-ui/react-generative-ui] Unknown component \"${type}\". ` +\n `Available components: ${available.join(\", \") || \"(none)\"}.`,\n );\n }\n}\n"],"mappings":";;;;;AAUA,MAAM,kBAA6C,EAAE,QAAQ,OAAO;;;;;;;;;;AAWpE,SAAgB,mBACd,MACA,SACA,UAAqC,iBAC1B;CAIX,MAAM,OAAO,yBAAyB,IAA+B;CAErE,OAAO,WAAW,cAAc,MADZ,MAAM,UAAU,YAAY,KAAK,cAAc,KAAA,CAClB,GAAG,SAAS,OAAO;AACtE;;;;;;;AAQA,MAAM,YAAY;;;;;;;;AASlB,SAAS,cACP,MACA,aACA,QAAQ,GACU;CAClB,IAAI,QAAQ,WAAW,OAAO;CAC9B,IAAI,QAAQ,QAAQ,OAAO,SAAS,WAAW,OAAO;CACtD,IAAI,OAAO,SAAS,YAAY,OAAO,SAAS,UAAU,OAAO;CACjE,IAAI,MAAM,QAAQ,IAAI,GACpB,OAAO,KAAK,KAAK,OAAO,UACtB,cAAc,OAAO,QAAQ,aAAa,OAAO,KAAK,CAAC,GAAG,QAAQ,CAAC,CACrE;CACF,IAAI,OAAO,SAAS,UAAU,OAAO;CAErC,MAAM,GAAG,WAAW,MAAM,GAAG,UAAU;CAIvC,IAAI,OAAO,SAAS,UAAU,OAAO;CACrC,IAAI,aAAa,WAAW,KAAK,YAAY,OAAA,SAAiB,OAAO;CAErE,IAAI,cAAc,OAChB,MAAM,cAAc,cAClB,MAAM,aACN,QAAQ,aAAa,UAAU,GAC/B,QAAQ,CACV;CAEF,OAAO;EAAE;EAAM;CAAM;AACvB;;AAGA,SAAS,QACP,aACA,KAC+B;CAC/B,OAAO,cAAc,OAAO,MAAM,YAAY,MAAM,CAAC,IAAI,KAAA;AAC3D;AAEA,SAAS,WACP,MACA,SACA,SACW;CACX,IAAI,QAAQ,QAAQ,OAAO,SAAS,WAAW,OAAO;CACtD,IAAI,OAAO,SAAS,YAAY,OAAO,SAAS,UAAU,OAAO;CACjE,IAAI,MAAM,QAAQ,IAAI,GAMpB,OAAO,KAAK,KAAK,OAAO,UACtB,oBAAC,UAAD,EAAA,UACG,WAAW,OAAO,SAAS,OAAO,EAC3B,GAFK,GAAG,MAAM,GAAG,SAAS,KAAK,GAE/B,CACX;CAEH,OAAO,cAAc,MAAM,SAAS,OAAO;AAC7C;AAEA,SAAS,cACP,SACA,SACA,SACW;CACX,MAAM,QAAQ,QAAQ,QAAQ;CAC9B,IAAI,CAAC,OAAO;EACV,uBAAuB,QAAQ,MAAM,OAAO,KAAK,OAAO,CAAC;EACzD,OAAO;CACT;CAIA,IAAI,CAAC,MAAM,oBAAoB,QAAQ,WAAW,aAAa,OAAO;CAGtE,MAAM,EAAE,UAAU,GAAG,SAAS,QAAQ;CACtC,MAAM,QAAiC;EAAE,GAAG;EAAM,SAAS,QAAQ;CAAO;CAC1E,IAAI,aAAa,KAAA,GACf,MAAM,cAAc,WAAW,UAAU,SAAS,OAAO;CAG3D,OAAO,oBAAC,+BAAD;EAA+B,QAAQ,MAAM;EAAe;CAAQ,CAAA;AAC7E;;;;;AAMA,SAAS,8BAA8B,EACrC,QACA,SAIY;CACZ,OAAO,OAAO,KAAK;AACrB;;;AAIA,SAAS,SAAS,MAAgC;CAChD,IAAI,QAAQ,QAAQ,OAAO,SAAS,WAAW,OAAO;CACtD,IAAI,OAAO,SAAS,YAAY,OAAO,SAAS,UAAU,OAAO;CACjE,IAAI,MAAM,QAAQ,IAAI,GAAG,OAAO;CAChC,OAAO,KAAK;AACd;AAEA,SAAS,uBAAuB,MAAc,WAA2B;CACvE,IAAI,QAAQ,IAAI,gBAAgB,cAE9B,QAAQ,MACN,0DAA0D,KAAK,2BACpC,UAAU,KAAK,IAAI,KAAK,SAAS,EAC9D;AAEJ"}
1
+ {"version":3,"file":"renderGenerativeUI.js","names":[],"sources":["../src/renderGenerativeUI.tsx"],"sourcesContent":["import { getPartialJsonObjectMeta } from \"assistant-stream/utils\";\nimport { Fragment, type ReactNode } from \"react\";\nimport {\n normalizeUINode,\n type NormalizedUIElement,\n type NormalizedUINode,\n} from \"./ir\";\nimport type { GenerativeUILibrary, GenerativeUIRenderContext } from \"./types\";\n\nconst DEFAULT_CONTEXT: GenerativeUIRenderContext = { status: \"done\" };\n\nconst isElement = (node: NormalizedUINode): node is NormalizedUIElement =>\n typeof node === \"object\" && node !== null && !Array.isArray(node);\n\n/**\n * Renders a generative-ui tree against a {@link GenerativeUILibrary}.\n *\n * The model emits each node as a flat object `{ $type, ...props }`. We first\n * normalize that wire form into the canonical {@link NormalizedUINode} (with\n * `children` lifted to a reserved top-level key), then render: each `type` is\n * looked up in the library and its `props` are passed to the component's\n * `render(props, context)`, with `children` rendered recursively so components\n * can nest.\n */\nexport function renderGenerativeUI(\n node: unknown,\n library: GenerativeUILibrary,\n context: GenerativeUIRenderContext = DEFAULT_CONTEXT,\n): ReactNode {\n // Tool args are parsed incrementally, and the parse meta records which path\n // is still mid-arrival, so normalization can hold back a node whose `$type`\n // string has not finished streaming.\n const meta = getPartialJsonObjectMeta(node as Record<symbol, unknown>);\n const partialPath = meta?.state === \"partial\" ? meta.partialPath : undefined;\n return renderNode(normalizeUINode(node, partialPath), library, context);\n}\n\nfunction renderNode(\n node: NormalizedUINode,\n library: GenerativeUILibrary,\n context: GenerativeUIRenderContext,\n): ReactNode {\n if (node == null || typeof node === \"boolean\") return null;\n if (typeof node === \"string\" || typeof node === \"number\") return node;\n if (Array.isArray(node)) {\n // Use a model-provided stable key when present. Otherwise, keep the\n // positional fallback: pairing the index with the node's kind means that\n // when the kind at an index changes, React remounts instead of handing a\n // streaming node's hook state to a different component.\n return node.map((child, index) => (\n <Fragment key={nodeKey(child, index)}>\n {renderNode(child, library, context)}\n </Fragment>\n ));\n }\n return isElement(node) ? renderElement(node, library, context) : null;\n}\n\nfunction renderElement(\n element: NormalizedUIElement,\n library: GenerativeUILibrary,\n context: GenerativeUIRenderContext,\n): ReactNode {\n const entry = library[element.type];\n if (!entry) {\n reportUnknownComponent(element.type, Object.keys(library));\n return null;\n }\n\n // Components that opt out of prop streaming wait until their props are\n // complete rather than rendering from a partial parse.\n if (!entry.streamProperties && context.status === \"streaming\") return null;\n\n // `children` is a reserved top-level key on the normalized element, not a\n // prop, so it is not in `props`. Inject the framework props last so the model\n // can never override them. `$action` is likewise reserved and stripped from\n // the prop bag during normalization, so it is re-injected here for components\n // that carry behavior (e.g. `Button`).\n const props: Record<string, unknown> = {\n ...element.props,\n $status: context.status,\n };\n if (context.dispatch !== undefined) {\n props[\"$dispatch\"] = context.dispatch;\n }\n if (element.action !== undefined) {\n props[\"$action\"] = element.action;\n }\n if (element.children !== undefined) {\n props[\"children\"] = renderNode(element.children, library, context);\n }\n\n return <GenerativeUIComponentRenderer render={entry.render} props={props} />;\n}\n\n/**\n * Mounts a single node's `render` on its own fiber so the function may use\n * hooks and hold state independently of its siblings and parent.\n */\nfunction GenerativeUIComponentRenderer({\n render,\n props,\n}: {\n render: (props: any) => ReactNode;\n props: Record<string, unknown>;\n}): ReactNode {\n return render(props);\n}\n\n/** A coarse kind tag for a child, used in its list key so a node changing kind\n * at a given index forces a remount rather than a wrong-fiber reuse. */\nfunction nodeKind(node: NormalizedUINode): string {\n if (node == null || typeof node === \"boolean\") return \"\";\n if (typeof node === \"string\" || typeof node === \"number\") return \"#text\";\n if (Array.isArray(node)) return \"#array\";\n return isElement(node) ? node.type : \"\";\n}\n\nfunction nodeKey(node: NormalizedUINode, index: number): string {\n return isElement(node) &&\n (typeof node.key === \"string\" || typeof node.key === \"number\")\n ? `model:${node.key}`\n : `${index}:${nodeKind(node)}`;\n}\n\nfunction reportUnknownComponent(type: string, available: string[]): void {\n if (process.env[\"NODE_ENV\"] !== \"production\") {\n // eslint-disable-next-line no-console\n console.error(\n `[@assistant-ui/react-generative-ui] Unknown component \"${type}\". ` +\n `Available components: ${available.join(\", \") || \"(none)\"}.`,\n );\n }\n}\n"],"mappings":";;;;;AASA,MAAM,kBAA6C,EAAE,QAAQ,OAAO;AAEpE,MAAM,aAAa,SACjB,OAAO,SAAS,YAAY,SAAS,QAAQ,CAAC,MAAM,QAAQ,IAAI;;;;;;;;;;;AAYlE,SAAgB,mBACd,MACA,SACA,UAAqC,iBAC1B;CAIX,MAAM,OAAO,yBAAyB,IAA+B;CAErE,OAAO,WAAW,gBAAgB,MADd,MAAM,UAAU,YAAY,KAAK,cAAc,KAAA,CAChB,GAAG,SAAS,OAAO;AACxE;AAEA,SAAS,WACP,MACA,SACA,SACW;CACX,IAAI,QAAQ,QAAQ,OAAO,SAAS,WAAW,OAAO;CACtD,IAAI,OAAO,SAAS,YAAY,OAAO,SAAS,UAAU,OAAO;CACjE,IAAI,MAAM,QAAQ,IAAI,GAKpB,OAAO,KAAK,KAAK,OAAO,UACtB,oBAAC,UAAD,EAAA,UACG,WAAW,OAAO,SAAS,OAAO,EAC3B,GAFK,QAAQ,OAAO,KAAK,CAEzB,CACX;CAEH,OAAO,UAAU,IAAI,IAAI,cAAc,MAAM,SAAS,OAAO,IAAI;AACnE;AAEA,SAAS,cACP,SACA,SACA,SACW;CACX,MAAM,QAAQ,QAAQ,QAAQ;CAC9B,IAAI,CAAC,OAAO;EACV,uBAAuB,QAAQ,MAAM,OAAO,KAAK,OAAO,CAAC;EACzD,OAAO;CACT;CAIA,IAAI,CAAC,MAAM,oBAAoB,QAAQ,WAAW,aAAa,OAAO;CAOtE,MAAM,QAAiC;EACrC,GAAG,QAAQ;EACX,SAAS,QAAQ;CACnB;CACA,IAAI,QAAQ,aAAa,KAAA,GACvB,MAAM,eAAe,QAAQ;CAE/B,IAAI,QAAQ,WAAW,KAAA,GACrB,MAAM,aAAa,QAAQ;CAE7B,IAAI,QAAQ,aAAa,KAAA,GACvB,MAAM,cAAc,WAAW,QAAQ,UAAU,SAAS,OAAO;CAGnE,OAAO,oBAAC,+BAAD;EAA+B,QAAQ,MAAM;EAAe;CAAQ,CAAA;AAC7E;;;;;AAMA,SAAS,8BAA8B,EACrC,QACA,SAIY;CACZ,OAAO,OAAO,KAAK;AACrB;;;AAIA,SAAS,SAAS,MAAgC;CAChD,IAAI,QAAQ,QAAQ,OAAO,SAAS,WAAW,OAAO;CACtD,IAAI,OAAO,SAAS,YAAY,OAAO,SAAS,UAAU,OAAO;CACjE,IAAI,MAAM,QAAQ,IAAI,GAAG,OAAO;CAChC,OAAO,UAAU,IAAI,IAAI,KAAK,OAAO;AACvC;AAEA,SAAS,QAAQ,MAAwB,OAAuB;CAC9D,OAAO,UAAU,IAAI,MAClB,OAAO,KAAK,QAAQ,YAAY,OAAO,KAAK,QAAQ,YACnD,SAAS,KAAK,QACd,GAAG,MAAM,GAAG,SAAS,IAAI;AAC/B;AAEA,SAAS,uBAAuB,MAAc,WAA2B;CACvE,IAAI,QAAQ,IAAI,gBAAgB,cAE9B,QAAQ,MACN,0DAA0D,KAAK,2BACpC,UAAU,KAAK,IAAI,KAAK,SAAS,EAC9D;AAEJ"}