@seed-ship/mcp-ui-solid 6.4.0 → 6.5.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 (35) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/dist/components/UIResourceRenderer.cjs +40 -10
  3. package/dist/components/UIResourceRenderer.cjs.map +1 -1
  4. package/dist/components/UIResourceRenderer.d.ts +20 -0
  5. package/dist/components/UIResourceRenderer.d.ts.map +1 -1
  6. package/dist/components/UIResourceRenderer.js +42 -12
  7. package/dist/components/UIResourceRenderer.js.map +1 -1
  8. package/dist/index.cjs +4 -0
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +3 -0
  11. package/dist/index.d.ts +3 -0
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +4 -0
  14. package/dist/index.js.map +1 -1
  15. package/dist/utils/duplicate-mount-registry.cjs +27 -0
  16. package/dist/utils/duplicate-mount-registry.cjs.map +1 -0
  17. package/dist/utils/duplicate-mount-registry.d.ts +84 -0
  18. package/dist/utils/duplicate-mount-registry.d.ts.map +1 -0
  19. package/dist/utils/duplicate-mount-registry.js +27 -0
  20. package/dist/utils/duplicate-mount-registry.js.map +1 -0
  21. package/dist/utils/stable-key.cjs +41 -0
  22. package/dist/utils/stable-key.cjs.map +1 -0
  23. package/dist/utils/stable-key.d.ts +33 -0
  24. package/dist/utils/stable-key.d.ts.map +1 -0
  25. package/dist/utils/stable-key.js +41 -0
  26. package/dist/utils/stable-key.js.map +1 -0
  27. package/package.json +1 -1
  28. package/src/components/UIResourceRenderer.identity.test.tsx +161 -0
  29. package/src/components/UIResourceRenderer.tsx +63 -2
  30. package/src/index.ts +8 -0
  31. package/src/utils/duplicate-mount-registry.test.ts +82 -0
  32. package/src/utils/duplicate-mount-registry.ts +113 -0
  33. package/src/utils/stable-key.test.ts +96 -0
  34. package/src/utils/stable-key.ts +91 -0
  35. package/tsconfig.tsbuildinfo +1 -1
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { Component } from 'solid-js';
6
6
  import type { UIComponent, UILayout, RendererError } from '../types';
7
+ import { type DuplicateMountInfo } from '../utils/duplicate-mount-registry';
7
8
  /**
8
9
  * How `<UIResourceRenderer>` reacts when `validateComponent()` rejects a
9
10
  * component (v5.4.0).
@@ -59,6 +60,25 @@ export interface UIResourceRendererProps {
59
60
  * graph, map, video, carousel, image-gallery, code.
60
61
  */
61
62
  toolbarVariant?: 'hover' | 'always-visible';
63
+ /**
64
+ * Per-instance hook fired when this renderer mounts a content key that
65
+ * is already mounted elsewhere in the document (v6.5.0 — closes Demande 2
66
+ * of `BRIEF-MCPUI-2026-05-10.md`).
67
+ *
68
+ * The key comes from `getUiResourceStableKey(content)` — `content.id` if
69
+ * provided, else a content hash. The reporter fires every time the
70
+ * concurrent mount count crosses 2+ ; consumers decide what to do
71
+ * (`console.warn`, telemetry beacon, debug overlay, …). The renderer
72
+ * never deduplicates visually on its own.
73
+ */
74
+ onMountDuplicate?: (info: DuplicateMountInfo) => void;
75
+ /**
76
+ * When `true`, log duplicate mounts to `console.warn` from this instance
77
+ * even when the global `isDebugEnabled()` flag is off. Use to opt-in to
78
+ * console noise on a single suspect surface without flipping the global
79
+ * debug switch (v6.5.0).
80
+ */
81
+ debugDuplicateMounts?: boolean;
62
82
  }
