@seed-ship/mcp-ui-solid 6.15.0 → 6.17.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 (265) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/README.md +20 -3
  3. package/dist/_virtual/leaflet.markercluster-src.cjs +30 -7
  4. package/dist/_virtual/leaflet.markercluster-src.cjs.map +1 -1
  5. package/dist/_virtual/leaflet.markercluster-src.js +28 -5
  6. package/dist/_virtual/leaflet.markercluster-src.js.map +1 -1
  7. package/dist/_virtual/{leaflet.markercluster-src2.cjs → leaflet2.markercluster-src.cjs} +1 -1
  8. package/dist/_virtual/leaflet2.markercluster-src.cjs.map +1 -0
  9. package/dist/_virtual/{leaflet.markercluster-src2.js → leaflet2.markercluster-src.js} +1 -1
  10. package/dist/_virtual/leaflet2.markercluster-src.js.map +1 -0
  11. package/dist/adapters/connector.js +1 -1
  12. package/dist/components/ActionGroupRenderer.js +1 -1
  13. package/dist/components/ActionRenderer.js +1 -1
  14. package/dist/components/AgentCard.js +1 -1
  15. package/dist/components/AgentHandoff.js +1 -1
  16. package/dist/components/ArtifactRenderer.js +1 -1
  17. package/dist/components/AutocompleteDropdown.cjs +1 -2
  18. package/dist/components/AutocompleteDropdown.cjs.map +1 -1
  19. package/dist/components/AutocompleteDropdown.js +2 -3
  20. package/dist/components/AutocompleteFormField.cjs +1 -2
  21. package/dist/components/AutocompleteFormField.cjs.map +1 -1
  22. package/dist/components/AutocompleteFormField.js +2 -3
  23. package/dist/components/BriefingDiff.js +1 -1
  24. package/dist/components/CarouselRenderer.js +1 -1
  25. package/dist/components/ChartJSRenderer.js +1 -1
  26. package/dist/components/ChatPrompt.js +1 -1
  27. package/dist/components/CodeBlockRenderer.js +1 -1
  28. package/dist/components/ComponentToolbar.js +1 -1
  29. package/dist/components/DataPreviewSection.js +1 -1
  30. package/dist/components/DegradedFallback.cjs.map +1 -1
  31. package/dist/components/DegradedFallback.d.ts +1 -1
  32. package/dist/components/DegradedFallback.js +1 -1
  33. package/dist/components/DegradedFallback.js.map +1 -1
  34. package/dist/components/DraggableGridItem.cjs +1 -2
  35. package/dist/components/DraggableGridItem.cjs.map +1 -1
  36. package/dist/components/DraggableGridItem.js +2 -3
  37. package/dist/components/EditableUIResourceRenderer.cjs +1 -2
  38. package/dist/components/EditableUIResourceRenderer.cjs.map +1 -1
  39. package/dist/components/EditableUIResourceRenderer.js +2 -3
  40. package/dist/components/ExpandableWrapper.js +2 -2
  41. package/dist/components/FeedbackInline.js +1 -1
  42. package/dist/components/FooterRenderer.js +1 -1
  43. package/dist/components/FormFieldRenderer.js +1 -1
  44. package/dist/components/FormRenderer.js +1 -1
  45. package/dist/components/GenerativeUIErrorBoundary.js +1 -1
  46. package/dist/components/GhostText.cjs +1 -2
  47. package/dist/components/GhostText.cjs.map +1 -1
  48. package/dist/components/GhostText.js +2 -3
  49. package/dist/components/GraphRenderer.cjs +2 -19
  50. package/dist/components/GraphRenderer.cjs.map +1 -1
  51. package/dist/components/GraphRenderer.d.ts.map +1 -1
  52. package/dist/components/GraphRenderer.js +2 -19
  53. package/dist/components/GraphRenderer.js.map +1 -1
  54. package/dist/components/GridRenderer.cjs +1 -2
  55. package/dist/components/GridRenderer.cjs.map +1 -1
  56. package/dist/components/GridRenderer.js +2 -3
  57. package/dist/components/ImageGalleryRenderer.js +1 -1
  58. package/dist/components/LightboxOverlay.js +1 -1
  59. package/dist/components/MapRenderer.cjs +10 -11
  60. package/dist/components/MapRenderer.cjs.map +1 -1
  61. package/dist/components/MapRenderer.d.ts +6 -1
  62. package/dist/components/MapRenderer.d.ts.map +1 -1
  63. package/dist/components/MapRenderer.js +7 -8
  64. package/dist/components/MapRenderer.js.map +1 -1
  65. package/dist/components/ModalRenderer.js +1 -1
  66. package/dist/components/PortalDropdownMenu.js +1 -1
  67. package/dist/components/PresentationFeedback.js +1 -1
  68. package/dist/components/RenderContext.js +1 -1
  69. package/dist/components/ResizeHandle.cjs +1 -2
  70. package/dist/components/ResizeHandle.cjs.map +1 -1
  71. package/dist/components/ResizeHandle.js +2 -3
  72. package/dist/components/ScratchpadPanel.js +1 -1
  73. package/dist/components/SplitStepper.js +1 -1
  74. package/dist/components/StreamingUIRenderer.js +1 -1
  75. package/dist/components/UIResourceRenderer.cjs +12 -1
  76. package/dist/components/UIResourceRenderer.cjs.map +1 -1
  77. package/dist/components/UIResourceRenderer.d.ts.map +1 -1
  78. package/dist/components/UIResourceRenderer.js +13 -2
  79. package/dist/components/UIResourceRenderer.js.map +1 -1
  80. package/dist/components/VerifiedText.js +1 -1
  81. package/dist/components/VideoRenderer.js +1 -1
  82. package/dist/components/index.d.ts.map +1 -1
  83. package/dist/index.d.cts +1 -1
  84. package/dist/index.d.ts +1 -1
  85. package/dist/index.d.ts.map +1 -1
  86. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/core/component.cjs +1 -1
  87. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/core/component.js +1 -1
  88. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/axis/axis.cjs +1 -1
  89. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/axis/axis.js +1 -1
  90. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/axis/constant.cjs +1 -1
  91. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/axis/constant.js +1 -1
  92. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/axis/guides/grid.cjs +2 -2
  93. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/axis/guides/grid.js +2 -2
  94. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/axis/guides/labels.cjs +6 -6
  95. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/axis/guides/labels.js +6 -6
  96. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/axis/guides/line.cjs +1 -1
  97. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/axis/guides/line.js +1 -1
  98. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/axis/guides/ticks.cjs +2 -2
  99. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/axis/guides/ticks.js +2 -2
  100. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/axis/guides/title.cjs +1 -1
  101. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/axis/guides/title.js +1 -1
  102. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/axis/guides/utils.cjs +1 -1
  103. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/axis/guides/utils.js +1 -1
  104. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/grid/index.cjs +3 -3
  105. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/grid/index.js +3 -3
  106. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/indicator/indicator.cjs +4 -4
  107. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/indicator/indicator.js +4 -4
  108. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/legend/category/item.cjs +5 -5
  109. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/legend/category/item.js +5 -5
  110. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/legend/category/items.cjs +5 -5
  111. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/legend/category/items.js +5 -5
  112. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/legend/category.cjs +2 -2
  113. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/legend/category.js +2 -2
  114. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/legend/continuous/handle.cjs +1 -1
  115. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/legend/continuous/handle.js +1 -1
  116. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/legend/title/index.cjs +3 -3
  117. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/legend/title/index.js +3 -3
  118. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/marker/utils.cjs +1 -1
  119. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/marker/utils.js +1 -1
  120. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/navigator/index.cjs +5 -5
  121. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/navigator/index.js +5 -5
  122. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/poptip/index.cjs +2 -2
  123. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/poptip/index.js +2 -2
  124. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/select/option.cjs +2 -2
  125. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/select/option.js +2 -2
  126. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/select/select.cjs +2 -2
  127. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/select/select.js +2 -2
  128. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/slider/handle.cjs +2 -2
  129. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/slider/handle.js +2 -2
  130. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/slider/index.cjs +4 -4
  131. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/slider/index.js +4 -4
  132. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/sparkline/columns.cjs +1 -1
  133. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/sparkline/columns.js +1 -1
  134. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/sparkline/index.cjs +2 -2
  135. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/sparkline/index.js +2 -2
  136. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/sparkline/lines.cjs +1 -1
  137. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/sparkline/lines.js +1 -1
  138. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/sparkline/utils.cjs +2 -2
  139. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/sparkline/utils.js +2 -2
  140. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/timebar/controller.cjs +2 -2
  141. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/timebar/controller.js +2 -2
  142. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/timebar/handle.cjs +1 -1
  143. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/timebar/handle.js +1 -1
  144. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/timebar/icons.cjs +4 -4
  145. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/timebar/icons.js +4 -4
  146. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/timebar/timebar.cjs +3 -3
  147. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/timebar/timebar.js +3 -3
  148. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/tooltip/index.cjs +1 -1
  149. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/ui/tooltip/index.js +1 -1
  150. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/util/selection.cjs +1 -1
  151. package/dist/node_modules/.pnpm/@antv_component@2.1.11/node_modules/@antv/component/esm/util/selection.js +1 -1
  152. package/dist/node_modules/.pnpm/@antv_g-lite@2.7.0/node_modules/@antv/g-lite/dist/index.esm.js +1 -1
  153. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/behaviors/scroll-canvas.cjs +1 -1
  154. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/behaviors/scroll-canvas.js +1 -1
  155. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/elements/combos/base-combo.cjs +1 -1
  156. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/elements/combos/base-combo.js +1 -1
  157. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/elements/edges/base-edge.cjs +1 -1
  158. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/elements/edges/base-edge.js +1 -1
  159. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/index.cjs +58 -58
  160. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/plugins/legend.cjs +1 -1
  161. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/plugins/legend.js +1 -1
  162. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/plugins/minimap/index.cjs +1 -1
  163. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/plugins/minimap/index.js +1 -1
  164. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/plugins/snapline/index.cjs +1 -1
  165. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/plugins/snapline/index.js +1 -1
  166. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/plugins/tooltip.cjs +1 -1
  167. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/plugins/tooltip.js +1 -1
  168. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/registry/build-in.cjs +1 -1
  169. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/registry/build-in.js +1 -1
  170. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/runtime/data.cjs +1 -1
  171. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/runtime/data.js +1 -1
  172. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/runtime/element.cjs +1 -1
  173. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/runtime/element.js +1 -1
  174. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/runtime/graph.cjs +1 -1
  175. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/runtime/graph.js +1 -1
  176. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/runtime/layout.cjs +2 -2
  177. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/runtime/layout.js +2 -2
  178. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/runtime/viewport.cjs +1 -1
  179. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/runtime/viewport.js +1 -1
  180. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/utils/element.cjs +1 -1
  181. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/utils/element.js +1 -1
  182. package/dist/node_modules/.pnpm/@antv_g6@5.1.0/node_modules/@antv/g6/esm/utils/point.js +1 -1
  183. package/dist/node_modules/.pnpm/@antv_layout@2.0.0/node_modules/@antv/layout/lib/algorithm/antv-dagre/rank/index.js +1 -1
  184. package/dist/node_modules/.pnpm/@antv_layout@2.0.0/node_modules/@antv/layout/lib/algorithm/concentric/index.js +1 -1
  185. package/dist/node_modules/.pnpm/@antv_scale@0.4.16/node_modules/@antv/scale/esm/scales/continuous.cjs +1 -1
  186. package/dist/node_modules/.pnpm/@antv_scale@0.4.16/node_modules/@antv/scale/esm/scales/continuous.js +1 -1
  187. package/dist/node_modules/.pnpm/@tanstack_solid-virtual@3.13.18_solid-js@1.9.11/node_modules/@tanstack/solid-virtual/dist/esm/index.cjs +13 -0
  188. package/dist/node_modules/.pnpm/@tanstack_solid-virtual@3.13.18_solid-js@1.9.11/node_modules/@tanstack/solid-virtual/dist/esm/index.cjs.map +1 -1
  189. package/dist/node_modules/.pnpm/@tanstack_solid-virtual@3.13.18_solid-js@1.9.11/node_modules/@tanstack/solid-virtual/dist/esm/index.js +15 -2
  190. package/dist/node_modules/.pnpm/@tanstack_solid-virtual@3.13.18_solid-js@1.9.11/node_modules/@tanstack/solid-virtual/dist/esm/index.js.map +1 -1
  191. package/dist/node_modules/.pnpm/@tanstack_virtual-core@3.13.18/node_modules/@tanstack/virtual-core/dist/esm/index.cjs +64 -0
  192. package/dist/node_modules/.pnpm/@tanstack_virtual-core@3.13.18/node_modules/@tanstack/virtual-core/dist/esm/index.cjs.map +1 -1
  193. package/dist/node_modules/.pnpm/@tanstack_virtual-core@3.13.18/node_modules/@tanstack/virtual-core/dist/esm/index.js +66 -2
  194. package/dist/node_modules/.pnpm/@tanstack_virtual-core@3.13.18/node_modules/@tanstack/virtual-core/dist/esm/index.js.map +1 -1
  195. package/dist/node_modules/.pnpm/@tanstack_virtual-core@3.13.18/node_modules/@tanstack/virtual-core/dist/esm/utils.cjs +1 -1
  196. package/dist/node_modules/.pnpm/@tanstack_virtual-core@3.13.18/node_modules/@tanstack/virtual-core/dist/esm/utils.cjs.map +1 -1
  197. package/dist/node_modules/.pnpm/@tanstack_virtual-core@3.13.18/node_modules/@tanstack/virtual-core/dist/esm/utils.js +1 -1
  198. package/dist/node_modules/.pnpm/@tanstack_virtual-core@3.13.18/node_modules/@tanstack/virtual-core/dist/esm/utils.js.map +1 -1
  199. package/dist/node_modules/.pnpm/color-string@1.9.1/node_modules/color-string/index.cjs +6 -6
  200. package/dist/node_modules/.pnpm/{dompurify@3.4.1 → dompurify@3.4.13}/node_modules/dompurify/dist/purify.es.cjs +671 -233
  201. package/dist/node_modules/.pnpm/dompurify@3.4.13/node_modules/dompurify/dist/purify.es.cjs.map +1 -0
  202. package/dist/node_modules/.pnpm/{dompurify@3.4.1 → dompurify@3.4.13}/node_modules/dompurify/dist/purify.es.js +671 -233
  203. package/dist/node_modules/.pnpm/dompurify@3.4.13/node_modules/dompurify/dist/purify.es.js.map +1 -0
  204. package/dist/node_modules/.pnpm/leaflet.markercluster@1.5.3_leaflet@1.9.4/node_modules/leaflet.markercluster/dist/leaflet.markercluster-src.cjs +7 -7
  205. package/dist/node_modules/.pnpm/leaflet.markercluster@1.5.3_leaflet@1.9.4/node_modules/leaflet.markercluster/dist/leaflet.markercluster-src.cjs.map +1 -1
  206. package/dist/node_modules/.pnpm/leaflet.markercluster@1.5.3_leaflet@1.9.4/node_modules/leaflet.markercluster/dist/leaflet.markercluster-src.js +7 -7
  207. package/dist/node_modules/.pnpm/leaflet.markercluster@1.5.3_leaflet@1.9.4/node_modules/leaflet.markercluster/dist/leaflet.markercluster-src.js.map +1 -1
  208. package/dist/node_modules/.pnpm/leaflet@1.9.4/node_modules/leaflet/dist/leaflet-src.cjs +83 -83
  209. package/dist/node_modules/.pnpm/leaflet@1.9.4/node_modules/leaflet/dist/leaflet-src.cjs.map +1 -1
  210. package/dist/node_modules/.pnpm/leaflet@1.9.4/node_modules/leaflet/dist/leaflet-src.js +83 -83
  211. package/dist/node_modules/.pnpm/leaflet@1.9.4/node_modules/leaflet/dist/leaflet-src.js.map +1 -1
  212. package/dist/plugins/groq.cjs +1 -2
  213. package/dist/plugins/groq.cjs.map +1 -1
  214. package/dist/plugins/groq.js +1 -2
  215. package/dist/plugins/rest.cjs +1 -2
  216. package/dist/plugins/rest.cjs.map +1 -1
  217. package/dist/plugins/rest.js +1 -2
  218. package/dist/plugins/supabase.cjs +1 -2
  219. package/dist/plugins/supabase.cjs.map +1 -1
  220. package/dist/plugins/supabase.js +1 -2
  221. package/dist/services/component-registry.cjs +223 -7
  222. package/dist/services/component-registry.cjs.map +1 -1
  223. package/dist/services/component-registry.d.ts +0 -3
  224. package/dist/services/component-registry.d.ts.map +1 -1
  225. package/dist/services/component-registry.js +223 -7
  226. package/dist/services/component-registry.js.map +1 -1
  227. package/dist/services/validation.cjs +1 -23
  228. package/dist/services/validation.cjs.map +1 -1
  229. package/dist/services/validation.d.ts.map +1 -1
  230. package/dist/services/validation.js +2 -24
  231. package/dist/services/validation.js.map +1 -1
  232. package/dist/types/index.d.ts +12 -6
  233. package/dist/types/index.d.ts.map +1 -1
  234. package/dist/types.d.cts +12 -6
  235. package/dist/types.d.ts +12 -6
  236. package/dist/utils/escape-html.cjs +10 -0
  237. package/dist/utils/escape-html.cjs.map +1 -0
  238. package/dist/utils/escape-html.d.ts +13 -0
  239. package/dist/utils/escape-html.d.ts.map +1 -0
  240. package/dist/utils/escape-html.js +10 -0
  241. package/dist/utils/escape-html.js.map +1 -0
  242. package/docs/briefs/BRIEF-graph-component-g6.md +10 -0
  243. package/package.json +2 -2
  244. package/src/components/DegradedFallback.tsx +1 -1
  245. package/src/components/GraphRenderer.tsx +1 -19
  246. package/src/components/MapRenderer.security.test.ts +55 -2
  247. package/src/components/MapRenderer.tsx +15 -13
  248. package/src/components/UIResourceRenderer.tsx +8 -0
  249. package/src/components/UnsupportedComponent.test.tsx +28 -1
  250. package/src/components/index.ts +3 -0
  251. package/src/hooks/useStreamingUI.test.ts +194 -0
  252. package/src/index.ts +1 -0
  253. package/src/services/component-registry.test.ts +104 -2
  254. package/src/services/component-registry.ts +236 -7
  255. package/src/services/validation.test.ts +26 -0
  256. package/src/services/validation.ts +12 -24
  257. package/src/types/index.ts +12 -26
  258. package/src/types/map-types.test.ts +20 -0
  259. package/src/utils/escape-html.test.ts +30 -0
  260. package/src/utils/escape-html.ts +24 -0
  261. package/tsconfig.tsbuildinfo +1 -1
  262. package/dist/_virtual/leaflet.markercluster-src2.cjs.map +0 -1
  263. package/dist/_virtual/leaflet.markercluster-src2.js.map +0 -1
  264. package/dist/node_modules/.pnpm/dompurify@3.4.1/node_modules/dompurify/dist/purify.es.cjs.map +0 -1
  265. package/dist/node_modules/.pnpm/dompurify@3.4.1/node_modules/dompurify/dist/purify.es.js.map +0 -1
