@seed-ship/mcp-ui-solid 6.19.1 → 6.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (282) hide show
  1. package/CHANGELOG.md +663 -0
  2. package/README.md +911 -4
  3. package/dist/adapters/connector.cjs +15 -4
  4. package/dist/adapters/connector.cjs.map +1 -1
  5. package/dist/adapters/connector.d.ts +38 -0
  6. package/dist/adapters/connector.d.ts.map +1 -1
  7. package/dist/adapters/connector.js +15 -4
  8. package/dist/adapters/connector.js.map +1 -1
  9. package/dist/adapters/index.d.ts +4 -3
  10. package/dist/adapters/index.d.ts.map +1 -1
  11. package/dist/adapters/macro-run.cjs +25 -13
  12. package/dist/adapters/macro-run.cjs.map +1 -1
  13. package/dist/adapters/macro-run.d.ts +37 -2
  14. package/dist/adapters/macro-run.d.ts.map +1 -1
  15. package/dist/adapters/macro-run.js +25 -13
  16. package/dist/adapters/macro-run.js.map +1 -1
  17. package/dist/adapters.cjs +2 -0
  18. package/dist/adapters.cjs.map +1 -1
  19. package/dist/adapters.js +4 -2
  20. package/dist/components/ActionGroupRenderer.cjs +3 -1
  21. package/dist/components/ActionGroupRenderer.cjs.map +1 -1
  22. package/dist/components/ActionGroupRenderer.d.ts.map +1 -1
  23. package/dist/components/ActionGroupRenderer.js +3 -1
  24. package/dist/components/ActionGroupRenderer.js.map +1 -1
  25. package/dist/components/AgentCard.cjs +11 -8
  26. package/dist/components/AgentCard.cjs.map +1 -1
  27. package/dist/components/AgentCard.d.ts.map +1 -1
  28. package/dist/components/AgentCard.js +11 -8
  29. package/dist/components/AgentCard.js.map +1 -1
  30. package/dist/components/AgentHandoff.cjs +6 -1
  31. package/dist/components/AgentHandoff.cjs.map +1 -1
  32. package/dist/components/AgentHandoff.d.ts.map +1 -1
  33. package/dist/components/AgentHandoff.js +6 -1
  34. package/dist/components/AgentHandoff.js.map +1 -1
  35. package/dist/components/ArtifactRenderer.cjs +25 -6
  36. package/dist/components/ArtifactRenderer.cjs.map +1 -1
  37. package/dist/components/ArtifactRenderer.d.ts.map +1 -1
  38. package/dist/components/ArtifactRenderer.js +25 -6
  39. package/dist/components/ArtifactRenderer.js.map +1 -1
  40. package/dist/components/AutocompleteDropdown.cjs +30 -24
  41. package/dist/components/AutocompleteDropdown.cjs.map +1 -1
  42. package/dist/components/AutocompleteDropdown.d.ts.map +1 -1
  43. package/dist/components/AutocompleteDropdown.js +30 -24
  44. package/dist/components/AutocompleteDropdown.js.map +1 -1
  45. package/dist/components/AutocompleteFormField.cjs +3 -1
  46. package/dist/components/AutocompleteFormField.cjs.map +1 -1
  47. package/dist/components/AutocompleteFormField.d.ts.map +1 -1
  48. package/dist/components/AutocompleteFormField.js +4 -2
  49. package/dist/components/AutocompleteFormField.js.map +1 -1
  50. package/dist/components/BriefingDiff.cjs +45 -39
  51. package/dist/components/BriefingDiff.cjs.map +1 -1
  52. package/dist/components/BriefingDiff.d.ts.map +1 -1
  53. package/dist/components/BriefingDiff.js +45 -39
  54. package/dist/components/BriefingDiff.js.map +1 -1
  55. package/dist/components/CarouselRenderer.cjs +8 -2
  56. package/dist/components/CarouselRenderer.cjs.map +1 -1
  57. package/dist/components/CarouselRenderer.d.ts.map +1 -1
  58. package/dist/components/CarouselRenderer.js +8 -2
  59. package/dist/components/CarouselRenderer.js.map +1 -1
  60. package/dist/components/ChartJSRenderer.cjs +60 -36
  61. package/dist/components/ChartJSRenderer.cjs.map +1 -1
  62. package/dist/components/ChartJSRenderer.d.ts.map +1 -1
  63. package/dist/components/ChartJSRenderer.js +61 -37
  64. package/dist/components/ChartJSRenderer.js.map +1 -1
  65. package/dist/components/ChatPrompt.cjs +15 -9
  66. package/dist/components/ChatPrompt.cjs.map +1 -1
  67. package/dist/components/ChatPrompt.d.ts.map +1 -1
  68. package/dist/components/ChatPrompt.js +15 -9
  69. package/dist/components/ChatPrompt.js.map +1 -1
  70. package/dist/components/CodeBlockRenderer.cjs +34 -16
  71. package/dist/components/CodeBlockRenderer.cjs.map +1 -1
  72. package/dist/components/CodeBlockRenderer.d.ts.map +1 -1
  73. package/dist/components/CodeBlockRenderer.js +34 -16
  74. package/dist/components/CodeBlockRenderer.js.map +1 -1
  75. package/dist/components/DataPreviewSection.cjs +91 -44
  76. package/dist/components/DataPreviewSection.cjs.map +1 -1
  77. package/dist/components/DataPreviewSection.d.ts.map +1 -1
  78. package/dist/components/DataPreviewSection.js +92 -45
  79. package/dist/components/DataPreviewSection.js.map +1 -1
  80. package/dist/components/DegradedFallback.cjs +20 -16
  81. package/dist/components/DegradedFallback.cjs.map +1 -1
  82. package/dist/components/DegradedFallback.d.ts.map +1 -1
  83. package/dist/components/DegradedFallback.js +20 -16
  84. package/dist/components/DegradedFallback.js.map +1 -1
  85. package/dist/components/FooterRenderer.cjs +21 -17
  86. package/dist/components/FooterRenderer.cjs.map +1 -1
  87. package/dist/components/FooterRenderer.d.ts.map +1 -1
  88. package/dist/components/FooterRenderer.js +21 -17
  89. package/dist/components/FooterRenderer.js.map +1 -1
  90. package/dist/components/FormFieldRenderer.cjs +116 -93
  91. package/dist/components/FormFieldRenderer.cjs.map +1 -1
  92. package/dist/components/FormFieldRenderer.d.ts.map +1 -1
  93. package/dist/components/FormFieldRenderer.js +116 -93
  94. package/dist/components/FormFieldRenderer.js.map +1 -1
  95. package/dist/components/FormRenderer.cjs +55 -31
  96. package/dist/components/FormRenderer.cjs.map +1 -1
  97. package/dist/components/FormRenderer.d.ts.map +1 -1
  98. package/dist/components/FormRenderer.js +55 -31
  99. package/dist/components/FormRenderer.js.map +1 -1
  100. package/dist/components/GenerativeUIErrorBoundary.cjs +20 -15
  101. package/dist/components/GenerativeUIErrorBoundary.cjs.map +1 -1
  102. package/dist/components/GenerativeUIErrorBoundary.d.ts.map +1 -1
  103. package/dist/components/GenerativeUIErrorBoundary.js +20 -15
  104. package/dist/components/GenerativeUIErrorBoundary.js.map +1 -1
  105. package/dist/components/GraphRenderer.cjs +56 -33
  106. package/dist/components/GraphRenderer.cjs.map +1 -1
  107. package/dist/components/GraphRenderer.d.ts.map +1 -1
  108. package/dist/components/GraphRenderer.js +56 -33
  109. package/dist/components/GraphRenderer.js.map +1 -1
  110. package/dist/components/IframeFallbackLink.cjs +37 -0
  111. package/dist/components/IframeFallbackLink.cjs.map +1 -0
  112. package/dist/components/IframeFallbackLink.d.ts +23 -0
  113. package/dist/components/IframeFallbackLink.d.ts.map +1 -0
  114. package/dist/components/IframeFallbackLink.js +37 -0
  115. package/dist/components/IframeFallbackLink.js.map +1 -0
  116. package/dist/components/ImageGalleryRenderer.cjs +13 -4
  117. package/dist/components/ImageGalleryRenderer.cjs.map +1 -1
  118. package/dist/components/ImageGalleryRenderer.d.ts.map +1 -1
  119. package/dist/components/ImageGalleryRenderer.js +13 -4
  120. package/dist/components/ImageGalleryRenderer.js.map +1 -1
  121. package/dist/components/LightboxOverlay.cjs +16 -8
  122. package/dist/components/LightboxOverlay.cjs.map +1 -1
  123. package/dist/components/LightboxOverlay.d.ts.map +1 -1
  124. package/dist/components/LightboxOverlay.js +17 -9
  125. package/dist/components/LightboxOverlay.js.map +1 -1
  126. package/dist/components/MapRenderer.cjs +59 -29
  127. package/dist/components/MapRenderer.cjs.map +1 -1
  128. package/dist/components/MapRenderer.d.ts +10 -2
  129. package/dist/components/MapRenderer.d.ts.map +1 -1
  130. package/dist/components/MapRenderer.js +60 -30
  131. package/dist/components/MapRenderer.js.map +1 -1
  132. package/dist/components/ModalRenderer.cjs +4 -1
  133. package/dist/components/ModalRenderer.cjs.map +1 -1
  134. package/dist/components/ModalRenderer.d.ts.map +1 -1
  135. package/dist/components/ModalRenderer.js +5 -2
  136. package/dist/components/ModalRenderer.js.map +1 -1
  137. package/dist/components/ScratchpadPanel.cjs +578 -535
  138. package/dist/components/ScratchpadPanel.cjs.map +1 -1
  139. package/dist/components/ScratchpadPanel.d.ts.map +1 -1
  140. package/dist/components/ScratchpadPanel.js +578 -535
  141. package/dist/components/ScratchpadPanel.js.map +1 -1
  142. package/dist/components/StreamingUIRenderer.cjs +92 -28
  143. package/dist/components/StreamingUIRenderer.cjs.map +1 -1
  144. package/dist/components/StreamingUIRenderer.d.ts.map +1 -1
  145. package/dist/components/StreamingUIRenderer.js +92 -28
  146. package/dist/components/StreamingUIRenderer.js.map +1 -1
  147. package/dist/components/UIResourceRenderer.cjs +481 -365
  148. package/dist/components/UIResourceRenderer.cjs.map +1 -1
  149. package/dist/components/UIResourceRenderer.d.ts +21 -0
  150. package/dist/components/UIResourceRenderer.d.ts.map +1 -1
  151. package/dist/components/UIResourceRenderer.js +484 -368
  152. package/dist/components/UIResourceRenderer.js.map +1 -1
  153. package/dist/components/VerifiedText.cjs +39 -20
  154. package/dist/components/VerifiedText.cjs.map +1 -1
  155. package/dist/components/VerifiedText.d.ts +2 -1
  156. package/dist/components/VerifiedText.d.ts.map +1 -1
  157. package/dist/components/VerifiedText.js +39 -20
  158. package/dist/components/VerifiedText.js.map +1 -1
  159. package/dist/components/VideoRenderer.cjs +51 -20
  160. package/dist/components/VideoRenderer.cjs.map +1 -1
  161. package/dist/components/VideoRenderer.d.ts.map +1 -1
  162. package/dist/components/VideoRenderer.js +51 -20
  163. package/dist/components/VideoRenderer.js.map +1 -1
  164. package/dist/components/chart-data-table.cjs +38 -17
  165. package/dist/components/chart-data-table.cjs.map +1 -1
  166. package/dist/components/chart-data-table.d.ts +30 -1
  167. package/dist/components/chart-data-table.d.ts.map +1 -1
  168. package/dist/components/chart-data-table.js +38 -17
  169. package/dist/components/chart-data-table.js.map +1 -1
  170. package/dist/context/MCPActionContext.cjs +3 -1
  171. package/dist/context/MCPActionContext.cjs.map +1 -1
  172. package/dist/context/MCPActionContext.d.ts.map +1 -1
  173. package/dist/context/MCPActionContext.js +3 -1
  174. package/dist/context/MCPActionContext.js.map +1 -1
  175. package/dist/context/MCPUIConfigContext.cjs +29 -0
  176. package/dist/context/MCPUIConfigContext.cjs.map +1 -0
  177. package/dist/context/MCPUIConfigContext.d.ts +124 -0
  178. package/dist/context/MCPUIConfigContext.d.ts.map +1 -0
  179. package/dist/context/MCPUIConfigContext.js +29 -0
  180. package/dist/context/MCPUIConfigContext.js.map +1 -0
  181. package/dist/context/MCPUIStringsContext.cjs +287 -2
  182. package/dist/context/MCPUIStringsContext.cjs.map +1 -1
  183. package/dist/context/MCPUIStringsContext.d.ts +607 -3
  184. package/dist/context/MCPUIStringsContext.d.ts.map +1 -1
  185. package/dist/context/MCPUIStringsContext.js +287 -2
  186. package/dist/context/MCPUIStringsContext.js.map +1 -1
  187. package/dist/hooks/index.d.ts +2 -2
  188. package/dist/hooks/index.d.ts.map +1 -1
  189. package/dist/hooks/useStreamingUI.cjs +28 -10
  190. package/dist/hooks/useStreamingUI.cjs.map +1 -1
  191. package/dist/hooks/useStreamingUI.d.ts +37 -0
  192. package/dist/hooks/useStreamingUI.d.ts.map +1 -1
  193. package/dist/hooks/useStreamingUI.js +28 -10
  194. package/dist/hooks/useStreamingUI.js.map +1 -1
  195. package/dist/hooks.cjs +1 -0
  196. package/dist/hooks.cjs.map +1 -1
  197. package/dist/hooks.js +2 -1
  198. package/dist/index.cjs +29 -8
  199. package/dist/index.cjs.map +1 -1
  200. package/dist/index.d.cts +12 -4
  201. package/dist/index.d.ts +12 -4
  202. package/dist/index.d.ts.map +1 -1
  203. package/dist/index.js +24 -3
  204. package/dist/index.js.map +1 -1
  205. package/dist/services/index.d.ts +1 -1
  206. package/dist/services/index.d.ts.map +1 -1
  207. package/dist/services/validation.cjs +52 -26
  208. package/dist/services/validation.cjs.map +1 -1
  209. package/dist/services/validation.d.ts +67 -2
  210. package/dist/services/validation.d.ts.map +1 -1
  211. package/dist/services/validation.js +52 -26
  212. package/dist/services/validation.js.map +1 -1
  213. package/dist/utils/degraded-projections.cjs +37 -12
  214. package/dist/utils/degraded-projections.cjs.map +1 -1
  215. package/dist/utils/degraded-projections.d.ts +39 -3
  216. package/dist/utils/degraded-projections.d.ts.map +1 -1
  217. package/dist/utils/degraded-projections.js +37 -12
  218. package/dist/utils/degraded-projections.js.map +1 -1
  219. package/dist/utils/format-string.cjs +10 -0
  220. package/dist/utils/format-string.cjs.map +1 -0
  221. package/dist/utils/format-string.d.ts +26 -0
  222. package/dist/utils/format-string.d.ts.map +1 -0
  223. package/dist/utils/format-string.js +10 -0
  224. package/dist/utils/format-string.js.map +1 -0
  225. package/dist/utils/iframe-coep.cjs +30 -0
  226. package/dist/utils/iframe-coep.cjs.map +1 -0
  227. package/dist/utils/iframe-coep.d.ts +46 -0
  228. package/dist/utils/iframe-coep.d.ts.map +1 -0
  229. package/dist/utils/iframe-coep.js +30 -0
  230. package/dist/utils/iframe-coep.js.map +1 -0
  231. package/dist/validation.cjs +5 -0
  232. package/dist/validation.cjs.map +1 -1
  233. package/dist/validation.d.cts +2 -1
  234. package/dist/validation.d.ts +2 -1
  235. package/dist/validation.d.ts.map +1 -1
  236. package/dist/validation.js +6 -1
  237. package/package.json +1 -1
  238. package/src/adapters/connector.ts +58 -4
  239. package/src/adapters/index.ts +12 -2
  240. package/src/adapters/macro-run.ts +71 -11
  241. package/src/components/ActionGroupRenderer.tsx +3 -1
  242. package/src/components/AgentCard.tsx +27 -9
  243. package/src/components/AgentHandoff.tsx +4 -1
  244. package/src/components/ArtifactRenderer.tsx +17 -5
  245. package/src/components/AutocompleteDropdown.tsx +8 -6
  246. package/src/components/AutocompleteFormField.tsx +5 -1
  247. package/src/components/BriefingDiff.tsx +11 -3
  248. package/src/components/CarouselRenderer.tsx +4 -2
  249. package/src/components/ChartJSRenderer.tsx +18 -9
  250. package/src/components/ChatPrompt.tsx +13 -8
  251. package/src/components/CodeBlockRenderer.tsx +12 -10
  252. package/src/components/DataPreviewSection.tsx +92 -26
  253. package/src/components/DegradedFallback.tsx +4 -2
  254. package/src/components/FooterRenderer.tsx +3 -1
  255. package/src/components/FormFieldRenderer.tsx +34 -19
  256. package/src/components/FormRenderer.tsx +38 -10
  257. package/src/components/GenerativeUIErrorBoundary.tsx +8 -3
  258. package/src/components/GraphRenderer.tsx +31 -16
  259. package/src/components/IframeFallbackLink.tsx +57 -0
  260. package/src/components/ImageGalleryRenderer.tsx +8 -4
  261. package/src/components/LightboxOverlay.tsx +6 -4
  262. package/src/components/MapRenderer.tsx +57 -20
  263. package/src/components/ModalRenderer.tsx +3 -1
  264. package/src/components/ScratchpadPanel.tsx +95 -44
  265. package/src/components/StreamingUIRenderer.tsx +41 -11
  266. package/src/components/UIResourceRenderer.tsx +176 -67
  267. package/src/components/VerifiedText.tsx +19 -9
  268. package/src/components/VideoRenderer.tsx +26 -4
  269. package/src/components/chart-data-table.ts +68 -14
  270. package/src/context/MCPActionContext.tsx +4 -1
  271. package/src/context/MCPUIConfigContext.tsx +151 -0
  272. package/src/context/MCPUIStringsContext.tsx +1014 -1
  273. package/src/hooks/index.ts +2 -1
  274. package/src/hooks/useStreamingUI.ts +64 -10
  275. package/src/index.ts +38 -0
  276. package/src/services/index.ts +1 -0
  277. package/src/services/validation.ts +131 -32
  278. package/src/solid-jsx-attrs.d.ts +24 -0
  279. package/src/utils/degraded-projections.ts +75 -12
  280. package/src/utils/format-string.ts +33 -0
  281. package/src/utils/iframe-coep.ts +74 -0
  282. package/src/validation.ts +9 -0
