@seed-ship/mcp-ui-solid 5.5.1 → 5.7.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.
- package/CHANGELOG.md +86 -0
- package/dist/components/FormRenderer.cjs +13 -2
- package/dist/components/FormRenderer.cjs.map +1 -1
- package/dist/components/FormRenderer.d.ts.map +1 -1
- package/dist/components/FormRenderer.js +13 -2
- package/dist/components/FormRenderer.js.map +1 -1
- package/dist/components/GenerativeUIErrorBoundary.cjs +11 -0
- package/dist/components/GenerativeUIErrorBoundary.cjs.map +1 -1
- package/dist/components/GenerativeUIErrorBoundary.d.ts.map +1 -1
- package/dist/components/GenerativeUIErrorBoundary.js +11 -0
- package/dist/components/GenerativeUIErrorBoundary.js.map +1 -1
- package/dist/components/StreamingUIRenderer.cjs +49 -3
- package/dist/components/StreamingUIRenderer.cjs.map +1 -1
- package/dist/components/StreamingUIRenderer.d.ts.map +1 -1
- package/dist/components/StreamingUIRenderer.js +51 -5
- package/dist/components/StreamingUIRenderer.js.map +1 -1
- package/dist/components/UIResourceRenderer.cjs +102 -14
- package/dist/components/UIResourceRenderer.cjs.map +1 -1
- package/dist/components/UIResourceRenderer.d.ts +36 -1
- package/dist/components/UIResourceRenderer.d.ts.map +1 -1
- package/dist/components/UIResourceRenderer.js +104 -16
- package/dist/components/UIResourceRenderer.js.map +1 -1
- package/dist/context/MCPUITelemetryContext.cjs +25 -0
- package/dist/context/MCPUITelemetryContext.cjs.map +1 -0
- package/dist/context/MCPUITelemetryContext.d.ts +36 -0
- package/dist/context/MCPUITelemetryContext.d.ts.map +1 -0
- package/dist/context/MCPUITelemetryContext.js +25 -0
- package/dist/context/MCPUITelemetryContext.js.map +1 -0
- package/dist/index.cjs +7 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-ui-spec/dist/schemas.cjs +25 -6
- package/dist/mcp-ui-spec/dist/schemas.cjs.map +1 -1
- package/dist/mcp-ui-spec/dist/schemas.js +25 -6
- package/dist/mcp-ui-spec/dist/schemas.js.map +1 -1
- package/dist/services/telemetry.cjs +56 -0
- package/dist/services/telemetry.cjs.map +1 -0
- package/dist/services/telemetry.d.ts +87 -0
- package/dist/services/telemetry.d.ts.map +1 -0
- package/dist/services/telemetry.js +56 -0
- package/dist/services/telemetry.js.map +1 -0
- package/dist/services/validation.cjs +25 -24
- package/dist/services/validation.cjs.map +1 -1
- package/dist/services/validation.d.ts.map +1 -1
- package/dist/services/validation.js +26 -25
- package/dist/services/validation.js.map +1 -1
- package/dist/types/index.d.ts +26 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types.d.cts +26 -0
- package/dist/types.d.ts +26 -0
- package/docs/briefs/BRIEF-citations-in-table-cells.md +365 -0
- package/package.json +3 -3
- package/src/components/FormRenderer.tsx +14 -0
- package/src/components/GenerativeUIErrorBoundary.tsx +17 -1
- package/src/components/StreamingUIRenderer.tsx +55 -3
- package/src/components/TableRenderer.citation.test.tsx +157 -0
- package/src/components/UIResourceRenderer.tsx +212 -15
- package/src/context/MCPUITelemetryContext.test.tsx +119 -0
- package/src/context/MCPUITelemetryContext.tsx +71 -0
- package/src/index.ts +20 -0
- package/src/services/telemetry.test.ts +134 -0
- package/src/services/telemetry.ts +149 -0
- package/src/services/validation.ts +43 -41
- package/src/types/index.ts +30 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -6,6 +6,7 @@ const solidJs = require("solid-js");
|
|
|
6
6
|
const validation = require("../services/validation.cjs");
|
|
7
7
|
const GenerativeUIErrorBoundary = require("./GenerativeUIErrorBoundary.cjs");
|
|
8
8
|
const perf = require("../utils/perf.cjs");
|
|
9
|
+
const MCPUITelemetryContext = require("../context/MCPUITelemetryContext.cjs");
|
|
9
10
|
const GridRenderer = require("./GridRenderer.cjs");
|
|
10
11
|
const FooterRenderer = require("./FooterRenderer.cjs");
|
|
11
12
|
const CarouselRenderer = require("./CarouselRenderer.cjs");
|
|
@@ -220,7 +221,27 @@ function highlightQuery(html, query) {
|
|
|
220
221
|
return text.replace(regex, '<mark class="bg-yellow-200 dark:bg-[#222F49] text-inherit rounded px-0.5">$1</mark>');
|
|
221
222
|
});
|
|
222
223
|
}
|
|
223
|
-
function
|
|
224
|
+
function defaultCitationChip(pageNum, fileName, verified = true) {
|
|
225
|
+
const safeDocName = encodeURIComponent(fileName || "");
|
|
226
|
+
const label = fileName ? `${fileName} - ${pageNum}` : `${pageNum}`;
|
|
227
|
+
if (!verified) {
|
|
228
|
+
return `<span class="citation-ref inline-flex items-center gap-0.5 align-middle opacity-60"><span class="text-gray-500 line-through">[${label}]</span></span>`;
|
|
229
|
+
}
|
|
230
|
+
return ['<span class="citation-ref inline-flex items-center gap-0.5 align-middle">', `<span class="text-gray-500">[${label}]</span>`, '<button class="inline-flex items-center ml-0.5 px-1 py-0.5 text-xs bg-gray-800 hover:bg-gray-700 border border-gray-600 hover:border-teal-500 rounded cursor-pointer transition-colors align-middle"', ` data-citation-page="${pageNum}"`, ` data-citation-doc="${safeDocName}"`, ' data-citation-verified="true"', ` title="View source - ${label}">`, '<svg class="w-3 h-3" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>', "</button>", "</span>"].join("");
|
|
231
|
+
}
|
|
232
|
+
function transformCellCitations(text, ctx) {
|
|
233
|
+
let out = text.replace(new RegExp("(?<![p.])\\[(\\d{1,2})\\](?!\\()", "g"), "[📄 CITATION $1]");
|
|
234
|
+
out = out.replace(/\bCitations?\s*\[(\d+)\]/gi, "[📄 CITATION $1]");
|
|
235
|
+
out = out.replace(/\[CITATION\s+(\d+)\]/gi, "[📄 CITATION $1]");
|
|
236
|
+
return out.replace(/[【[]\s*📄\s*CITATION\s*(\d+)\s*[】\]]/gi, (_m, idStr) => {
|
|
237
|
+
const id = parseInt(idStr, 10);
|
|
238
|
+
const mapping = ctx.map[id] ?? ctx.map[String(id)];
|
|
239
|
+
if (ctx.render) return ctx.render(id, mapping);
|
|
240
|
+
if (mapping) return defaultCitationChip(mapping.page, mapping.file ?? "", true);
|
|
241
|
+
return Object.keys(ctx.map).length > 0 ? "" : `[réf. ${id}]`;
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
function renderCellValue(value, citationCtx) {
|
|
224
245
|
if (value === null || value === void 0) {
|
|
225
246
|
return "-";
|
|
226
247
|
}
|
|
@@ -256,20 +277,25 @@ function renderCellValue(value) {
|
|
|
256
277
|
ADD_ATTR: ["target", "rel"]
|
|
257
278
|
});
|
|
258
279
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
return purify_es.sanitize(strValue, {
|
|
262
|
-
ALLOWED_TAGS: ["a", "strong", "em", "b", "i", "code", "span", "br", "button", "svg", "path"],
|
|
263
|
-
ALLOWED_ATTR: ["href", "target", "rel", "class", "data-citation-page", "data-citation-source", "data-citation-doc", "data-citation-verified", "title", "fill", "stroke", "viewBox", "stroke-linecap", "stroke-linejoin", "stroke-width", "d"],
|
|
264
|
-
ADD_ATTR: ["target", "rel"]
|
|
265
|
-
});
|
|
280
|
+
if (citationCtx) {
|
|
281
|
+
strValue = transformCellCitations(strValue, citationCtx);
|
|
266
282
|
}
|
|
267
|
-
const hasMarkdown = /[*_
|
|
283
|
+
const hasMarkdown = /[*_`#]/.test(strValue);
|
|
268
284
|
if (hasMarkdown) {
|
|
269
285
|
const parsed = marked_esm.marked.parse(strValue, {
|
|
270
286
|
async: false
|
|
271
287
|
});
|
|
272
288
|
return purify_es.sanitize(parsed, {
|
|
289
|
+
ALLOWED_TAGS: ["a", "strong", "em", "b", "i", "code", "span", "br", "button", "svg", "path", "p", "ul", "ol", "li", "pre", "blockquote", "h1", "h2", "h3", "h4", "h5", "h6"],
|
|
290
|
+
ALLOWED_ATTR: ["href", "target", "rel", "class", "data-citation-page", "data-citation-source", "data-citation-doc", "data-citation-verified", "title", "fill", "stroke", "viewBox", "stroke-linecap", "stroke-linejoin", "stroke-width", "d"],
|
|
291
|
+
ADD_ATTR: ["target", "rel"]
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
const hasHtml = /<[a-z][\s\S]*>/i.test(strValue);
|
|
295
|
+
if (hasHtml) {
|
|
296
|
+
return purify_es.sanitize(strValue, {
|
|
297
|
+
ALLOWED_TAGS: ["a", "strong", "em", "b", "i", "code", "span", "br", "button", "svg", "path"],
|
|
298
|
+
ALLOWED_ATTR: ["href", "target", "rel", "class", "data-citation-page", "data-citation-source", "data-citation-doc", "data-citation-verified", "title", "fill", "stroke", "viewBox", "stroke-linecap", "stroke-linejoin", "stroke-width", "d"],
|
|
273
299
|
ADD_ATTR: ["target", "rel"]
|
|
274
300
|
});
|
|
275
301
|
}
|
|
@@ -278,6 +304,10 @@ function renderCellValue(value) {
|
|
|
278
304
|
function TableRenderer(props) {
|
|
279
305
|
const tableParams = props.component.params;
|
|
280
306
|
let scrollContainerRef;
|
|
307
|
+
const citationCtx = tableParams.citationMap ? {
|
|
308
|
+
map: tableParams.citationMap,
|
|
309
|
+
render: tableParams.citationRender
|
|
310
|
+
} : void 0;
|
|
281
311
|
const allRows = () => tableParams.rows || [];
|
|
282
312
|
const columns = () => tableParams.columns || [];
|
|
283
313
|
const [sortKey, setSortKey] = solidJs.createSignal(null);
|
|
@@ -518,7 +548,7 @@ ${dataRows}`;
|
|
|
518
548
|
},
|
|
519
549
|
children: (column) => (() => {
|
|
520
550
|
var _el$23 = web.getNextElement(_tmpl$10), _el$24 = _el$23.firstChild;
|
|
521
|
-
web.effect(() => web.setProperty(_el$24, "innerHTML", highlightQuery(renderCellValue(row[column.key]), debouncedQuery())));
|
|
551
|
+
web.effect(() => web.setProperty(_el$24, "innerHTML", highlightQuery(renderCellValue(row[column.key], citationCtx), debouncedQuery())));
|
|
522
552
|
return _el$23;
|
|
523
553
|
})()
|
|
524
554
|
}));
|
|
@@ -551,7 +581,7 @@ ${dataRows}`;
|
|
|
551
581
|
},
|
|
552
582
|
children: (column) => (() => {
|
|
553
583
|
var _el$27 = web.getNextElement(_tmpl$10), _el$28 = _el$27.firstChild;
|
|
554
|
-
web.effect(() => web.setProperty(_el$28, "innerHTML", highlightQuery(renderCellValue(row[column.key]), debouncedQuery())));
|
|
584
|
+
web.effect(() => web.setProperty(_el$28, "innerHTML", highlightQuery(renderCellValue(row[column.key], citationCtx), debouncedQuery())));
|
|
555
585
|
return _el$27;
|
|
556
586
|
})()
|
|
557
587
|
}));
|
|
@@ -1055,9 +1085,44 @@ function LinkRenderer(props) {
|
|
|
1055
1085
|
})();
|
|
1056
1086
|
}
|
|
1057
1087
|
function ComponentRenderer(props) {
|
|
1058
|
-
var _a, _b, _c;
|
|
1088
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1059
1089
|
perf.markRenderStart(props.component.id);
|
|
1060
|
-
|
|
1090
|
+
const telemetry = MCPUITelemetryContext.useTelemetry();
|
|
1091
|
+
solidJs.onMount(() => {
|
|
1092
|
+
perf.markRenderEnd(props.component.id);
|
|
1093
|
+
if (telemetry) {
|
|
1094
|
+
const ts = Date.now();
|
|
1095
|
+
telemetry.dispatch({
|
|
1096
|
+
type: "component:mounted",
|
|
1097
|
+
id: props.component.id,
|
|
1098
|
+
componentType: props.component.type,
|
|
1099
|
+
ts
|
|
1100
|
+
});
|
|
1101
|
+
if (typeof performance !== "undefined" && typeof performance.getEntriesByName === "function") {
|
|
1102
|
+
const entries = performance.getEntriesByName(`${perf.PERF_PREFIX}${props.component.id}:render`, "measure");
|
|
1103
|
+
const last = entries[entries.length - 1];
|
|
1104
|
+
if (last) {
|
|
1105
|
+
telemetry.dispatch({
|
|
1106
|
+
type: "component:rendered",
|
|
1107
|
+
id: props.component.id,
|
|
1108
|
+
componentType: props.component.type,
|
|
1109
|
+
durationMs: last.duration,
|
|
1110
|
+
ts
|
|
1111
|
+
});
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
});
|
|
1116
|
+
solidJs.onCleanup(() => {
|
|
1117
|
+
if (telemetry) {
|
|
1118
|
+
telemetry.dispatch({
|
|
1119
|
+
type: "component:unmounted",
|
|
1120
|
+
id: props.component.id,
|
|
1121
|
+
componentType: props.component.type,
|
|
1122
|
+
ts: Date.now()
|
|
1123
|
+
});
|
|
1124
|
+
}
|
|
1125
|
+
});
|
|
1061
1126
|
const validation$1 = validation.validateComponent(props.component);
|
|
1062
1127
|
if (!validation$1.valid) {
|
|
1063
1128
|
(_a = props.onError) == null ? void 0 : _a.call(props, {
|
|
@@ -1066,8 +1131,18 @@ function ComponentRenderer(props) {
|
|
|
1066
1131
|
componentId: props.component.id,
|
|
1067
1132
|
details: validation$1.errors
|
|
1068
1133
|
});
|
|
1134
|
+
if (telemetry) {
|
|
1135
|
+
telemetry.dispatch({
|
|
1136
|
+
type: "validation:failed",
|
|
1137
|
+
id: props.component.id,
|
|
1138
|
+
componentType: props.component.type,
|
|
1139
|
+
errorCount: ((_b = validation$1.errors) == null ? void 0 : _b.length) ?? 0,
|
|
1140
|
+
firstErrorCode: ((_d = (_c = validation$1.errors) == null ? void 0 : _c[0]) == null ? void 0 : _d.code) ?? null,
|
|
1141
|
+
ts: Date.now()
|
|
1142
|
+
});
|
|
1143
|
+
}
|
|
1069
1144
|
const mode = props.errorMode ?? "block";
|
|
1070
|
-
const firstError = ((
|
|
1145
|
+
const firstError = ((_f = (_e = validation$1.errors) == null ? void 0 : _e[0]) == null ? void 0 : _f.message) || "Unknown validation error";
|
|
1071
1146
|
if (mode === "silent") {
|
|
1072
1147
|
return null;
|
|
1073
1148
|
}
|
|
@@ -1319,7 +1394,20 @@ function ActionRenderer(props) {
|
|
|
1319
1394
|
execute,
|
|
1320
1395
|
isExecuting
|
|
1321
1396
|
} = useAction.useAction();
|
|
1397
|
+
const telemetry = MCPUITelemetryContext.useTelemetry();
|
|
1398
|
+
function dispatchTelemetry() {
|
|
1399
|
+
if (!telemetry) return;
|
|
1400
|
+
const actionName = params.toolName ?? params.action ?? "unknown";
|
|
1401
|
+
telemetry.dispatch({
|
|
1402
|
+
type: "action:dispatched",
|
|
1403
|
+
id: props.component.id,
|
|
1404
|
+
componentType: "action",
|
|
1405
|
+
actionName,
|
|
1406
|
+
ts: Date.now()
|
|
1407
|
+
});
|
|
1408
|
+
}
|
|
1322
1409
|
const handleClick = async (e) => {
|
|
1410
|
+
dispatchTelemetry();
|
|
1323
1411
|
if (params.action === "tool-call" && params.toolName) {
|
|
1324
1412
|
e.preventDefault();
|
|
1325
1413
|
await execute(params.toolName, params.params || {});
|