@@ -582,31 +582,260 @@ export const CodeRegistry: ComponentRegistryEntry = {
582
582
  /**
583
583
  * Map Registry Entry
584
584
  */
585
+ const MAP_LAT_LNG_POINT_SCHEMA = {
586
+ oneOf: [
587
+ {
588
+ type: 'array',
589
+ items: { type: 'number' },
590
+ minItems: 2,
591
+ maxItems: 2,
592
+ description: '[latitude, longitude] tuple',
593
+ },
594
+ {
595
+ type: 'object',
596
+ properties: {
597
+ lat: { type: 'number' },
598
+ lng: { type: 'number' },
599
+ },
600
+ required: ['lat', 'lng'],
601
+ description: '{ lat, lng } object',
602
+ },
603
+ ],
604
+ }
605
+
606
+ const MAP_GEOJSON_POSITION_SCHEMA = {
607
+ type: 'array',
608
+ items: { type: 'number' },
609
+ minItems: 2,
610
+ }
611
+
612
+ const MAP_GEOJSON_COORDINATES_SCHEMA = {
613
+ anyOf: [
614
+ MAP_GEOJSON_POSITION_SCHEMA,
615
+ { type: 'array', items: MAP_GEOJSON_POSITION_SCHEMA },
616
+ { type: 'array', items: { type: 'array', items: MAP_GEOJSON_POSITION_SCHEMA } },
617
+ {
618
+ type: 'array',
619
+ items: {
620
+ type: 'array',
621
+ items: { type: 'array', items: MAP_GEOJSON_POSITION_SCHEMA },
622
+ },
623
+ },
624
+ ],
625
+ }
626
+
627
+ const MAP_GEOJSON_BBOX_SCHEMA = {
628
+ type: 'array',
629
+ items: { type: 'number' },
630
+ }
631
+
632
+ const MAP_GEOJSON_GEOMETRY_TYPE_SCHEMA = {
633
+ type: 'string',
634
+ enum: [
635
+ 'Point',
636
+ 'MultiPoint',
637
+ 'LineString',
638
+ 'MultiLineString',
639
+ 'Polygon',
640
+ 'MultiPolygon',
641
+ 'GeometryCollection',
642
+ ],
643
+ }
644
+
645
+ const MAP_GEOJSON_SIMPLE_GEOMETRY_SCHEMA = {
646
+ type: 'object',
647
+ properties: {
648
+ type: MAP_GEOJSON_GEOMETRY_TYPE_SCHEMA,
649
+ coordinates: MAP_GEOJSON_COORDINATES_SCHEMA,
650
+ bbox: MAP_GEOJSON_BBOX_SCHEMA,
651
+ },
652
+ required: ['type'],
653
+ }
654
+
655
+ const MAP_GEOJSON_GEOMETRY_SCHEMA = {
656
+ type: 'object',
657
+ properties: {
658
+ type: MAP_GEOJSON_GEOMETRY_TYPE_SCHEMA,
659
+ coordinates: MAP_GEOJSON_COORDINATES_SCHEMA,
660
+ geometries: { type: 'array', items: MAP_GEOJSON_SIMPLE_GEOMETRY_SCHEMA },
661
+ bbox: MAP_GEOJSON_BBOX_SCHEMA,
662
+ },
663
+ required: ['type'],
664
+ }
665
+
666
+ const MAP_GEOJSON_FEATURE_SCHEMA = {
667
+ type: 'object',
668
+ properties: {
669
+ type: { type: 'string', enum: ['Feature'] },
670
+ geometry: { oneOf: [MAP_GEOJSON_GEOMETRY_SCHEMA, { type: 'null' }] },
671
+ properties: { oneOf: [{ type: 'object' }, { type: 'null' }] },
672
+ id: { oneOf: [{ type: 'string' }, { type: 'number' }] },
673
+ bbox: MAP_GEOJSON_BBOX_SCHEMA,
674
+ },
675
+ required: ['type', 'geometry'],
676
+ }
677
+
678
+ const MAP_GEOJSON_FEATURE_COLLECTION_SCHEMA = {
679
+ type: 'object',
680
+ properties: {
681
+ type: { type: 'string', enum: ['FeatureCollection'] },
682
+ features: { type: 'array', items: MAP_GEOJSON_FEATURE_SCHEMA },
683
+ bbox: MAP_GEOJSON_BBOX_SCHEMA,
684
+ },
685
+ required: ['type', 'features'],
686
+ }
687
+
688
+ const MAP_GEOJSON_SCHEMA = {
689
+ oneOf: [
690
+ MAP_GEOJSON_FEATURE_COLLECTION_SCHEMA,
691
+ MAP_GEOJSON_FEATURE_SCHEMA,
692
+ MAP_GEOJSON_GEOMETRY_SCHEMA,
693
+ ],
694
+ description: 'GeoJSON FeatureCollection, Feature, or Geometry',
695
+ }
696
+
697
+ const MAP_GEOJSON_STYLE_SCHEMA = {
698
+ type: 'object',
699
+ properties: {
700
+ fillColor: { type: 'string' },
701
+ fillOpacity: { type: 'number' },
702
+ strokeColor: { type: 'string' },
703
+ strokeWeight: { type: 'number' },
704
+ strokeOpacity: { type: 'number' },
705
+ choroplethField: { type: 'string' },
706
+ choroplethScale: {
707
+ type: 'array',
708
+ items: {
709
+ type: 'array',
710
+ items: [{ type: 'number' }, { type: 'string' }],
711
+ additionalItems: false,
712
+ minItems: 2,
713
+ maxItems: 2,
714
+ },
715
+ },
716
+ choroplethFallback: { type: 'string' },
717
+ },
718
+ }
719
+
720
+ const MAP_POPUP_SCHEMA = {
721
+ type: 'object',
722
+ properties: {
723
+ titleField: { type: 'string' },
724
+ fields: { type: 'array', items: { type: 'string' } },
725
+ template: {
726
+ type: 'string',
727
+ description: 'Trusted-host HTML template; ignored on the default untrusted renderer path',
728
+ },
729
+ },
730
+ }
731
+
585
732
  export const MapRegistry: ComponentRegistryEntry = {
586
733
  type: 'map',
587
734
  name: 'InteractiveMap',
588
735
  description:
589
- 'Render interactive maps with markers using Leaflet. Supports marker clustering, custom tile layers, and auto-fitting bounds. Best for displaying geographic data with up to 1000 markers.',
736
+ 'Render interactive maps on the default OpenStreetMap base layer (using Leaflet internally) from already-resolved markers, GeoJSON, named layers, clustering, or PMTiles. The renderer does not geocode place names.',
590
737
  schema: {
591
738
  type: 'object',
592
739
  properties: {
593
- center: { type: 'array', items: { type: 'number' }, minItems: 2, maxItems: 2, description: 'Map center [lat, lng]' },
594
- zoom: { type: 'number', description: 'Zoom level (1-18, default: 13)' },
740
+ center: {
741
+ ...MAP_LAT_LNG_POINT_SCHEMA,
742
+ description: 'Initial map center as [lat, lng] or { lat, lng }',
743
+ },
744
+ zoom: { type: 'number', description: 'Initial zoom level (default: 13)' },
595
745
  markers: {
596
746
  type: 'array',
597
747
  items: {
598
748
  type: 'object',
599
749
  properties: {
600
- position: { type: 'array', items: { type: 'number' }, minItems: 2, maxItems: 2 },
601
- title: { type: 'string' },
750
+ position: MAP_LAT_LNG_POINT_SCHEMA,
751
+ tooltip: { type: 'string' },
602
752
  popup: { type: 'string' },
603
753
  },
604
754
  required: ['position'],
605
755
  },
606
756
  },
607
757
  height: { type: 'string', description: 'CSS height (default: 400px)' },
608
- fitBounds: { type: 'boolean', description: 'Auto-fit to show all markers' },
609
- clustering: { type: 'boolean', description: 'Enable marker clustering for large datasets' },
758
+ fitBounds: { type: 'boolean', description: 'Auto-fit to rendered markers and features' },
759
+ zoomControl: { type: 'boolean', description: 'Show Leaflet zoom controls' },
760
+ scrollWheelZoom: { type: 'boolean', description: 'Allow scroll-wheel zoom' },
761
+ tileLayer: {
762
+ type: 'string',
763
+ description:
764
+ 'Optional base tile URL template (defaults to OpenStreetMap); the host remains responsible for network policy',
765
+ },
766
+ attribution: { type: 'string', description: 'Base-map attribution' },
767
+ className: { type: 'string', description: 'Custom CSS class' },
768
+ geojson: MAP_GEOJSON_SCHEMA,
769
+ geojsonStyle: MAP_GEOJSON_STYLE_SCHEMA,
770
+ popup: MAP_POPUP_SCHEMA,
771
+ layers: {
772
+ type: 'array',
773
+ description: 'Named GeoJSON overlays',
774
+ items: {
775
+ type: 'object',
776
+ properties: {
777
+ name: { type: 'string', minLength: 1 },
778
+ visible: { type: 'boolean' },
779
+ geojson: MAP_GEOJSON_SCHEMA,
780
+ style: MAP_GEOJSON_STYLE_SCHEMA,
781
+ popup: MAP_POPUP_SCHEMA,
782
+ },
783
+ required: ['name', 'geojson'],
784
+ },
785
+ },
786
+ clustering: {
787
+ oneOf: [
788
+ { type: 'boolean' },
789
+ {
790
+ type: 'object',
791
+ properties: {
792
+ maxClusterRadius: { type: 'number' },
793
+ spiderfyOnMaxZoom: { type: 'boolean' },
794
+ showCoverageOnHover: { type: 'boolean' },
795
+ disableClusteringAtZoom: { type: 'number' },
796
+ animateAddingMarkers: { type: 'boolean' },
797
+ },
798
+ },
799
+ ],
800
+ description: 'Enable marker clustering or provide cluster options',
801
+ },
802
+ pmtiles: {
803
+ type: 'object',
804
+ description: 'PMTiles vector-tile overlay (requires the optional protomaps-leaflet peer)',
805
+ properties: {
806
+ url: { type: 'string' },
807
+ attribution: { type: 'string' },
808
+ paintRules: {
809
+ type: 'array',
810
+ items: {
811
+ type: 'object',
812
+ properties: {
813
+ dataLayer: { type: 'string' },
814
+ symbolizer: { type: 'string', enum: ['polygon', 'line', 'circle'] },
815
+ color: { type: 'string' },
816
+ width: { type: 'number' },
817
+ opacity: { type: 'number' },
818
+ },
819
+ required: ['dataLayer', 'symbolizer'],
820
+ },
821
+ },
822
+ labelRules: {
823
+ type: 'array',
824
+ items: {
825
+ type: 'object',
826
+ properties: {
827
+ dataLayer: { type: 'string' },
828
+ textField: { type: 'string' },
829
+ fontSize: { type: 'number' },
830
+ },
831
+ required: ['dataLayer', 'textField'],
832
+ },
833
+ },
834
+ maxZoom: { type: 'number' },
835
+ minZoom: { type: 'number' },
836
+ },
837
+ required: ['url'],
838
+ },
610
839
  },
611
840
  required: [],
612
841
  },
@@ -15,6 +15,7 @@ import {
15
15
  DEFAULT_RESOURCE_LIMITS,
16
16
  } from './validation';
17
17
  import type { UIComponent, ComponentType } from '../types';
18
+ import { ComponentTypeSchema } from '@seed-ship/mcp-ui-spec';
18
19
 
19
20
  /** Helper to create a minimal valid UIComponent for testing */
20
21
  function makeComponent(type: ComponentType, params: Record<string, any> = {}): UIComponent {
@@ -51,6 +52,7 @@ const PASSTHROUGH_TYPES: ComponentType[] = [
51
52
  'grid',
52
53
  'carousel',
53
54
  'footer',
55
+ 'composite', // v6.x — restored to KNOWN_COMPONENT_TYPES via the spec-derived Set
54
56
  ];
55
57
 
56
58
  describe('validateComponent', () => {
@@ -64,6 +66,30 @@ describe('validateComponent', () => {
64
66
  });
65
67
  });
66
68
 
69
+ describe('spec↔solid parity (drift guard)', () => {
70
+ // KNOWN_COMPONENT_TYPES is now derived from ComponentTypeSchema.options (the
71
+ // single source of truth) instead of a hand-written list, so a spec enum
72
+ // member can never silently drift out of solid's known-types set again.
73
+ // `composite` is the regression case: it lives in the spec enum but had
74
+ // been dropped from the former hand list, contradicting its pass-through
75
+ // docstring and making a composite component get flagged as unknown.
76
+ it('composite is a spec component type (single source of truth)', () => {
77
+ expect(ComponentTypeSchema.options).toContain('composite');
78
+ });
79
+
80
+ it('every passthrough type under test is a real spec component type', () => {
81
+ for (const type of PASSTHROUGH_TYPES) {
82
+ expect(ComponentTypeSchema.options).toContain(type);
83
+ }
84
+ });
85
+
86
+ it('recognizes composite (regression lock: it had drifted out of the known set)', () => {
87
+ const result = validateComponent(makeComponent('composite'));
88
+ const unknown = result.errors?.find((e) => e.code === 'UNKNOWN_COMPONENT_TYPE');
89
+ expect(unknown).toBeUndefined();
90
+ });
91
+ });
92
+
67
93
  describe('validated types still work', () => {
68
94
  it('validates a valid chart component', () => {
69
95
  const component = makeComponent('chart', {
@@ -27,6 +27,8 @@ import {
27
27
  FormComponentParamsSchema,
28
28
  // v6.0.0 — graph primitive (peer @antv/g6 ^5)
29
29
  GraphComponentParamsSchema,
30
+ // Single source of truth for the component-type enum (kills spec↔solid drift).
31
+ ComponentTypeSchema,
30
32
  } from '@seed-ship/mcp-ui-spec';
31
33
  import type {
32
34
  UIComponent,
@@ -44,30 +46,14 @@ import type {
44
46
  /**
45
47
  * All known ComponentType values — used to distinguish known-but-unvalidated
46
48
  * types (pass through) from truly unknown strings (reject).
49
+ *
50
+ * Derived directly from the spec's `ComponentTypeSchema` (the single source of
51
+ * truth) rather than hand-maintained, so a new enum member in the spec can
52
+ * never silently drift out of solid's known-types set again. This is what
53
+ * restored `composite`: it is in the spec enum but had been dropped from the
54
+ * former hand-written list, contradicting the pass-through docstrings below.
47
55
  */
48
- const KNOWN_COMPONENT_TYPES: Set<string> = new Set<ComponentType>([
49
- 'chart',
50
- 'table',
51
- 'metric',
52
- 'text',
53
- 'grid',
54
- 'iframe',
55
- 'image',
56
- 'link',
57
- 'action',
58
- 'footer',
59
- 'carousel',
60
- 'artifact',
61
- 'form',
62
- 'modal',
63
- 'action-group',
64
- 'image-gallery',
65
- 'video',
66
- 'code',
67
- 'map',
68
- // v6.0.0
69
- 'graph',
70
- ]);
56
+ const KNOWN_COMPONENT_TYPES: Set<string> = new Set<string>(ComponentTypeSchema.options);
71
57
 
72
58
  /**
73
59
  * Spec-driven validation dispatch table (B.1 — v5.5.0, expanded in v5.6.0).
@@ -81,7 +67,9 @@ const KNOWN_COMPONENT_TYPES: Set<string> = new Set<ComponentType>([
81
67
  *
82
68
  * **v5.6.0** : `map` and `form` joined the dispatch after spec@5.0.2 relaxed
83
69
  * their schemas (LatLngPoint union for map.center, regex relax for
84
- * field.name) per deposium audit §L answers. Closed B.1 to **14/17 types**.
70
+ * field.name) per deposium audit §L answers. As of v6.x this table
71
+ * spec-validates 15 of the 21 component types; the remainder use imperative
72
+ * validators (`chart`/`table`) or are pass-through (`grid`/`footer`/`composite`/`modal`).
85
73
  *
86
74
  * Types deliberately omitted (kept on the imperative path):
87
75
  * - `chart`, `table` — have rich imperative validators with their own
@@ -6,29 +6,15 @@
6
6
  */
7
7
 
8
8
  /**
9
- * Component types supported by the renderer
9
+ * Component types supported by the renderer.
10
+ *
11
+ * Re-exported from `@seed-ship/mcp-ui-spec` (`ComponentTypeSchema`) — the spec
12
+ * is the single source of truth for the enum. Solid used to hand-maintain a
13
+ * parallel union here, which drifted (it had silently dropped `composite`).
14
+ * Re-exporting keeps this type and the spec enum in lockstep by construction.
10
15
  */
11
- export type ComponentType =
12
- | 'chart'
13
- | 'table'
14
- | 'metric'
15
- | 'text'
16
- | 'grid'
17
- | 'iframe'
18
- | 'image'
19
- | 'link'
20
- | 'action'
21
- | 'footer'
22
- | 'carousel'
23
- | 'artifact'
24
- | 'form'
25
- | 'modal'
26
- | 'action-group'
27
- | 'image-gallery' // Sprint 5
28
- | 'video' // Sprint 5
29
- | 'code' // Sprint 6
30
- | 'map' // Sprint 6
31
- | 'graph' // v6.0.0 — node-link viz (peer @antv/g6)
16
+ import type { ComponentType, LatLngPoint } from '@seed-ship/mcp-ui-spec'
17
+ export type { ComponentType, LatLngPoint }
32
18
 
33
19
  /**
34
20
  * Chart types (powered by Quickchart)
@@ -793,9 +779,9 @@ export interface CodeComponentParams {
793
779
  */
794
780
  export interface MapMarker {
795
781
  /**
796
- * Position as [latitude, longitude] tuple
782
+ * Position as a [latitude, longitude] tuple or { lat, lng } object
797
783
  */
798
- position: [number, number]
784
+ position: LatLngPoint
799
785
 
800
786
  /**
801
787
  * Tooltip text (shown on hover)
@@ -895,9 +881,9 @@ export interface MapLayer {
895
881
  */
896
882
  export interface MapComponentParams {
897
883
  /**
898
- * Initial center [lat, lng]
884
+ * Initial center as [lat, lng] or { lat, lng }
899
885
  */
900
- center?: [number, number]
886
+ center?: LatLngPoint
901
887
 
902
888
  /**
903
889
  * Initial zoom level (default: 13)
@@ -0,0 +1,20 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import type { LatLngPoint as SpecLatLngPoint } from '@seed-ship/mcp-ui-spec'
3
+ import type { LatLngPoint, MapComponentParams, MapMarker } from './index'
4
+
5
+ type Equal<A, B> = [A] extends [B] ? ([B] extends [A] ? true : never) : never
6
+ const _latLngParity: Equal<LatLngPoint, SpecLatLngPoint> = true
7
+ void _latLngParity
8
+
9
+ describe('public map types (UI-MAP-0a)', () => {
10
+ it('accepts both tuple and object LatLng forms', () => {
11
+ const tuple: LatLngPoint = [48.8566, 2.3522]
12
+ const object: LatLngPoint = { lat: 51.5074, lng: -0.1278 }
13
+ const marker: MapMarker = { position: object, tooltip: 'London' }
14
+ const params: MapComponentParams = { center: object, markers: [marker] }
15
+
16
+ expect(tuple).toEqual([48.8566, 2.3522])
17
+ expect(params.center).toEqual(object)
18
+ expect(params.markers?.[0].position).toEqual(object)
19
+ })
20
+ })
@@ -0,0 +1,30 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { escapeHtml } from './escape-html';
3
+
4
+ describe('escapeHtml', () => {
5
+ it('escapes all five significant HTML characters', () => {
6
+ expect(escapeHtml(`&<>"'`)).toBe('&amp;&lt;&gt;&quot;&#39;');
7
+ });
8
+
9
+ it('escapes the single quote (the case MapRenderer previously missed)', () => {
10
+ expect(escapeHtml("O'Brien")).toBe('O&#39;Brien');
11
+ });
12
+
13
+ it('escapes ampersand first so entities are not double-encoded incorrectly', () => {
14
+ expect(escapeHtml('a & b < c')).toBe('a &amp; b &lt; c');
15
+ });
16
+
17
+ it('neutralizes a script-injection attempt in a popup/tooltip value', () => {
18
+ expect(escapeHtml('<script>alert("x")</script>')).toBe(
19
+ '&lt;script&gt;alert(&quot;x&quot;)&lt;/script&gt;'
20
+ );
21
+ });
22
+
23
+ it('leaves a plain string untouched', () => {
24
+ expect(escapeHtml('Toulouse 31000')).toBe('Toulouse 31000');
25
+ });
26
+
27
+ it('returns an empty string for empty input', () => {
28
+ expect(escapeHtml('')).toBe('');
29
+ });
30
+ });
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Canonical HTML-escaper for untrusted payload values bound into HTML-string
3
+ * contexts (Leaflet marker popups/tooltips, G6 node/edge tooltips).
4
+ *
5
+ * Escapes the five significant characters — `& < > " '` — so a value is safe
6
+ * in both text-node and quoted-attribute positions. Pure + exported for tests.
7
+ *
8
+ * Consolidated (audit 2026-05-30 hygiene pass) from two previously-divergent
9
+ * private copies: MapRenderer's escaped `& < > "` (it MISSED the single quote),
10
+ * GraphRenderer's escaped all five. This single source removes that divergence.
11
+ */
12
+ export function escapeHtml(str: string): string {
13
+ return str.replace(/[&<>"']/g, (c) =>
14
+ c === '&'
15
+ ? '&amp;'
16
+ : c === '<'
17
+ ? '&lt;'
18
+ : c === '>'
19
+ ? '&gt;'
20
+ : c === '"'
21
+ ? '&quot;'
22
+ : '&#39;'
23
+ );
24
+ }