@@ -10,6 +10,42 @@
10
10
  * isn't left with a blank space, not faithful reproductions of the chart/
11
11
  * map/graph.
12
12
  */
13
+ /**
14
+ * Column headers and series names of the degraded tables.
15
+ *
16
+ * The projections are pure helpers with no access to `MCPUIStrings`, so the
17
+ * wording is injected: each function takes an optional trailing `labels`
18
+ * partial, and the renderers feed it from `useMCPUIStrings()`. Left out, the
19
+ * English defaults below apply — the pre-v6.20.0 behaviour.
20
+ *
21
+ * @since v6.20.0
22
+ */
23
+ export interface DegradedProjectionLabels {
24
+ /** Graph edge table — source column. */
25
+ source: string;
26
+ /** Graph edge table — target column. */
27
+ target: string;
28
+ /** Graph edge / node table — label column. */
29
+ label: string;
30
+ /** Graph node table — node id column. */
31
+ node: string;
32
+ /** Map table — feature type column. */
33
+ type: string;
34
+ /** Map table — latitude column. */
35
+ lat: string;
36
+ /** Map table — longitude column. */
37
+ lng: string;
38
+ /** Map table — property summary column. */
39
+ info: string;
40
+ /** Map table — `Type` cell of a marker row (v6.20.0, 6th pass). */
41
+ marker: string;
42
+ /** Map table — `Type` cell of a GeoJSON feature without a geometry type (v6.20.0). */
43
+ feature: string;
44
+ /** Chart table — fallback dataset name. Template — `{n}`. */
45
+ series: string;
46
+ }
47
+ /** English defaults for {@link DegradedProjectionLabels}. */
48
+ export declare const DEGRADED_PROJECTION_LABELS: DegradedProjectionLabels;
13
49
  export interface DegradedTable {
14
50
  columns: string[];
15
51
  rows: Array<Array<string | number>>;
@@ -30,7 +66,7 @@ export declare function graphToDegradedTable(params: {
30
66
  label?: string;
31
67
  weight?: number;
32
68
  }>;
33
- }): DegradedTable;
69
+ }, labels?: Partial<DegradedProjectionLabels>): DegradedTable;
34
70
  /**
35
71
  * Map → a coordinate table. Markers become Lat/Lng/Label rows; GeoJSON
36
72
  * features become Type / Lat / Lng (+ a compact properties summary). So a
@@ -46,7 +82,7 @@ export declare function mapToDegradedTable(params: {
46
82
  popup?: string;
47
83
  }>;
48
84
  geojson?: unknown;
49
- }): DegradedTable;
85
+ }, labels?: Partial<DegradedProjectionLabels>): DegradedTable;
50
86
  /**
51
87
  * Chart → a series table: one row per label, one column per dataset. So a
52
88
  * chart that can't draw still shows its numbers. Point/object data (scatter,
@@ -60,5 +96,5 @@ export declare function chartToDegradedTable(params: {
60
96
  data?: unknown[];
61
97
  }>;
62
98
  };
63
- }): DegradedTable;
99
+ }, labels?: Partial<DegradedProjectionLabels>): DegradedTable;
64
100
  //# sourceMappingURL=degraded-projections.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"degraded-projections.d.ts","sourceRoot":"","sources":["../../src/utils/degraded-projections.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;CACrC;AAmBD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAC3C,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9C,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpF,GAAG,aAAa,CAkBhB;AAoBD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE;IACzC,OAAO,CAAC,EAAE,KAAK,CAAC;QACd,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,GAAG,EAAE,MAAM,CAAA;SAAE,CAAC;QAC1D,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG,aAAa,CA8BhB;AAID;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAC3C,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;QAChC,QAAQ,CAAC,EAAE,KAAK,CAAC;YAAE,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAA;SAAE,CAAC,CAAC;KACxD,CAAC;CACH,GAAG,aAAa,CAWhB"}
1
+ {"version":3,"file":"degraded-projections.d.ts","sourceRoot":"","sources":["../../src/utils/degraded-projections.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH;;;;;;;;;GASG;AACH,MAAM,WAAW,wBAAwB;IACvC,wCAAwC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,oCAAoC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC;IACf,sFAAsF;IACtF,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,6DAA6D;AAC7D,eAAO,MAAM,0BAA0B,EAAE,wBAYxC,CAAC;AAOF,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;CACrC;AAmBD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAC3C,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9C,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpF,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,wBAAwB,CAAC,GAAG,aAAa,CAmB5D;AAoBD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE;IACzC,OAAO,CAAC,EAAE,KAAK,CAAC;QACd,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,GAAG,EAAE,MAAM,CAAA;SAAE,CAAC;QAC1D,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,wBAAwB,CAAC,GAAG,aAAa,CA+B5D;AAID;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAC3C,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;QAChC,QAAQ,CAAC,EAAE,KAAK,CAAC;YAAE,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAA;SAAE,CAAC,CAAC;KACxD,CAAC;CACH,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,wBAAwB,CAAC,GAAG,aAAa,CAe5D"}
@@ -1,3 +1,21 @@
1
+ import { formatMCPUIString } from "./format-string.js";
2
+ const DEGRADED_PROJECTION_LABELS = {
3
+ source: "Source",
4
+ target: "Target",
5
+ label: "Label",
6
+ node: "Node",
7
+ type: "Type",
8
+ lat: "Lat",
9
+ lng: "Lng",
10
+ info: "Info",
11
+ marker: "marker",
12
+ feature: "feature",
13
+ series: "Series {n}"
14
+ };
15
+ const withLabels = (labels) => ({
16
+ ...DEGRADED_PROJECTION_LABELS,
17
+ ...labels
18
+ });
1
19
  const MAX_PROJECTED_ROWS = 200;
2
20
  function cell(value) {
3
21
  if (value == null) return "";
@@ -10,11 +28,12 @@ function cell(value) {
10
28
  }
11
29
  return String(value);
12
30
  }
13
- function graphToDegradedTable(params) {
31
+ function graphToDegradedTable(params, labels) {
32
+ const l = withLabels(labels);
14
33
  const edges = params.edges ?? [];
15
34
  if (edges.length > 0) {
16
35
  return {
17
- columns: ["Source", "Target", "Label"],
36
+ columns: [l.source, l.target, l.label],
18
37
  rows: edges.slice(0, MAX_PROJECTED_ROWS).map((e) => {
19
38
  const label = [e.weight != null ? String(e.weight) : "", e.label ?? ""].filter(Boolean).join(" · ");
20
39
  return [cell(e.source), cell(e.target), label];
@@ -23,7 +42,7 @@ function graphToDegradedTable(params) {
23
42
  }
24
43
  const nodes = params.nodes ?? [];
25
44
  return {
26
- columns: ["Node", "Label"],
45
+ columns: [l.node, l.label],
27
46
  rows: nodes.slice(0, MAX_PROJECTED_ROWS).map((n) => [cell(n.id), cell(n.label ?? n.id)])
28
47
  };
29
48
  }
@@ -35,13 +54,14 @@ function firstLngLat(coords) {
35
54
  }
36
55
  return null;
37
56
  }
38
- function mapToDegradedTable(params) {
57
+ function mapToDegradedTable(params, labels) {
39
58
  var _a, _b, _c, _d;
59
+ const l = withLabels(labels);
40
60
  const rows = [];
41
61
  for (const m of params.markers ?? []) {
42
62
  const lat = Array.isArray(m.position) ? m.position[0] : (_a = m.position) == null ? void 0 : _a.lat;
43
63
  const lng = Array.isArray(m.position) ? m.position[1] : (_b = m.position) == null ? void 0 : _b.lng;
44
- rows.push(["marker", cell(lat), cell(lng), cell(m.tooltip ?? m.popup ?? "")]);
64
+ rows.push([l.marker, cell(lat), cell(lng), cell(m.tooltip ?? m.popup ?? "")]);
45
65
  }
46
66
  const fc = params.geojson;
47
67
  const features = Array.isArray(fc == null ? void 0 : fc.features) ? fc.features : [];
@@ -50,29 +70,33 @@ function mapToDegradedTable(params) {
50
70
  const props = f.properties ?? {};
51
71
  const propSummary = Object.keys(props).slice(0, 3).map((k) => `${k}=${cell(props[k])}`).join(", ");
52
72
  rows.push([
53
- cell(((_d = f.geometry) == null ? void 0 : _d.type) ?? "feature"),
73
+ cell(((_d = f.geometry) == null ? void 0 : _d.type) ?? l.feature),
54
74
  ll ? cell(ll[1]) : "",
55
75
  ll ? cell(ll[0]) : "",
56
76
  propSummary
57
77
  ]);
58
78
  }
59
79
  return {
60
- columns: ["Type", "Lat", "Lng", "Info"],
80
+ columns: [l.type, l.lat, l.lng, l.info],
61
81
  rows: rows.slice(0, MAX_PROJECTED_ROWS)
62
82
  };
63
83
  }
64
- function chartToDegradedTable(params) {
84
+ function chartToDegradedTable(params, labels) {
65
85
  var _a, _b;
86
+ const l = withLabels(labels);
66
87
  const datasets = ((_a = params.data) == null ? void 0 : _a.datasets) ?? [];
67
- const labels = ((_b = params.data) == null ? void 0 : _b.labels) ?? [];
68
- const rowCount = Math.max(labels.length, ...datasets.map((d) => {
88
+ const dataLabels = ((_b = params.data) == null ? void 0 : _b.labels) ?? [];
89
+ const rowCount = Math.max(dataLabels.length, ...datasets.map((d) => {
69
90
  var _a2;
70
91
  return ((_a2 = d.data) == null ? void 0 : _a2.length) ?? 0;
71
92
  }), 0);
72
- const columns = ["", ...datasets.map((d, i) => d.label ?? `Series ${i + 1}`)];
93
+ const columns = [
94
+ "",
95
+ ...datasets.map((d, i) => d.label ?? formatMCPUIString(l.series, { n: i + 1 }))
96
+ ];
73
97
  const rows = [];
74
98
  for (let r = 0; r < Math.min(rowCount, MAX_PROJECTED_ROWS); r++) {
75
- rows.push([cell(labels[r] ?? r + 1), ...datasets.map((d) => {
99
+ rows.push([cell(dataLabels[r] ?? r + 1), ...datasets.map((d) => {
76
100
  var _a2;
77
101
  return cell((_a2 = d.data) == null ? void 0 : _a2[r]);
78
102
  })]);
@@ -80,6 +104,7 @@ function chartToDegradedTable(params) {
80
104
  return { columns, rows };
81
105
  }
82
106
  export {
107
+ DEGRADED_PROJECTION_LABELS,
83
108
  chartToDegradedTable,
84
109
  graphToDegradedTable,
85
110
  mapToDegradedTable
@@ -1 +1 @@
1
- {"version":3,"file":"degraded-projections.js","sources":["../../src/utils/degraded-projections.ts"],"sourcesContent":["/**\n * Degraded-fallback projections (audit 2026-05-30, P2.5).\n *\n * Pure functions that turn a heavy renderer's params into a flat\n * `{ columns, rows }` table for `<DegradedFallback>` — the middle rung of\n * the fallback ladder shown when the native render (G6 / Leaflet / Chart.js)\n * is unavailable or throws. No peer deps, no side effects, fully testable.\n *\n * These are best-effort views: they surface the underlying data so the user\n * isn't left with a blank space, not faithful reproductions of the chart/\n * map/graph.\n */\n\nexport interface DegradedTable {\n columns: string[];\n rows: Array<Array<string | number>>;\n}\n\nconst MAX_PROJECTED_ROWS = 200;\n\n/** Compact a value to a single table cell string. */\nfunction cell(value: unknown): string {\n if (value == null) return '';\n if (typeof value === 'object') {\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n }\n return String(value);\n}\n\n// ─── Graph ───────────────────────────────────────────────────────────────\n\n/**\n * Graph → edge table when edges exist (Source / Target / Label), else a\n * node list (Node / Label). The graph renderer can therefore degrade to a\n * readable relationship listing instead of a blank canvas.\n */\nexport function graphToDegradedTable(params: {\n nodes?: Array<{ id: string; label?: string }>;\n edges?: Array<{ source: string; target: string; label?: string; weight?: number }>;\n}): DegradedTable {\n const edges = params.edges ?? [];\n if (edges.length > 0) {\n return {\n columns: ['Source', 'Target', 'Label'],\n rows: edges.slice(0, MAX_PROJECTED_ROWS).map((e) => {\n const label = [e.weight != null ? String(e.weight) : '', e.label ?? '']\n .filter(Boolean)\n .join(' · ');\n return [cell(e.source), cell(e.target), label];\n }),\n };\n }\n const nodes = params.nodes ?? [];\n return {\n columns: ['Node', 'Label'],\n rows: nodes.slice(0, MAX_PROJECTED_ROWS).map((n) => [cell(n.id), cell(n.label ?? n.id)]),\n };\n}\n\n// ─── Map ───────────────────────────────────────────────────────────────────\n\ninterface GeoJSONLikeFeature {\n geometry?: { type?: string; coordinates?: unknown } | null;\n properties?: Record<string, unknown> | null;\n}\n\n/** Pull a representative `[lng, lat]` pair out of a geometry's coordinates. */\nfunction firstLngLat(coords: unknown): [number, number] | null {\n let c: unknown = coords;\n // Descend nested arrays until we reach a [number, number, ...] position.\n while (Array.isArray(c) && Array.isArray(c[0])) c = c[0];\n if (Array.isArray(c) && typeof c[0] === 'number' && typeof c[1] === 'number') {\n return [c[0], c[1]];\n }\n return null;\n}\n\n/**\n * Map → a coordinate table. Markers become Lat/Lng/Label rows; GeoJSON\n * features become Type / Lat / Lng (+ a compact properties summary). So a\n * map that can't paint still lists where its points are.\n */\nexport function mapToDegradedTable(params: {\n markers?: Array<{\n position: [number, number] | { lat: number; lng: number };\n tooltip?: string;\n popup?: string;\n }>;\n geojson?: unknown;\n}): DegradedTable {\n const rows: Array<Array<string | number>> = [];\n\n for (const m of params.markers ?? []) {\n const lat = Array.isArray(m.position) ? m.position[0] : m.position?.lat;\n const lng = Array.isArray(m.position) ? m.position[1] : m.position?.lng;\n rows.push(['marker', cell(lat), cell(lng), cell(m.tooltip ?? m.popup ?? '')]);\n }\n\n const fc = params.geojson as { features?: GeoJSONLikeFeature[] } | undefined;\n const features = Array.isArray(fc?.features) ? fc!.features : [];\n for (const f of features) {\n const ll = firstLngLat(f.geometry?.coordinates);\n const props = f.properties ?? {};\n const propSummary = Object.keys(props)\n .slice(0, 3)\n .map((k) => `${k}=${cell(props[k])}`)\n .join(', ');\n rows.push([\n cell(f.geometry?.type ?? 'feature'),\n ll ? cell(ll[1]) : '',\n ll ? cell(ll[0]) : '',\n propSummary,\n ]);\n }\n\n return {\n columns: ['Type', 'Lat', 'Lng', 'Info'],\n rows: rows.slice(0, MAX_PROJECTED_ROWS),\n };\n}\n\n// ─── Chart ───────────────────────────────────────────────────────────────\n\n/**\n * Chart → a series table: one row per label, one column per dataset. So a\n * chart that can't draw still shows its numbers. Point/object data (scatter,\n * bubble, time series) is stringified per cell.\n */\nexport function chartToDegradedTable(params: {\n data?: {\n labels?: Array<string | number>;\n datasets?: Array<{ label?: string; data?: unknown[] }>;\n };\n}): DegradedTable {\n const datasets = params.data?.datasets ?? [];\n const labels = params.data?.labels ?? [];\n const rowCount = Math.max(labels.length, ...datasets.map((d) => d.data?.length ?? 0), 0);\n\n const columns = ['', ...datasets.map((d, i) => d.label ?? `Series ${i + 1}`)];\n const rows: Array<Array<string | number>> = [];\n for (let r = 0; r < Math.min(rowCount, MAX_PROJECTED_ROWS); r++) {\n rows.push([cell(labels[r] ?? r + 1), ...datasets.map((d) => cell(d.data?.[r]))]);\n }\n return { columns, rows };\n}\n"],"names":["_a"],"mappings":"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"}
1
+ {"version":3,"file":"degraded-projections.js","sources":["../../src/utils/degraded-projections.ts"],"sourcesContent":["/**\n * Degraded-fallback projections (audit 2026-05-30, P2.5).\n *\n * Pure functions that turn a heavy renderer's params into a flat\n * `{ columns, rows }` table for `<DegradedFallback>` — the middle rung of\n * the fallback ladder shown when the native render (G6 / Leaflet / Chart.js)\n * is unavailable or throws. No peer deps, no side effects, fully testable.\n *\n * These are best-effort views: they surface the underlying data so the user\n * isn't left with a blank space, not faithful reproductions of the chart/\n * map/graph.\n */\n\nimport { formatMCPUIString } from './format-string';\n\n/**\n * Column headers and series names of the degraded tables.\n *\n * The projections are pure helpers with no access to `MCPUIStrings`, so the\n * wording is injected: each function takes an optional trailing `labels`\n * partial, and the renderers feed it from `useMCPUIStrings()`. Left out, the\n * English defaults below apply — the pre-v6.20.0 behaviour.\n *\n * @since v6.20.0\n */\nexport interface DegradedProjectionLabels {\n /** Graph edge table — source column. */\n source: string;\n /** Graph edge table — target column. */\n target: string;\n /** Graph edge / node table — label column. */\n label: string;\n /** Graph node table — node id column. */\n node: string;\n /** Map table — feature type column. */\n type: string;\n /** Map table — latitude column. */\n lat: string;\n /** Map table — longitude column. */\n lng: string;\n /** Map table — property summary column. */\n info: string;\n /** Map table — `Type` cell of a marker row (v6.20.0, 6th pass). */\n marker: string;\n /** Map table — `Type` cell of a GeoJSON feature without a geometry type (v6.20.0). */\n feature: string;\n /** Chart table — fallback dataset name. Template — `{n}`. */\n series: string;\n}\n\n/** English defaults for {@link DegradedProjectionLabels}. */\nexport const DEGRADED_PROJECTION_LABELS: DegradedProjectionLabels = {\n source: 'Source',\n target: 'Target',\n label: 'Label',\n node: 'Node',\n type: 'Type',\n lat: 'Lat',\n lng: 'Lng',\n info: 'Info',\n marker: 'marker',\n feature: 'feature',\n series: 'Series {n}',\n};\n\nconst withLabels = (labels?: Partial<DegradedProjectionLabels>): DegradedProjectionLabels => ({\n ...DEGRADED_PROJECTION_LABELS,\n ...labels,\n});\n\nexport interface DegradedTable {\n columns: string[];\n rows: Array<Array<string | number>>;\n}\n\nconst MAX_PROJECTED_ROWS = 200;\n\n/** Compact a value to a single table cell string. */\nfunction cell(value: unknown): string {\n if (value == null) return '';\n if (typeof value === 'object') {\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n }\n return String(value);\n}\n\n// ─── Graph ───────────────────────────────────────────────────────────────\n\n/**\n * Graph → edge table when edges exist (Source / Target / Label), else a\n * node list (Node / Label). The graph renderer can therefore degrade to a\n * readable relationship listing instead of a blank canvas.\n */\nexport function graphToDegradedTable(params: {\n nodes?: Array<{ id: string; label?: string }>;\n edges?: Array<{ source: string; target: string; label?: string; weight?: number }>;\n}, labels?: Partial<DegradedProjectionLabels>): DegradedTable {\n const l = withLabels(labels);\n const edges = params.edges ?? [];\n if (edges.length > 0) {\n return {\n columns: [l.source, l.target, l.label],\n rows: edges.slice(0, MAX_PROJECTED_ROWS).map((e) => {\n const label = [e.weight != null ? String(e.weight) : '', e.label ?? '']\n .filter(Boolean)\n .join(' · ');\n return [cell(e.source), cell(e.target), label];\n }),\n };\n }\n const nodes = params.nodes ?? [];\n return {\n columns: [l.node, l.label],\n rows: nodes.slice(0, MAX_PROJECTED_ROWS).map((n) => [cell(n.id), cell(n.label ?? n.id)]),\n };\n}\n\n// ─── Map ───────────────────────────────────────────────────────────────────\n\ninterface GeoJSONLikeFeature {\n geometry?: { type?: string; coordinates?: unknown } | null;\n properties?: Record<string, unknown> | null;\n}\n\n/** Pull a representative `[lng, lat]` pair out of a geometry's coordinates. */\nfunction firstLngLat(coords: unknown): [number, number] | null {\n let c: unknown = coords;\n // Descend nested arrays until we reach a [number, number, ...] position.\n while (Array.isArray(c) && Array.isArray(c[0])) c = c[0];\n if (Array.isArray(c) && typeof c[0] === 'number' && typeof c[1] === 'number') {\n return [c[0], c[1]];\n }\n return null;\n}\n\n/**\n * Map → a coordinate table. Markers become Lat/Lng/Label rows; GeoJSON\n * features become Type / Lat / Lng (+ a compact properties summary). So a\n * map that can't paint still lists where its points are.\n */\nexport function mapToDegradedTable(params: {\n markers?: Array<{\n position: [number, number] | { lat: number; lng: number };\n tooltip?: string;\n popup?: string;\n }>;\n geojson?: unknown;\n}, labels?: Partial<DegradedProjectionLabels>): DegradedTable {\n const l = withLabels(labels);\n const rows: Array<Array<string | number>> = [];\n\n for (const m of params.markers ?? []) {\n const lat = Array.isArray(m.position) ? m.position[0] : m.position?.lat;\n const lng = Array.isArray(m.position) ? m.position[1] : m.position?.lng;\n rows.push([l.marker, cell(lat), cell(lng), cell(m.tooltip ?? m.popup ?? '')]);\n }\n\n const fc = params.geojson as { features?: GeoJSONLikeFeature[] } | undefined;\n const features = Array.isArray(fc?.features) ? fc!.features : [];\n for (const f of features) {\n const ll = firstLngLat(f.geometry?.coordinates);\n const props = f.properties ?? {};\n const propSummary = Object.keys(props)\n .slice(0, 3)\n .map((k) => `${k}=${cell(props[k])}`)\n .join(', ');\n rows.push([\n cell(f.geometry?.type ?? l.feature),\n ll ? cell(ll[1]) : '',\n ll ? cell(ll[0]) : '',\n propSummary,\n ]);\n }\n\n return {\n columns: [l.type, l.lat, l.lng, l.info],\n rows: rows.slice(0, MAX_PROJECTED_ROWS),\n };\n}\n\n// ─── Chart ───────────────────────────────────────────────────────────────\n\n/**\n * Chart → a series table: one row per label, one column per dataset. So a\n * chart that can't draw still shows its numbers. Point/object data (scatter,\n * bubble, time series) is stringified per cell.\n */\nexport function chartToDegradedTable(params: {\n data?: {\n labels?: Array<string | number>;\n datasets?: Array<{ label?: string; data?: unknown[] }>;\n };\n}, labels?: Partial<DegradedProjectionLabels>): DegradedTable {\n const l = withLabels(labels);\n const datasets = params.data?.datasets ?? [];\n const dataLabels = params.data?.labels ?? [];\n const rowCount = Math.max(dataLabels.length, ...datasets.map((d) => d.data?.length ?? 0), 0);\n\n const columns = [\n '',\n ...datasets.map((d, i) => d.label ?? formatMCPUIString(l.series, { n: i + 1 })),\n ];\n const rows: Array<Array<string | number>> = [];\n for (let r = 0; r < Math.min(rowCount, MAX_PROJECTED_ROWS); r++) {\n rows.push([cell(dataLabels[r] ?? r + 1), ...datasets.map((d) => cell(d.data?.[r]))]);\n }\n return { columns, rows };\n}\n"],"names":["_a"],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ function formatMCPUIString(template, vars) {
4
+ return template.replace(
5
+ /\{(\w+)\}/g,
6
+ (match, name) => Object.prototype.hasOwnProperty.call(vars, name) ? String(vars[name]) : match
7
+ );
8
+ }
9
+ exports.formatMCPUIString = formatMCPUIString;
10
+ //# sourceMappingURL=format-string.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-string.cjs","sources":["../../src/utils/format-string.ts"],"sourcesContent":["/**\n * `formatMCPUIString` — the chrome-string template helper, runtime-free.\n *\n * @since v6.20.0 (extracted from `MCPUIStringsContext` so the pure adapters\n * under `src/adapters` can interpolate their own message templates without\n * importing `solid-js`). `MCPUIStringsContext` re-exports it, so every\n * existing import path — including the root barrel — keeps working.\n *\n * This module imports nothing. It must stay that way: `src/adapters/*` is\n * published as a dedicated subpath that never pulls in the renderer.\n */\n\n/**\n * Substitutes `{name}` placeholders in a chrome string template.\n *\n * Only the keys present in `vars` are replaced; an unknown placeholder is\n * left verbatim so a mistyped or locale-specific template degrades to\n * visible text rather than to `undefined`.\n *\n * @example\n * ```ts\n * formatMCPUIString('Sort by {column}', { column: 'Revenue' }) // 'Sort by Revenue'\n * formatMCPUIString('Export CSV ({count} rows)', { count: 42 }) // 'Export CSV (42 rows)'\n * ```\n */\nexport function formatMCPUIString(\n template: string,\n vars: Record<string, string | number>\n): string {\n return template.replace(/\\{(\\w+)\\}/g, (match, name: string) =>\n Object.prototype.hasOwnProperty.call(vars, name) ? String(vars[name]) : match\n )\n}\n"],"names":[],"mappings":";;AAyBO,SAAS,kBACd,UACA,MACQ;AACR,SAAO,SAAS;AAAA,IAAQ;AAAA,IAAc,CAAC,OAAO,SAC5C,OAAO,UAAU,eAAe,KAAK,MAAM,IAAI,IAAI,OAAO,KAAK,IAAI,CAAC,IAAI;AAAA,EAAA;AAE5E;;"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * `formatMCPUIString` — the chrome-string template helper, runtime-free.
3
+ *
4
+ * @since v6.20.0 (extracted from `MCPUIStringsContext` so the pure adapters
5
+ * under `src/adapters` can interpolate their own message templates without
6
+ * importing `solid-js`). `MCPUIStringsContext` re-exports it, so every
7
+ * existing import path — including the root barrel — keeps working.
8
+ *
9
+ * This module imports nothing. It must stay that way: `src/adapters/*` is
10
+ * published as a dedicated subpath that never pulls in the renderer.
11
+ */
12
+ /**
13
+ * Substitutes `{name}` placeholders in a chrome string template.
14
+ *
15
+ * Only the keys present in `vars` are replaced; an unknown placeholder is
16
+ * left verbatim so a mistyped or locale-specific template degrades to
17
+ * visible text rather than to `undefined`.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * formatMCPUIString('Sort by {column}', { column: 'Revenue' }) // 'Sort by Revenue'
22
+ * formatMCPUIString('Export CSV ({count} rows)', { count: 42 }) // 'Export CSV (42 rows)'
23
+ * ```
24
+ */
25
+ export declare function formatMCPUIString(template: string, vars: Record<string, string | number>): string;
26
+ //# sourceMappingURL=format-string.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-string.d.ts","sourceRoot":"","sources":["../../src/utils/format-string.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GACpC,MAAM,CAIR"}
@@ -0,0 +1,10 @@
1
+ function formatMCPUIString(template, vars) {
2
+ return template.replace(
3
+ /\{(\w+)\}/g,
4
+ (match, name) => Object.prototype.hasOwnProperty.call(vars, name) ? String(vars[name]) : match
5
+ );
6
+ }
7
+ export {
8
+ formatMCPUIString
9
+ };
10
+ //# sourceMappingURL=format-string.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-string.js","sources":["../../src/utils/format-string.ts"],"sourcesContent":["/**\n * `formatMCPUIString` — the chrome-string template helper, runtime-free.\n *\n * @since v6.20.0 (extracted from `MCPUIStringsContext` so the pure adapters\n * under `src/adapters` can interpolate their own message templates without\n * importing `solid-js`). `MCPUIStringsContext` re-exports it, so every\n * existing import path — including the root barrel — keeps working.\n *\n * This module imports nothing. It must stay that way: `src/adapters/*` is\n * published as a dedicated subpath that never pulls in the renderer.\n */\n\n/**\n * Substitutes `{name}` placeholders in a chrome string template.\n *\n * Only the keys present in `vars` are replaced; an unknown placeholder is\n * left verbatim so a mistyped or locale-specific template degrades to\n * visible text rather than to `undefined`.\n *\n * @example\n * ```ts\n * formatMCPUIString('Sort by {column}', { column: 'Revenue' }) // 'Sort by Revenue'\n * formatMCPUIString('Export CSV ({count} rows)', { count: 42 }) // 'Export CSV (42 rows)'\n * ```\n */\nexport function formatMCPUIString(\n template: string,\n vars: Record<string, string | number>\n): string {\n return template.replace(/\\{(\\w+)\\}/g, (match, name: string) =>\n Object.prototype.hasOwnProperty.call(vars, name) ? String(vars[name]) : match\n )\n}\n"],"names":[],"mappings":"AAyBO,SAAS,kBACd,UACA,MACQ;AACR,SAAO,SAAS;AAAA,IAAQ;AAAA,IAAc,CAAC,OAAO,SAC5C,OAAO,UAAU,eAAe,KAAK,MAAM,IAAI,IAAI,OAAO,KAAK,IAAI,CAAC,IAAI;AAAA,EAAA;AAE5E;"}
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const solidJs = require("solid-js");
4
+ const validation = require("../services/validation.cjs");
5
+ function shouldSetCredentialless(url, config, options) {
6
+ const mode = config.iframeCredentialless;
7
+ if (mode === "always") return true;
8
+ if (mode === "never") return false;
9
+ if (!options.sandboxedWithoutSameOrigin) return false;
10
+ return !validation.isTrustedIframeDomain(url, {
11
+ customTrustedDomains: config.customTrustedIframeDomains
12
+ });
13
+ }
14
+ function createCrossOriginIsolated() {
15
+ const [isolated, setIsolated] = solidJs.createSignal(false);
16
+ solidJs.onMount(() => {
17
+ setIsolated(typeof window !== "undefined" && window.crossOriginIsolated === true);
18
+ });
19
+ return isolated;
20
+ }
21
+ function shouldShowIframeFallbackLink(config, crossOriginIsolated) {
22
+ const mode = config.iframeFallbackLink;
23
+ if (mode === "always") return true;
24
+ if (mode === "never") return false;
25
+ return crossOriginIsolated;
26
+ }
27
+ exports.createCrossOriginIsolated = createCrossOriginIsolated;
28
+ exports.shouldSetCredentialless = shouldSetCredentialless;
29
+ exports.shouldShowIframeFallbackLink = shouldShowIframeFallbackLink;
30
+ //# sourceMappingURL=iframe-coep.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iframe-coep.cjs","sources":["../../src/utils/iframe-coep.ts"],"sourcesContent":["/**\n * COEP helpers for the two iframes the library renders\n * (`IframeRenderer` in `UIResourceRenderer.tsx`, and the YouTube / Vimeo\n * embed in `VideoRenderer.tsx`).\n *\n * @since v6.21.0\n *\n * A host that serves `Cross-Origin-Embedder-Policy: credentialless` makes the\n * browser refuse any cross-origin iframe whose own document sends no COEP\n * header. The HTML attribute `credentialless` on the `<iframe>` lifts that,\n * at the price of the embedded document losing access to the cookies and\n * storage of its own origin — see `MCPUIConfigContext` for the policy.\n */\n\nimport { createSignal, onMount, type Accessor } from 'solid-js'\nimport { isTrustedIframeDomain } from '../services/validation'\nimport type { MCPUIConfig } from '../context/MCPUIConfigContext'\n\n/**\n * Does this iframe get the boolean `credentialless` attribute?\n *\n * `'auto'` (the default) says yes only when the embed has nothing to lose:\n * the host is not trusted AND the iframe already runs without cookies because\n * its `sandbox` has no `allow-same-origin` (`sandboxedWithoutSameOrigin`).\n * The video embed carries no sandbox, so in `'auto'` it keeps its provider\n * cookies and a COEP host must opt in with `'always'`.\n *\n * An unparsable URL is not trusted, so it gets the attribute.\n */\nexport function shouldSetCredentialless(\n url: string,\n config: MCPUIConfig,\n options: { sandboxedWithoutSameOrigin: boolean }\n): boolean {\n const mode = config.iframeCredentialless\n if (mode === 'always') return true\n if (mode === 'never') return false\n if (!options.sandboxedWithoutSameOrigin) return false\n return !isTrustedIframeDomain(url, {\n customTrustedDomains: config.customTrustedIframeDomains,\n })\n}\n\n/**\n * `window.crossOriginIsolated`, read **after mount** into a signal.\n *\n * Reading it during render would make the server emit markup the client\n * cannot reproduce; the signal starts at `false` (the SSR value) and flips\n * once mounted, so hydration always matches.\n */\nexport function createCrossOriginIsolated(): Accessor<boolean> {\n const [isolated, setIsolated] = createSignal(false)\n onMount(() => {\n setIsolated(typeof window !== 'undefined' && window.crossOriginIsolated === true)\n })\n return isolated\n}\n\n/**\n * Does the \"open in a new tab\" link show under an embed?\n *\n * `'auto'` shows it only on a cross-origin-isolated page — exactly where COEP\n * can block the frame, and where the blocking is silent (a refused\n * cross-origin document fires no `error` event the parent can observe).\n */\nexport function shouldShowIframeFallbackLink(\n config: MCPUIConfig,\n crossOriginIsolated: boolean\n): boolean {\n const mode = config.iframeFallbackLink\n if (mode === 'always') return true\n if (mode === 'never') return false\n return crossOriginIsolated\n}\n"],"names":["isTrustedIframeDomain","createSignal","onMount"],"mappings":";;;;AA6BO,SAAS,wBACd,KACA,QACA,SACS;AACT,QAAM,OAAO,OAAO;AACpB,MAAI,SAAS,SAAU,QAAO;AAC9B,MAAI,SAAS,QAAS,QAAO;AAC7B,MAAI,CAAC,QAAQ,2BAA4B,QAAO;AAChD,SAAO,CAACA,WAAAA,sBAAsB,KAAK;AAAA,IACjC,sBAAsB,OAAO;AAAA,EAAA,CAC9B;AACH;AASO,SAAS,4BAA+C;AAC7D,QAAM,CAAC,UAAU,WAAW,IAAIC,QAAAA,aAAa,KAAK;AAClDC,UAAAA,QAAQ,MAAM;AACZ,gBAAY,OAAO,WAAW,eAAe,OAAO,wBAAwB,IAAI;AAAA,EAClF,CAAC;AACD,SAAO;AACT;AASO,SAAS,6BACd,QACA,qBACS;AACT,QAAM,OAAO,OAAO;AACpB,MAAI,SAAS,SAAU,QAAO;AAC9B,MAAI,SAAS,QAAS,QAAO;AAC7B,SAAO;AACT;;;;"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * COEP helpers for the two iframes the library renders
3
+ * (`IframeRenderer` in `UIResourceRenderer.tsx`, and the YouTube / Vimeo
4
+ * embed in `VideoRenderer.tsx`).
5
+ *
6
+ * @since v6.21.0
7
+ *
8
+ * A host that serves `Cross-Origin-Embedder-Policy: credentialless` makes the
9
+ * browser refuse any cross-origin iframe whose own document sends no COEP
10
+ * header. The HTML attribute `credentialless` on the `<iframe>` lifts that,
11
+ * at the price of the embedded document losing access to the cookies and
12
+ * storage of its own origin — see `MCPUIConfigContext` for the policy.
13
+ */
14
+ import { type Accessor } from 'solid-js';
15
+ import type { MCPUIConfig } from '../context/MCPUIConfigContext';
16
+ /**
17
+ * Does this iframe get the boolean `credentialless` attribute?
18
+ *
19
+ * `'auto'` (the default) says yes only when the embed has nothing to lose:
20
+ * the host is not trusted AND the iframe already runs without cookies because
21
+ * its `sandbox` has no `allow-same-origin` (`sandboxedWithoutSameOrigin`).
22
+ * The video embed carries no sandbox, so in `'auto'` it keeps its provider
23
+ * cookies and a COEP host must opt in with `'always'`.
24
+ *
25
+ * An unparsable URL is not trusted, so it gets the attribute.
26
+ */
27
+ export declare function shouldSetCredentialless(url: string, config: MCPUIConfig, options: {
28
+ sandboxedWithoutSameOrigin: boolean;
29
+ }): boolean;
30
+ /**
31
+ * `window.crossOriginIsolated`, read **after mount** into a signal.
32
+ *
33
+ * Reading it during render would make the server emit markup the client
34
+ * cannot reproduce; the signal starts at `false` (the SSR value) and flips
35
+ * once mounted, so hydration always matches.
36
+ */
37
+ export declare function createCrossOriginIsolated(): Accessor<boolean>;
38
+ /**
39
+ * Does the "open in a new tab" link show under an embed?
40
+ *
41
+ * `'auto'` shows it only on a cross-origin-isolated page — exactly where COEP
42
+ * can block the frame, and where the blocking is silent (a refused
43
+ * cross-origin document fires no `error` event the parent can observe).
44
+ */
45
+ export declare function shouldShowIframeFallbackLink(config: MCPUIConfig, crossOriginIsolated: boolean): boolean;
46
+ //# sourceMappingURL=iframe-coep.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iframe-coep.d.ts","sourceRoot":"","sources":["../../src/utils/iframe-coep.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAyB,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAA;AAE/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAEhE;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE;IAAE,0BAA0B,EAAE,OAAO,CAAA;CAAE,GAC/C,OAAO,CAQT;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,IAAI,QAAQ,CAAC,OAAO,CAAC,CAM7D;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,WAAW,EACnB,mBAAmB,EAAE,OAAO,GAC3B,OAAO,CAKT"}
@@ -0,0 +1,30 @@
1
+ import { createSignal, onMount } from "solid-js";
2
+ import { isTrustedIframeDomain } from "../services/validation.js";
3
+ function shouldSetCredentialless(url, config, options) {
4
+ const mode = config.iframeCredentialless;
5
+ if (mode === "always") return true;
6
+ if (mode === "never") return false;
7
+ if (!options.sandboxedWithoutSameOrigin) return false;
8
+ return !isTrustedIframeDomain(url, {
9
+ customTrustedDomains: config.customTrustedIframeDomains
10
+ });
11
+ }
12
+ function createCrossOriginIsolated() {
13
+ const [isolated, setIsolated] = createSignal(false);
14
+ onMount(() => {
15
+ setIsolated(typeof window !== "undefined" && window.crossOriginIsolated === true);
16
+ });
17
+ return isolated;
18
+ }
19
+ function shouldShowIframeFallbackLink(config, crossOriginIsolated) {
20
+ const mode = config.iframeFallbackLink;
21
+ if (mode === "always") return true;
22
+ if (mode === "never") return false;
23
+ return crossOriginIsolated;
24
+ }
25
+ export {
26
+ createCrossOriginIsolated,
27
+ shouldSetCredentialless,
28
+ shouldShowIframeFallbackLink
29
+ };
30
+ //# sourceMappingURL=iframe-coep.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iframe-coep.js","sources":["../../src/utils/iframe-coep.ts"],"sourcesContent":["/**\n * COEP helpers for the two iframes the library renders\n * (`IframeRenderer` in `UIResourceRenderer.tsx`, and the YouTube / Vimeo\n * embed in `VideoRenderer.tsx`).\n *\n * @since v6.21.0\n *\n * A host that serves `Cross-Origin-Embedder-Policy: credentialless` makes the\n * browser refuse any cross-origin iframe whose own document sends no COEP\n * header. The HTML attribute `credentialless` on the `<iframe>` lifts that,\n * at the price of the embedded document losing access to the cookies and\n * storage of its own origin — see `MCPUIConfigContext` for the policy.\n */\n\nimport { createSignal, onMount, type Accessor } from 'solid-js'\nimport { isTrustedIframeDomain } from '../services/validation'\nimport type { MCPUIConfig } from '../context/MCPUIConfigContext'\n\n/**\n * Does this iframe get the boolean `credentialless` attribute?\n *\n * `'auto'` (the default) says yes only when the embed has nothing to lose:\n * the host is not trusted AND the iframe already runs without cookies because\n * its `sandbox` has no `allow-same-origin` (`sandboxedWithoutSameOrigin`).\n * The video embed carries no sandbox, so in `'auto'` it keeps its provider\n * cookies and a COEP host must opt in with `'always'`.\n *\n * An unparsable URL is not trusted, so it gets the attribute.\n */\nexport function shouldSetCredentialless(\n url: string,\n config: MCPUIConfig,\n options: { sandboxedWithoutSameOrigin: boolean }\n): boolean {\n const mode = config.iframeCredentialless\n if (mode === 'always') return true\n if (mode === 'never') return false\n if (!options.sandboxedWithoutSameOrigin) return false\n return !isTrustedIframeDomain(url, {\n customTrustedDomains: config.customTrustedIframeDomains,\n })\n}\n\n/**\n * `window.crossOriginIsolated`, read **after mount** into a signal.\n *\n * Reading it during render would make the server emit markup the client\n * cannot reproduce; the signal starts at `false` (the SSR value) and flips\n * once mounted, so hydration always matches.\n */\nexport function createCrossOriginIsolated(): Accessor<boolean> {\n const [isolated, setIsolated] = createSignal(false)\n onMount(() => {\n setIsolated(typeof window !== 'undefined' && window.crossOriginIsolated === true)\n })\n return isolated\n}\n\n/**\n * Does the \"open in a new tab\" link show under an embed?\n *\n * `'auto'` shows it only on a cross-origin-isolated page — exactly where COEP\n * can block the frame, and where the blocking is silent (a refused\n * cross-origin document fires no `error` event the parent can observe).\n */\nexport function shouldShowIframeFallbackLink(\n config: MCPUIConfig,\n crossOriginIsolated: boolean\n): boolean {\n const mode = config.iframeFallbackLink\n if (mode === 'always') return true\n if (mode === 'never') return false\n return crossOriginIsolated\n}\n"],"names":[],"mappings":";;AA6BO,SAAS,wBACd,KACA,QACA,SACS;AACT,QAAM,OAAO,OAAO;AACpB,MAAI,SAAS,SAAU,QAAO;AAC9B,MAAI,SAAS,QAAS,QAAO;AAC7B,MAAI,CAAC,QAAQ,2BAA4B,QAAO;AAChD,SAAO,CAAC,sBAAsB,KAAK;AAAA,IACjC,sBAAsB,OAAO;AAAA,EAAA,CAC9B;AACH;AASO,SAAS,4BAA+C;AAC7D,QAAM,CAAC,UAAU,WAAW,IAAI,aAAa,KAAK;AAClD,UAAQ,MAAM;AACZ,gBAAY,OAAO,WAAW,eAAe,OAAO,wBAAwB,IAAI;AAAA,EAClF,CAAC;AACD,SAAO;AACT;AASO,SAAS,6BACd,QACA,qBACS;AACT,QAAM,OAAO,OAAO;AACpB,MAAI,SAAS,SAAU,QAAO;AAC9B,MAAI,SAAS,QAAS,QAAO;AAC7B,SAAO;AACT;"}
@@ -2,9 +2,14 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const validation = require("./services/validation.cjs");
4
4
  exports.DEFAULT_RESOURCE_LIMITS = validation.DEFAULT_RESOURCE_LIMITS;
5
+ exports.DEFAULT_VALIDATION_MESSAGES = validation.DEFAULT_VALIDATION_MESSAGES;
6
+ exports.getIframeSandbox = validation.getIframeSandbox;
7
+ exports.isTrustedIframeDomain = validation.isTrustedIframeDomain;
5
8
  exports.sanitizeString = validation.sanitizeString;
6
9
  exports.validateChartComponent = validation.validateChartComponent;
7
10
  exports.validateComponent = validation.validateComponent;
11
+ exports.validateFieldValue = validation.validateFieldValue;
12
+ exports.validateFormData = validation.validateFormData;
8
13
  exports.validateGridPosition = validation.validateGridPosition;
9
14
  exports.validateIframeDomain = validation.validateIframeDomain;
10
15
  exports.validateLayout = validation.validateLayout;
@@ -1 +1 @@
1
- {"version":3,"file":"validation.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;"}
1
+ {"version":3,"file":"validation.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;"}
@@ -9,6 +9,7 @@
9
9
  * import { validateLayout } from '@seed-ship/mcp-ui-solid/validation'
10
10
  * ```
11
11
  */
12
- export { validateComponent, validateLayout, validateGridPosition, validateChartComponent, validateTableComponent, validatePayloadSize, validateIframeDomain, sanitizeString, DEFAULT_RESOURCE_LIMITS, } from './services/validation';
12
+ export { validateComponent, validateLayout, validateGridPosition, validateChartComponent, validateTableComponent, validatePayloadSize, validateIframeDomain, getIframeSandbox, isTrustedIframeDomain, sanitizeString, DEFAULT_RESOURCE_LIMITS, validateFieldValue, validateFormData, DEFAULT_VALIDATION_MESSAGES, } from './services/validation';
13
+ export type { FormValidationMessages } from './services/validation';
13
14
  export type { UIComponent, UILayout, GridPosition, ComponentType, ChartComponentParams, TableComponentParams, MetricComponentParams, TextComponentParams, ValidationResult, ResourceLimits, } from './types';
14
15
  //# sourceMappingURL=validation.d.ts.map
@@ -9,6 +9,7 @@
9
9
  * import { validateLayout } from '@seed-ship/mcp-ui-solid/validation'
10
10
  * ```
11
11
  */
12
- export { validateComponent, validateLayout, validateGridPosition, validateChartComponent, validateTableComponent, validatePayloadSize, validateIframeDomain, sanitizeString, DEFAULT_RESOURCE_LIMITS, } from './services/validation';
12
+ export { validateComponent, validateLayout, validateGridPosition, validateChartComponent, validateTableComponent, validatePayloadSize, validateIframeDomain, getIframeSandbox, isTrustedIframeDomain, sanitizeString, DEFAULT_RESOURCE_LIMITS, validateFieldValue, validateFormData, DEFAULT_VALIDATION_MESSAGES, } from './services/validation';
13
+ export type { FormValidationMessages } from './services/validation';
13
14
  export type { UIComponent, UILayout, GridPosition, ComponentType, ChartComponentParams, TableComponentParams, MetricComponentParams, TextComponentParams, ValidationResult, ResourceLimits, } from './types';
14
15
  //# sourceMappingURL=validation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,oBAAoB,EACpB,cAAc,EACd,uBAAuB,GACxB,MAAM,uBAAuB,CAAA;AAG9B,YAAY,EACV,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,GACf,MAAM,SAAS,CAAA"}
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAGhB,qBAAqB,EACrB,cAAc,EACd,uBAAuB,EAEvB,kBAAkB,EAClB,gBAAgB,EAChB,2BAA2B,GAC5B,MAAM,uBAAuB,CAAA;AAC9B,YAAY,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAGnE,YAAY,EACV,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,GACf,MAAM,SAAS,CAAA"}
@@ -1,9 +1,14 @@
1
- import { DEFAULT_RESOURCE_LIMITS, sanitizeString, validateChartComponent, validateComponent, validateGridPosition, validateIframeDomain, validateLayout, validatePayloadSize, validateTableComponent } from "./services/validation.js";
1
+ import { DEFAULT_RESOURCE_LIMITS, DEFAULT_VALIDATION_MESSAGES, getIframeSandbox, isTrustedIframeDomain, sanitizeString, validateChartComponent, validateComponent, validateFieldValue, validateFormData, validateGridPosition, validateIframeDomain, validateLayout, validatePayloadSize, validateTableComponent } from "./services/validation.js";
2
2
  export {
3
3
  DEFAULT_RESOURCE_LIMITS,
4
+ DEFAULT_VALIDATION_MESSAGES,
5
+ getIframeSandbox,
6
+ isTrustedIframeDomain,
4
7
  sanitizeString,
5
8
  validateChartComponent,
6
9
  validateComponent,
10
+ validateFieldValue,
11
+ validateFormData,
7
12
  validateGridPosition,
8
13
  validateIframeDomain,
9
14
  validateLayout,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seed-ship/mcp-ui-solid",
3
- "version": "6.19.1",
3
+ "version": "6.21.0",
4
4
  "description": "SolidJS components for rendering MCP-generated UI resources",
5
5
  "type": "module",
6
6
  "files": [
@@ -29,6 +29,7 @@ import {
29
29
  type ConnectorAction,
30
30
  } from '@seed-ship/mcp-ui-spec'
31
31
  import { z } from 'zod'
32
+ import { formatMCPUIString } from '../utils/format-string'
32
33
 
33
34
  // ─────────────────────────────────────────────────────────────
34
35
  // connectorActionsToActionGroup
@@ -74,11 +75,57 @@ export function connectorActionsToActionGroup(
74
75
  // connectorResultToUILayout
75
76
  // ─────────────────────────────────────────────────────────────
76
77
 
78
+ /**
79
+ * The visible wording of the two degraded states (R2).
80
+ *
81
+ * These paragraphs are rendered as `text` components, so unlike the payload
82
+ * they are the LIBRARY's own chrome. They cannot go through
83
+ * `MCPUIStrings` — the adapters are runtime-free and never import
84
+ * `solid-js` — so a host localizes them through
85
+ * `ConnectorResultToUILayoutOptions.messages` instead.
86
+ *
87
+ * Every field is a template resolved with `formatMCPUIString`.
88
+ *
89
+ * @since v6.20.0 — the defaults used to be hardcoded French.
90
+ */
91
+ export interface ConnectorAdapterMessages {
92
+ /**
93
+ * Unreadable payload (tier 3). Template — `{versionSuffix}` is
94
+ * `degradedVersionSuffix` when the payload carried a string
95
+ * `schemaVersion`, and `''` otherwise.
96
+ */
97
+ degradedNotice: string
98
+ /** Inserted into `degradedNotice`. Template — `{version}`. */
99
+ degradedVersionSuffix: string
100
+ /**
101
+ * Usable envelope, unknown version (tier 2). Template — `{version}` = the
102
+ * version read, `{expected}` = `CONNECTOR_DYNAMIC_RESULT_V1`.
103
+ */
104
+ versionWarning: string
105
+ }
106
+
107
+ /** English defaults for {@link ConnectorAdapterMessages}. */
108
+ export const DEFAULT_CONNECTOR_MESSAGES: ConnectorAdapterMessages = {
109
+ degradedNotice:
110
+ '### Result not rendered\n\nThe connector result could not be interpreted{versionSuffix}. This explicit state replaces a silent disappearance of the rendering.',
111
+ degradedVersionSuffix: ' (schema: `{version}`)',
112
+ versionWarning:
113
+ '> \u26A0 Unrecognized connector schema (`{version}`, expected `{expected}`). The rendering below is in degraded mode.',
114
+ }
115
+
77
116
  export interface ConnectorResultToUILayoutOptions {
78
117
  /** Layout id. Default derived from `connectorId` + `queryHash` / `toolName`. */
79
118
  id?: string
80
119
  /** Heading for the actions `action-group`. */
81
120
  actionsTitle?: string
121
+ /**
122
+ * Partial override of the degraded-state wording, merged over
123
+ * {@link DEFAULT_CONNECTOR_MESSAGES}. Hosts that render in another
124
+ * language pass their own paragraphs here.
125
+ *
126
+ * @since v6.20.0
127
+ */
128
+ messages?: Partial<ConnectorAdapterMessages>
82
129
  }
83
130
 
84
131
  /**
@@ -144,6 +191,7 @@ export function connectorResultToUILayout(
144
191
  options: ConnectorResultToUILayoutOptions = {}
145
192
  ): UILayout {
146
193
  const strict = ConnectorDynamicResultV1Schema.safeParse(result)
194
+ const messages: ConnectorAdapterMessages = { ...DEFAULT_CONNECTOR_MESSAGES, ...options.messages }
147
195
 
148
196
  // ── Tier 3 : unreadable ───────────────────────────────────
149
197
  if (!strict.success) {
@@ -158,9 +206,12 @@ export function connectorResultToUILayout(
158
206
  components: [
159
207
  degradedTextComponent(
160
208
  'connector-degraded-notice',
161
- `### Résultat non rendu\n\nLe résultat du connecteur n'a pas pu être interprété${
162
- typeof version === 'string' ? ` (schéma : \`${version}\`)` : ''
163
- }. Cet état explicite remplace une disparition silencieuse du rendu.`
209
+ formatMCPUIString(messages.degradedNotice, {
210
+ versionSuffix:
211
+ typeof version === 'string'
212
+ ? formatMCPUIString(messages.degradedVersionSuffix, { version })
213
+ : '',
214
+ })
164
215
  ),
165
216
  ],
166
217
  grid: { ...DEFAULT_GRID },
@@ -171,7 +222,10 @@ export function connectorResultToUILayout(
171
222
  const components: UIComponent[] = [
172
223
  degradedTextComponent(
173
224
  'connector-version-warning',
174
- `> ⚠ Schéma connecteur non reconnu (\`${r.schemaVersion}\`, attendu \`${CONNECTOR_DYNAMIC_RESULT_V1}\`). Le rendu ci-dessous est en mode dégradé.`
225
+ formatMCPUIString(messages.versionWarning, {
226
+ version: r.schemaVersion,
227
+ expected: CONNECTOR_DYNAMIC_RESULT_V1,
228
+ })
175
229
  ),
176
230
  ...collectComponents(r),
177
231
  ]