63
83
  /**
64
84
  * Smart cell value renderer that handles markdown links and other formats
@@ -1 +1 @@
1
- {"version":3,"file":"UIResourceRenderer.d.ts","sourceRoot":"","sources":["../../src/components/UIResourceRenderer.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,SAAS,EAAyE,MAAM,UAAU,CAAA;AAE3G,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,EAA0B,MAAM,UAAU,CAAA;AAM5F;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,aAAa,GAAG,QAAQ,CAAA;AAgEpE;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,OAAO,EAAE,WAAW,GAAG,QAAQ,CAAA;IAE/B;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAElB;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;IAExC;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IAEd;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,mBAAmB,CAAA;IAE/B;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAAA;CAC5C;AAmJD;;GAEG;AACH;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAYlE;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC,CAAA;IACjG;;;;;OAKG;IACH,MAAM,CAAC,EAAE,CACP,EAAE,EAAE,MAAM,EACV,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,GAAG,SAAS,KACrF,MAAM,CAAA;CACZ;AA8DD,wBAAgB,eAAe,CAAC,KAAK,EAAE,GAAG,EAAE,WAAW,CAAC,EAAE,WAAW,GAAG,MAAM,CAkG7E;AAkqCD;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAAS,CAAC,uBAAuB,CA6GjE,CAAA"}
1
+ {"version":3,"file":"UIResourceRenderer.d.ts","sourceRoot":"","sources":["../../src/components/UIResourceRenderer.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,SAAS,EAAyE,MAAM,UAAU,CAAA;AAE3G,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,EAA0B,MAAM,UAAU,CAAA;AAM5F,OAAO,EAIL,KAAK,kBAAkB,EACxB,MAAM,mCAAmC,CAAA;AAG1C;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,aAAa,GAAG,QAAQ,CAAA;AAgEpE;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,OAAO,EAAE,WAAW,GAAG,QAAQ,CAAA;IAE/B;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAElB;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;IAExC;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IAEd;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,mBAAmB,CAAA;IAE/B;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAAA;IAE3C;;;;;;;;;;OAUG;IACH,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAA;IAErD;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B;AAmJD;;GAEG;AACH;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAYlE;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC,CAAA;IACjG;;;;;OAKG;IACH,MAAM,CAAC,EAAE,CACP,EAAE,EAAE,MAAM,EACV,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,GAAG,SAAS,KACrF,MAAM,CAAA;CACZ;AA8DD,wBAAgB,eAAe,CAAC,KAAK,EAAE,GAAG,EAAE,WAAW,CAAC,EAAE,WAAW,GAAG,MAAM,CAkG7E;AAkqCD;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAAS,CAAC,uBAAuB,CA6IjE,CAAA"}
@@ -1,9 +1,12 @@
1
- import { delegateEvents, createComponent, getNextElement, template, getNextMarker, insert, effect, style, className, setProperty, setAttribute, runHydrationEvents, memo, isServer, use, addEventListener, classList, setStyleProperty } from "solid-js/web";
1
+ import { delegateEvents, createComponent, getNextElement, template, getNextMarker, spread, mergeProps, insert, effect, style, setAttribute, runHydrationEvents, setProperty, className, memo, isServer, use, addEventListener, classList, setStyleProperty } from "solid-js/web";
2
2
  import purify from "../node_modules/.pnpm/dompurify@3.4.1/node_modules/dompurify/dist/purify.es.js";
3
- import { createMemo, For, Show, onMount, onCleanup, createSignal, createEffect } from "solid-js";
3
+ import { createMemo, onMount, onCleanup, For, Show, createSignal, createEffect } from "solid-js";
4
4
  import { validateComponent, getIframeSandbox, DEFAULT_RESOURCE_LIMITS } from "../services/validation.js";
5
5
  import { GenerativeUIErrorBoundary } from "./GenerativeUIErrorBoundary.js";
6
6
  import { markRenderStart, markRenderEnd, PERF_PREFIX } from "../utils/perf.js";
7
+ import { isDebugEnabled } from "../utils/logger.js";
8
+ import { getUiResourceStableKey } from "../utils/stable-key.js";
9
+ import { _registerMount, _unregisterMount, getDuplicateMountReporter } from "../utils/duplicate-mount-registry.js";
7
10
  import { useTelemetry } from "../context/MCPUITelemetryContext.js";
8
11
  import { GridRenderer } from "./GridRenderer.js";
9
12
  import { FooterRenderer } from "./FooterRenderer.js";
@@ -1726,6 +1729,23 @@ const UIResourceRenderer = (props) => {
1726
1729
  };
1727
1730
  });
1728
1731
  const layoutData = layout();
1732
+ const isLayoutContent = !("type" in props.content) || props.content.type === "composite";
1733
+ const outerKey = createMemo(() => getUiResourceStableKey(props.content));
1734
+ onMount(() => {
1735
+ var _a, _b;
1736
+ const key = outerKey();
1737
+ const info = _registerMount(key);
1738
+ if (info.count > 1) {
1739
+ (_a = props.onMountDuplicate) == null ? void 0 : _a.call(props, info);
1740
+ (_b = getDuplicateMountReporter()) == null ? void 0 : _b(info);
1741
+ if (isDebugEnabled() || props.debugDuplicateMounts) {
1742
+ console.warn("[mcp-ui] duplicate UIResourceRenderer mount", info);
1743
+ }
1744
+ }
1745
+ });
1746
+ onCleanup(() => {
1747
+ _unregisterMount(outerKey());
1748
+ });
1729
1749
  const renderComponent = (component, onError) => createComponent(ComponentRenderer, {
1730
1750
  component,
1731
1751
  onError,
@@ -1740,6 +1760,15 @@ const UIResourceRenderer = (props) => {
1740
1760
  renderComponent,
1741
1761
  get children() {
1742
1762
  var _el$232 = getNextElement(_tmpl$53), _el$233 = _el$232.firstChild, _el$234 = _el$233.nextSibling, [_el$235, _co$50] = getNextMarker(_el$234.nextSibling);
1763
+ spread(_el$232, mergeProps({
1764
+ get ["class"]() {
1765
+ return `w-full ${props.class || ""}`;
1766
+ }
1767
+ }, () => isLayoutContent ? {
1768
+ "data-mcp-ui-layout-id": outerKey()
1769
+ } : {
1770
+ "data-mcp-ui-component-id": outerKey()
1771
+ }), false, true);
1743
1772
  insert(_el$233, createComponent(For, {
1744
1773
  get each() {
1745
1774
  return layoutData.components;
@@ -1758,7 +1787,15 @@ const UIResourceRenderer = (props) => {
1758
1787
  return props.toolbarVariant;
1759
1788
  }
1760
1789
  }));
1761
- effect((_$p) => style(_el$236, getGridStyleString(component), _$p));
1790
+ effect((_p$) => {
1791
+ var _v$43 = getGridStyleString(component), _v$44 = getUiResourceStableKey(component);
1792
+ _p$.e = style(_el$236, _v$43, _p$.e);
1793
+ _v$44 !== _p$.t && setAttribute(_el$236, "data-mcp-ui-component-id", _p$.t = _v$44);
1794
+ return _p$;
1795
+ }, {
1796
+ e: void 0,
1797
+ t: void 0
1798
+ });
1762
1799
  return _el$236;
1763
1800
  })()
1764
1801
  }));
@@ -1774,15 +1811,8 @@ const UIResourceRenderer = (props) => {
1774
1811
  });
1775
1812
  }
1776
1813
  }), _el$235, _co$50);
1777
- effect((_p$) => {
1778
- var _v$43 = `w-full ${props.class || ""}`, _v$44 = gridContainerStyle();
1779
- _v$43 !== _p$.e && className(_el$232, _p$.e = _v$43);
1780
- _p$.t = style(_el$233, _v$44, _p$.t);
1781
- return _p$;
1782
- }, {
1783
- e: void 0,
1784
- t: void 0
1785
- });
1814
+ effect((_$p) => style(_el$233, gridContainerStyle(), _$p));
1815
+ runHydrationEvents();
1786
1816
  return _el$232;
1787
1817
  }
1788
1818
  });