@seed-ship/mcp-ui-solid 1.0.28 → 1.0.31
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/dist/components/GenerativeUIErrorBoundary.cjs.map +1 -0
- package/dist/components/GenerativeUIErrorBoundary.js.map +1 -0
- package/dist/components/StreamingUIRenderer.cjs.map +1 -0
- package/dist/components/StreamingUIRenderer.js.map +1 -0
- package/dist/{mcp-ui-solid/src/components → components}/UIResourceRenderer.cjs +102 -97
- package/dist/components/UIResourceRenderer.cjs.map +1 -0
- package/dist/components/UIResourceRenderer.d.ts +0 -11
- package/dist/components/UIResourceRenderer.d.ts.map +1 -1
- package/dist/{mcp-ui-solid/src/components → components}/UIResourceRenderer.js +102 -97
- package/dist/components/UIResourceRenderer.js.map +1 -0
- package/dist/components.cjs +3 -3
- package/dist/components.d.ts +12 -0
- package/dist/components.js +3 -3
- package/dist/hooks/useStreamingUI.cjs.map +1 -0
- package/dist/hooks/useStreamingUI.js.map +1 -0
- package/dist/hooks.cjs +1 -1
- package/dist/hooks.d.ts +8 -0
- package/dist/hooks.js +1 -1
- package/dist/index.cjs +6 -6
- package/dist/index.js +6 -6
- package/dist/node_modules/.pnpm/dompurify@3.3.0/node_modules/dompurify/dist/purify.es.cjs +1006 -0
- package/dist/node_modules/.pnpm/dompurify@3.3.0/node_modules/dompurify/dist/purify.es.cjs.map +1 -0
- package/dist/node_modules/.pnpm/dompurify@3.3.0/node_modules/dompurify/dist/purify.es.js +1007 -0
- package/dist/node_modules/.pnpm/dompurify@3.3.0/node_modules/dompurify/dist/purify.es.js.map +1 -0
- package/dist/services/component-registry.cjs.map +1 -0
- package/dist/services/component-registry.js.map +1 -0
- package/dist/services/validation.cjs.map +1 -0
- package/dist/services/validation.js.map +1 -0
- package/dist/types-export.cjs +2 -0
- package/dist/types-export.cjs.map +1 -0
- package/dist/types-export.d.ts +13 -0
- package/dist/types-export.d.ts.map +1 -0
- package/dist/types-export.js +2 -0
- package/dist/types-export.js.map +1 -0
- package/dist/types.d.ts +265 -0
- package/dist/utils/logger.cjs.map +1 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/validation.cjs +1 -1
- package/dist/validation.js +1 -1
- package/package.json +25 -23
- package/src/components/ActionRenderer.tsx +33 -0
- package/src/components/ArtifactRenderer.tsx +54 -0
- package/src/components/CarouselRenderer.tsx +77 -0
- package/src/components/FooterRenderer.tsx +66 -0
- package/src/components/GenerativeUIErrorBoundary.tsx +259 -0
- package/src/components/StreamingUIRenderer.tsx +327 -0
- package/src/components/UIResourceRenderer.tsx +573 -0
- package/src/components/index.ts +14 -0
- package/src/hooks/index.ts +14 -0
- package/src/hooks/useStreamingUI.ts +447 -0
- package/src/index.test.ts +36 -0
- package/src/index.ts +70 -0
- package/src/services/component-registry.ts +378 -0
- package/src/services/index.ts +9 -0
- package/src/services/validation.ts +472 -0
- package/src/types/index.ts +320 -0
- package/src/types-export.ts +31 -0
- package/src/utils/logger.ts +74 -0
- package/src/validation.ts +38 -0
- package/src/vite-env.d.ts +11 -0
- package/tsconfig.json +20 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/vite.config.ts +52 -0
- package/vite.config.ts.timestamp-1763266929437-a71eed80b91318.mjs +45 -0
- package/vitest.config.ts +10 -0
- package/dist/mcp-ui-solid/src/components/GenerativeUIErrorBoundary.cjs.map +0 -1
- package/dist/mcp-ui-solid/src/components/GenerativeUIErrorBoundary.js.map +0 -1
- package/dist/mcp-ui-solid/src/components/StreamingUIRenderer.cjs.map +0 -1
- package/dist/mcp-ui-solid/src/components/StreamingUIRenderer.js.map +0 -1
- package/dist/mcp-ui-solid/src/components/UIResourceRenderer.cjs.map +0 -1
- package/dist/mcp-ui-solid/src/components/UIResourceRenderer.js.map +0 -1
- package/dist/mcp-ui-solid/src/hooks/useStreamingUI.cjs.map +0 -1
- package/dist/mcp-ui-solid/src/hooks/useStreamingUI.js.map +0 -1
- package/dist/mcp-ui-solid/src/services/component-registry.cjs.map +0 -1
- package/dist/mcp-ui-solid/src/services/component-registry.js.map +0 -1
- package/dist/mcp-ui-solid/src/services/validation.cjs.map +0 -1
- package/dist/mcp-ui-solid/src/services/validation.js.map +0 -1
- package/dist/mcp-ui-solid/src/utils/logger.cjs.map +0 -1
- package/dist/mcp-ui-solid/src/utils/logger.js.map +0 -1
- /package/dist/{mcp-ui-solid/src/components → components}/GenerativeUIErrorBoundary.cjs +0 -0
- /package/dist/{mcp-ui-solid/src/components → components}/GenerativeUIErrorBoundary.js +0 -0
- /package/dist/{mcp-ui-solid/src/components → components}/StreamingUIRenderer.cjs +0 -0
- /package/dist/{mcp-ui-solid/src/components → components}/StreamingUIRenderer.js +0 -0
- /package/dist/{mcp-ui-solid/src/hooks → hooks}/useStreamingUI.cjs +0 -0
- /package/dist/{mcp-ui-solid/src/hooks → hooks}/useStreamingUI.js +0 -0
- /package/dist/{mcp-ui-solid/src/services → services}/component-registry.cjs +0 -0
- /package/dist/{mcp-ui-solid/src/services → services}/component-registry.js +0 -0
- /package/dist/{mcp-ui-solid/src/services → services}/validation.cjs +0 -0
- /package/dist/{mcp-ui-solid/src/services → services}/validation.js +0 -0
- /package/dist/{mcp-ui-solid/src/utils → utils}/logger.cjs +0 -0
- /package/dist/{mcp-ui-solid/src/utils → utils}/logger.js +0 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generative MCP UI - Type Definitions
|
|
3
|
+
* Phase 0-3 Implementation
|
|
4
|
+
*
|
|
5
|
+
* Defines the contract for LLM-generated UI components
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Component types supported by the renderer
|
|
9
|
+
*/
|
|
10
|
+
export type ComponentType = 'chart' | 'table' | 'metric' | 'text' | 'grid' | 'iframe' | 'image' | 'link' | 'action';
|
|
11
|
+
/**
|
|
12
|
+
* Chart types (powered by Quickchart)
|
|
13
|
+
*/
|
|
14
|
+
export type ChartType = 'bar' | 'line' | 'pie' | 'doughnut' | 'radar' | 'scatter';
|
|
15
|
+
/**
|
|
16
|
+
* Grid layout specification (12-column system)
|
|
17
|
+
*/
|
|
18
|
+
export interface GridPosition {
|
|
19
|
+
/**
|
|
20
|
+
* Column start (1-12)
|
|
21
|
+
*/
|
|
22
|
+
colStart: number;
|
|
23
|
+
/**
|
|
24
|
+
* Column span (1-12)
|
|
25
|
+
*/
|
|
26
|
+
colSpan: number;
|
|
27
|
+
/**
|
|
28
|
+
* Row start (1-based, auto-increment if not specified)
|
|
29
|
+
*/
|
|
30
|
+
rowStart?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Row span (default: 1)
|
|
33
|
+
*/
|
|
34
|
+
rowSpan?: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Component resource limits (SECURITY)
|
|
38
|
+
*/
|
|
39
|
+
export interface ResourceLimits {
|
|
40
|
+
/**
|
|
41
|
+
* Max data points per chart (default: 1000)
|
|
42
|
+
*/
|
|
43
|
+
maxDataPoints: number;
|
|
44
|
+
/**
|
|
45
|
+
* Max table rows (default: 100, pagination required)
|
|
46
|
+
*/
|
|
47
|
+
maxTableRows: number;
|
|
48
|
+
/**
|
|
49
|
+
* Max payload size in bytes (default: 50KB)
|
|
50
|
+
*/
|
|
51
|
+
maxPayloadSize: number;
|
|
52
|
+
/**
|
|
53
|
+
* Iframe render timeout in ms (default: 5000ms)
|
|
54
|
+
*/
|
|
55
|
+
renderTimeout: number;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Chart component parameters
|
|
59
|
+
*/
|
|
60
|
+
export interface ChartComponentParams {
|
|
61
|
+
type: ChartType;
|
|
62
|
+
title?: string;
|
|
63
|
+
data: {
|
|
64
|
+
labels: string[];
|
|
65
|
+
datasets: Array<{
|
|
66
|
+
label: string;
|
|
67
|
+
data: number[];
|
|
68
|
+
backgroundColor?: string | string[];
|
|
69
|
+
borderColor?: string | string[];
|
|
70
|
+
borderWidth?: number;
|
|
71
|
+
}>;
|
|
72
|
+
};
|
|
73
|
+
options?: {
|
|
74
|
+
responsive?: boolean;
|
|
75
|
+
maintainAspectRatio?: boolean;
|
|
76
|
+
tension?: number;
|
|
77
|
+
scales?: any;
|
|
78
|
+
plugins?: any;
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Table component parameters
|
|
83
|
+
*/
|
|
84
|
+
export interface TableComponentParams {
|
|
85
|
+
title?: string;
|
|
86
|
+
columns: Array<{
|
|
87
|
+
key: string;
|
|
88
|
+
label: string;
|
|
89
|
+
sortable?: boolean;
|
|
90
|
+
width?: string;
|
|
91
|
+
}>;
|
|
92
|
+
rows: Array<Record<string, any>>;
|
|
93
|
+
pagination?: {
|
|
94
|
+
currentPage: number;
|
|
95
|
+
pageSize: number;
|
|
96
|
+
totalRows: number;
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Metric card component parameters
|
|
101
|
+
*/
|
|
102
|
+
export interface MetricComponentParams {
|
|
103
|
+
title: string;
|
|
104
|
+
value: string | number;
|
|
105
|
+
unit?: string;
|
|
106
|
+
trend?: {
|
|
107
|
+
value: number;
|
|
108
|
+
direction: 'up' | 'down' | 'neutral';
|
|
109
|
+
};
|
|
110
|
+
subtitle?: string;
|
|
111
|
+
icon?: string;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Text component parameters
|
|
115
|
+
*/
|
|
116
|
+
export interface TextComponentParams {
|
|
117
|
+
content: string;
|
|
118
|
+
markdown?: boolean;
|
|
119
|
+
className?: string;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Action component parameters
|
|
123
|
+
*/
|
|
124
|
+
export interface ActionComponentParams {
|
|
125
|
+
label: string;
|
|
126
|
+
type: 'button' | 'link';
|
|
127
|
+
action: 'tool-call' | 'link' | 'submit';
|
|
128
|
+
toolName?: string;
|
|
129
|
+
params?: Record<string, any>;
|
|
130
|
+
url?: string;
|
|
131
|
+
variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger';
|
|
132
|
+
size?: 'sm' | 'md' | 'lg';
|
|
133
|
+
icon?: string;
|
|
134
|
+
disabled?: boolean;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* UI Component definition (generated by LLM)
|
|
138
|
+
*/
|
|
139
|
+
export interface UIComponent {
|
|
140
|
+
/**
|
|
141
|
+
* Unique component ID
|
|
142
|
+
*/
|
|
143
|
+
id: string;
|
|
144
|
+
/**
|
|
145
|
+
* Component type
|
|
146
|
+
*/
|
|
147
|
+
type: ComponentType;
|
|
148
|
+
/**
|
|
149
|
+
* Grid position
|
|
150
|
+
*/
|
|
151
|
+
position: GridPosition;
|
|
152
|
+
/**
|
|
153
|
+
* Component parameters (type-specific)
|
|
154
|
+
*/
|
|
155
|
+
params: ChartComponentParams | TableComponentParams | MetricComponentParams | TextComponentParams | ActionComponentParams;
|
|
156
|
+
/**
|
|
157
|
+
* Metadata for observability
|
|
158
|
+
*/
|
|
159
|
+
metadata?: {
|
|
160
|
+
generatedAt: string;
|
|
161
|
+
llmModel?: string;
|
|
162
|
+
confidence?: number;
|
|
163
|
+
toolsUsed?: string[];
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* UI Layout (collection of components)
|
|
168
|
+
*/
|
|
169
|
+
export interface UILayout {
|
|
170
|
+
/**
|
|
171
|
+
* Layout ID
|
|
172
|
+
*/
|
|
173
|
+
id: string;
|
|
174
|
+
/**
|
|
175
|
+
* Components in the layout
|
|
176
|
+
*/
|
|
177
|
+
components: UIComponent[];
|
|
178
|
+
/**
|
|
179
|
+
* Grid configuration
|
|
180
|
+
*/
|
|
181
|
+
grid: {
|
|
182
|
+
columns: number;
|
|
183
|
+
gap: string;
|
|
184
|
+
minRowHeight?: string;
|
|
185
|
+
};
|
|
186
|
+
/**
|
|
187
|
+
* Layout metadata
|
|
188
|
+
*/
|
|
189
|
+
metadata?: {
|
|
190
|
+
query: string;
|
|
191
|
+
generatedAt: string;
|
|
192
|
+
llmModel?: string;
|
|
193
|
+
totalComponents: number;
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Component registry entry
|
|
198
|
+
*/
|
|
199
|
+
export interface ComponentRegistryEntry {
|
|
200
|
+
/**
|
|
201
|
+
* Component type identifier
|
|
202
|
+
*/
|
|
203
|
+
type: ComponentType;
|
|
204
|
+
/**
|
|
205
|
+
* Component name
|
|
206
|
+
*/
|
|
207
|
+
name: string;
|
|
208
|
+
/**
|
|
209
|
+
* Component description (for LLM context)
|
|
210
|
+
*/
|
|
211
|
+
description: string;
|
|
212
|
+
/**
|
|
213
|
+
* JSON schema for validation
|
|
214
|
+
*/
|
|
215
|
+
schema: any;
|
|
216
|
+
/**
|
|
217
|
+
* Example usage (for LLM few-shot prompting)
|
|
218
|
+
*/
|
|
219
|
+
examples: Array<{
|
|
220
|
+
query: string;
|
|
221
|
+
component: UIComponent;
|
|
222
|
+
}>;
|
|
223
|
+
/**
|
|
224
|
+
* Resource limits
|
|
225
|
+
*/
|
|
226
|
+
limits: ResourceLimits;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Component validation result
|
|
230
|
+
*/
|
|
231
|
+
export interface ValidationResult {
|
|
232
|
+
valid: boolean;
|
|
233
|
+
errors?: Array<{
|
|
234
|
+
path: string;
|
|
235
|
+
message: string;
|
|
236
|
+
code: string;
|
|
237
|
+
}>;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Renderer error types
|
|
241
|
+
*/
|
|
242
|
+
export type RendererErrorType = 'validation' | 'render' | 'timeout' | 'resource_limit' | 'network' | 'security';
|
|
243
|
+
/**
|
|
244
|
+
* Renderer error
|
|
245
|
+
*/
|
|
246
|
+
export interface RendererError {
|
|
247
|
+
type: RendererErrorType;
|
|
248
|
+
message: string;
|
|
249
|
+
componentId?: string;
|
|
250
|
+
details?: any;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Streaming event types (Phase 2)
|
|
254
|
+
*/
|
|
255
|
+
export type StreamEventType = 'status' | 'component-start' | 'component' | 'component-complete' | 'error' | 'complete';
|
|
256
|
+
/**
|
|
257
|
+
* Streaming event (Phase 2)
|
|
258
|
+
*/
|
|
259
|
+
export interface StreamEvent {
|
|
260
|
+
event: StreamEventType;
|
|
261
|
+
data: any;
|
|
262
|
+
sequenceId?: number;
|
|
263
|
+
timestamp: string;
|
|
264
|
+
}
|
|
265
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.cjs","sources":["../../src/utils/logger.ts"],"sourcesContent":["/**\n * Simple internal logger utility\n *\n * Provides basic logging functionality for the package.\n * Consumers can disable logging by setting NODE_ENV=production\n * or by implementing their own logging solution.\n */\n\nconst isDev = typeof process !== 'undefined' && process.env.NODE_ENV !== 'production'\n\nexport interface Logger {\n info(message: string, context?: Record<string, unknown>): void\n warn(message: string, context?: Record<string, unknown>): void\n error(message: string, context?: Record<string, unknown>): void\n debug(message: string, context?: Record<string, unknown>): void\n}\n\nfunction formatLogMessage(\n feature: string,\n message: string,\n context?: Record<string, unknown>\n): string {\n const contextStr = context ? ` ${JSON.stringify(context)}` : ''\n return `[@seed-ship/mcp-ui-solid:${feature}] ${message}${contextStr}`\n}\n\n/**\n * Creates a feature-scoped logger\n *\n * @param feature - Feature name for log prefixing\n * @returns Logger instance\n *\n * @example\n * ```typescript\n * const logger = createLogger('my-component')\n * logger.info('Component mounted', { componentId: '123' })\n * ```\n */\nexport function createLogger(feature: string): Logger {\n return {\n info(message: string, context?: Record<string, unknown>) {\n if (isDev) {\n console.info(formatLogMessage(feature, message, context))\n }\n },\n\n warn(message: string, context?: Record<string, unknown>) {\n if (isDev) {\n console.warn(formatLogMessage(feature, message, context))\n }\n },\n\n error(message: string, context?: Record<string, unknown>) {\n // Always log errors, even in production\n console.error(formatLogMessage(feature, message, context))\n },\n\n debug(message: string, context?: Record<string, unknown>) {\n if (isDev) {\n console.debug(formatLogMessage(feature, message, context))\n }\n },\n }\n}\n\n/**\n * No-op logger for testing or when logging is disabled\n */\nexport const noopLogger: Logger = {\n info: () => {},\n warn: () => {},\n error: () => {},\n debug: () => {},\n}\n"],"names":[],"mappings":";;AAQA,MAAM,QAAQ,OAAO,YAAY,eAAe,QAAQ,IAAI,aAAa;AASzE,SAAS,iBACP,SACA,SACA,SACQ;AACR,QAAM,aAAa,UAAU,IAAI,KAAK,UAAU,OAAO,CAAC,KAAK;AAC7D,SAAO,4BAA4B,OAAO,KAAK,OAAO,GAAG,UAAU;AACrE;AAcO,SAAS,aAAa,SAAyB;AACpD,SAAO;AAAA,IACL,KAAK,SAAiB,SAAmC;AACvD,UAAI,OAAO;AACT,gBAAQ,KAAK,iBAAiB,SAAS,SAAS,OAAO,CAAC;AAAA,MAC1D;AAAA,IACF;AAAA,IAEA,KAAK,SAAiB,SAAmC;AACvD,UAAI,OAAO;AACT,gBAAQ,KAAK,iBAAiB,SAAS,SAAS,OAAO,CAAC;AAAA,MAC1D;AAAA,IACF;AAAA,IAEA,MAAM,SAAiB,SAAmC;AAExD,cAAQ,MAAM,iBAAiB,SAAS,SAAS,OAAO,CAAC;AAAA,IAC3D;AAAA,IAEA,MAAM,SAAiB,SAAmC;AACxD,UAAI,OAAO;AACT,gBAAQ,MAAM,iBAAiB,SAAS,SAAS,OAAO,CAAC;AAAA,MAC3D;AAAA,IACF;AAAA,EAAA;AAEJ;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sources":["../../src/utils/logger.ts"],"sourcesContent":["/**\n * Simple internal logger utility\n *\n * Provides basic logging functionality for the package.\n * Consumers can disable logging by setting NODE_ENV=production\n * or by implementing their own logging solution.\n */\n\nconst isDev = typeof process !== 'undefined' && process.env.NODE_ENV !== 'production'\n\nexport interface Logger {\n info(message: string, context?: Record<string, unknown>): void\n warn(message: string, context?: Record<string, unknown>): void\n error(message: string, context?: Record<string, unknown>): void\n debug(message: string, context?: Record<string, unknown>): void\n}\n\nfunction formatLogMessage(\n feature: string,\n message: string,\n context?: Record<string, unknown>\n): string {\n const contextStr = context ? ` ${JSON.stringify(context)}` : ''\n return `[@seed-ship/mcp-ui-solid:${feature}] ${message}${contextStr}`\n}\n\n/**\n * Creates a feature-scoped logger\n *\n * @param feature - Feature name for log prefixing\n * @returns Logger instance\n *\n * @example\n * ```typescript\n * const logger = createLogger('my-component')\n * logger.info('Component mounted', { componentId: '123' })\n * ```\n */\nexport function createLogger(feature: string): Logger {\n return {\n info(message: string, context?: Record<string, unknown>) {\n if (isDev) {\n console.info(formatLogMessage(feature, message, context))\n }\n },\n\n warn(message: string, context?: Record<string, unknown>) {\n if (isDev) {\n console.warn(formatLogMessage(feature, message, context))\n }\n },\n\n error(message: string, context?: Record<string, unknown>) {\n // Always log errors, even in production\n console.error(formatLogMessage(feature, message, context))\n },\n\n debug(message: string, context?: Record<string, unknown>) {\n if (isDev) {\n console.debug(formatLogMessage(feature, message, context))\n }\n },\n }\n}\n\n/**\n * No-op logger for testing or when logging is disabled\n */\nexport const noopLogger: Logger = {\n info: () => {},\n warn: () => {},\n error: () => {},\n debug: () => {},\n}\n"],"names":[],"mappings":"AAQA,MAAM,QAAQ,OAAO,YAAY,eAAe,QAAQ,IAAI,aAAa;AASzE,SAAS,iBACP,SACA,SACA,SACQ;AACR,QAAM,aAAa,UAAU,IAAI,KAAK,UAAU,OAAO,CAAC,KAAK;AAC7D,SAAO,4BAA4B,OAAO,KAAK,OAAO,GAAG,UAAU;AACrE;AAcO,SAAS,aAAa,SAAyB;AACpD,SAAO;AAAA,IACL,KAAK,SAAiB,SAAmC;AACvD,UAAI,OAAO;AACT,gBAAQ,KAAK,iBAAiB,SAAS,SAAS,OAAO,CAAC;AAAA,MAC1D;AAAA,IACF;AAAA,IAEA,KAAK,SAAiB,SAAmC;AACvD,UAAI,OAAO;AACT,gBAAQ,KAAK,iBAAiB,SAAS,SAAS,OAAO,CAAC;AAAA,MAC1D;AAAA,IACF;AAAA,IAEA,MAAM,SAAiB,SAAmC;AAExD,cAAQ,MAAM,iBAAiB,SAAS,SAAS,OAAO,CAAC;AAAA,IAC3D;AAAA,IAEA,MAAM,SAAiB,SAAmC;AACxD,UAAI,OAAO;AACT,gBAAQ,MAAM,iBAAiB,SAAS,SAAS,OAAO,CAAC;AAAA,MAC3D;AAAA,IACF;AAAA,EAAA;AAEJ;"}
|
package/dist/validation.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const validation = require("./
|
|
3
|
+
const validation = require("./services/validation.cjs");
|
|
4
4
|
exports.DEFAULT_RESOURCE_LIMITS = validation.DEFAULT_RESOURCE_LIMITS;
|
|
5
5
|
exports.sanitizeString = validation.sanitizeString;
|
|
6
6
|
exports.validateChartComponent = validation.validateChartComponent;
|
package/dist/validation.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DEFAULT_RESOURCE_LIMITS, sanitizeString, validateChartComponent, validateComponent, validateGridPosition, validateIframeDomain, validateLayout, validatePayloadSize, validateTableComponent } from "./
|
|
1
|
+
import { DEFAULT_RESOURCE_LIMITS, sanitizeString, validateChartComponent, validateComponent, validateGridPosition, validateIframeDomain, validateLayout, validatePayloadSize, validateTableComponent } from "./services/validation.js";
|
|
2
2
|
export {
|
|
3
3
|
DEFAULT_RESOURCE_LIMITS,
|
|
4
4
|
sanitizeString,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seed-ship/mcp-ui-solid",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.31",
|
|
4
4
|
"description": "SolidJS components for rendering MCP-generated UI resources",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -8,45 +8,47 @@
|
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
11
12
|
"solid": "./dist/index.js",
|
|
12
13
|
"import": "./dist/index.js",
|
|
13
|
-
"require": "./dist/index.cjs"
|
|
14
|
-
"types": "./dist/index.d.ts"
|
|
14
|
+
"require": "./dist/index.cjs"
|
|
15
15
|
},
|
|
16
16
|
"./components": {
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
17
|
+
"types": "./dist/components.d.ts",
|
|
18
|
+
"solid": "./dist/components.js",
|
|
19
|
+
"import": "./dist/components.js",
|
|
20
|
+
"require": "./dist/components.cjs"
|
|
21
21
|
},
|
|
22
22
|
"./hooks": {
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
23
|
+
"types": "./dist/hooks.d.ts",
|
|
24
|
+
"solid": "./dist/hooks.js",
|
|
25
|
+
"import": "./dist/hooks.js",
|
|
26
|
+
"require": "./dist/hooks.cjs"
|
|
27
27
|
},
|
|
28
28
|
"./types": {
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
29
|
+
"types": "./dist/types.d.ts",
|
|
30
|
+
"solid": "./dist/types.js",
|
|
31
|
+
"import": "./dist/types.js",
|
|
32
|
+
"require": "./dist/types.cjs"
|
|
33
33
|
},
|
|
34
34
|
"./validation": {
|
|
35
|
+
"types": "./dist/validation.d.ts",
|
|
35
36
|
"solid": "./dist/validation.js",
|
|
36
37
|
"import": "./dist/validation.js",
|
|
37
|
-
"require": "./dist/validation.cjs"
|
|
38
|
-
|
|
38
|
+
"require": "./dist/validation.cjs"
|
|
39
|
+
},
|
|
40
|
+
"./types-only": {
|
|
41
|
+
"types": "./dist/types-export.d.ts",
|
|
42
|
+
"import": "./dist/types-export.js",
|
|
43
|
+
"require": "./dist/types-export.cjs"
|
|
39
44
|
}
|
|
40
45
|
},
|
|
41
|
-
"files": [
|
|
42
|
-
"dist",
|
|
43
|
-
"README.md",
|
|
44
|
-
"CHANGELOG.md"
|
|
45
|
-
],
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"solid-js": "^1.9.0"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
+
"@types/dompurify": "^3.0.5",
|
|
51
|
+
"dompurify": "^3.3.0",
|
|
50
52
|
"marked": "^16.3.0",
|
|
51
53
|
"zod": "^3.22.4"
|
|
52
54
|
},
|
|
@@ -86,7 +88,7 @@
|
|
|
86
88
|
},
|
|
87
89
|
"scripts": {
|
|
88
90
|
"build": "vite build && pnpm build:types",
|
|
89
|
-
"build:types": "tsc --emitDeclarationOnly --outDir dist --
|
|
91
|
+
"build:types": "tsc --declaration --emitDeclarationOnly --outDir dist --composite false && cp dist/components/index.d.ts dist/components.d.ts 2>/dev/null || true && cp dist/hooks/index.d.ts dist/hooks.d.ts 2>/dev/null || true && cp dist/types/index.d.ts dist/types.d.ts 2>/dev/null || true",
|
|
90
92
|
"dev": "vite build --watch",
|
|
91
93
|
"test": "vitest run",
|
|
92
94
|
"test:watch": "vitest",
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Component, Show } from 'solid-js'
|
|
2
|
+
// import type { ActionSpec } from '@seed-ship/mcp-ui-spec'
|
|
3
|
+
type ActionSpec = any
|
|
4
|
+
|
|
5
|
+
export interface ActionRendererProps {
|
|
6
|
+
action: ActionSpec
|
|
7
|
+
onExecute: (toolName: string, params: any) => Promise<any>
|
|
8
|
+
disabled?: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const ActionRenderer: Component<ActionRendererProps> = (props) => {
|
|
12
|
+
const handleClick = async () => {
|
|
13
|
+
if (props.disabled) return
|
|
14
|
+
await props.onExecute(props.action.toolName, props.action.params)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const variantClasses: Record<string, string> = {
|
|
18
|
+
primary: 'bg-blue-600 hover:bg-blue-700 text-white',
|
|
19
|
+
secondary: 'bg-gray-200 hover:bg-gray-300 text-gray-800 dark:bg-gray-700 dark:hover:bg-gray-600 dark:text-white',
|
|
20
|
+
danger: 'bg-red-600 hover:bg-red-700 text-white'
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<button
|
|
25
|
+
onClick={handleClick}
|
|
26
|
+
disabled={props.disabled}
|
|
27
|
+
class={`px-3 py-1.5 rounded-md text-sm font-medium transition-colors ${variantClasses[props.action.variant || 'primary']
|
|
28
|
+
} ${props.disabled ? 'opacity-50 cursor-not-allowed' : ''}`}
|
|
29
|
+
>
|
|
30
|
+
{props.action.label}
|
|
31
|
+
</button>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Component } from 'solid-js'
|
|
2
|
+
|
|
3
|
+
export interface ArtifactComponentParams {
|
|
4
|
+
url: string
|
|
5
|
+
filename: string
|
|
6
|
+
mimeType: string
|
|
7
|
+
size?: number
|
|
8
|
+
description?: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const ArtifactRenderer: Component<{ params: ArtifactComponentParams }> = (props) => {
|
|
12
|
+
const getIcon = () => {
|
|
13
|
+
if (props.params.mimeType.includes('csv')) return '📊'
|
|
14
|
+
if (props.params.mimeType.includes('json')) return '{}'
|
|
15
|
+
if (props.params.mimeType.includes('pdf')) return '📄'
|
|
16
|
+
return '📁'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const formatSize = (bytes?: number) => {
|
|
20
|
+
if (!bytes) return ''
|
|
21
|
+
if (bytes < 1024) return `${bytes} B`
|
|
22
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`
|
|
23
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<div class="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800/50 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors">
|
|
28
|
+
<div class="flex items-center gap-3">
|
|
29
|
+
<div class="w-10 h-10 flex items-center justify-center bg-white dark:bg-gray-700 rounded-md shadow-sm text-xl">
|
|
30
|
+
{getIcon()}
|
|
31
|
+
</div>
|
|
32
|
+
<div>
|
|
33
|
+
<h4 class="text-sm font-medium text-gray-900 dark:text-white truncate max-w-[200px]">
|
|
34
|
+
{props.params.filename}
|
|
35
|
+
</h4>
|
|
36
|
+
<p class="text-xs text-gray-500 dark:text-gray-400">
|
|
37
|
+
{formatSize(props.params.size)} • {props.params.description || 'Generated artifact'}
|
|
38
|
+
</p>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<a
|
|
43
|
+
href={props.params.url}
|
|
44
|
+
download={props.params.filename}
|
|
45
|
+
class="px-3 py-1.5 text-sm font-medium text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/20 hover:bg-blue-100 dark:hover:bg-blue-900/40 rounded-md transition-colors flex items-center gap-1"
|
|
46
|
+
>
|
|
47
|
+
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
48
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
|
|
49
|
+
</svg>
|
|
50
|
+
Download
|
|
51
|
+
</a>
|
|
52
|
+
</div>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Component, For, createSignal, onMount } from 'solid-js'
|
|
2
|
+
import { isServer } from 'solid-js/web'
|
|
3
|
+
import { UIResourceRenderer } from './UIResourceRenderer'
|
|
4
|
+
|
|
5
|
+
// Local definition to avoid missing module error
|
|
6
|
+
type UIComponent = any
|
|
7
|
+
|
|
8
|
+
export interface CarouselRendererProps {
|
|
9
|
+
items: UIComponent[]
|
|
10
|
+
height?: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const CarouselRenderer: Component<CarouselRendererProps> = (props) => {
|
|
14
|
+
let scrollContainer: HTMLDivElement | undefined
|
|
15
|
+
const [canScrollLeft, setCanScrollLeft] = createSignal(false)
|
|
16
|
+
const [canScrollRight, setCanScrollRight] = createSignal(true)
|
|
17
|
+
|
|
18
|
+
const checkScroll = () => {
|
|
19
|
+
if (isServer || !scrollContainer) return
|
|
20
|
+
setCanScrollLeft(scrollContainer.scrollLeft > 0)
|
|
21
|
+
setCanScrollRight(
|
|
22
|
+
scrollContainer.scrollLeft < scrollContainer.scrollWidth - scrollContainer.clientWidth - 10
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const scroll = (direction: 'left' | 'right') => {
|
|
27
|
+
if (isServer || !scrollContainer) return
|
|
28
|
+
const scrollAmount = scrollContainer.clientWidth * 0.8
|
|
29
|
+
scrollContainer.scrollBy({
|
|
30
|
+
left: direction === 'left' ? -scrollAmount : scrollAmount,
|
|
31
|
+
behavior: 'smooth'
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<div class="relative group">
|
|
37
|
+
{/* Navigation Buttons */}
|
|
38
|
+
<button
|
|
39
|
+
onClick={() => scroll('left')}
|
|
40
|
+
class={`absolute left-2 top-1/2 -translate-y-1/2 z-10 p-2 bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm rounded-full shadow-md border border-gray-200 dark:border-gray-700 transition-opacity ${canScrollLeft() ? 'opacity-0 group-hover:opacity-100' : 'opacity-0 pointer-events-none'
|
|
41
|
+
}`}
|
|
42
|
+
>
|
|
43
|
+
<svg class="w-5 h-5 text-gray-700 dark:text-gray-300" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
44
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
|
45
|
+
</svg>
|
|
46
|
+
</button>
|
|
47
|
+
|
|
48
|
+
<button
|
|
49
|
+
onClick={() => scroll('right')}
|
|
50
|
+
class={`absolute right-2 top-1/2 -translate-y-1/2 z-10 p-2 bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm rounded-full shadow-md border border-gray-200 dark:border-gray-700 transition-opacity ${canScrollRight() ? 'opacity-0 group-hover:opacity-100' : 'opacity-0 pointer-events-none'
|
|
51
|
+
}`}
|
|
52
|
+
>
|
|
53
|
+
<svg class="w-5 h-5 text-gray-700 dark:text-gray-300" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
54
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
|
55
|
+
</svg>
|
|
56
|
+
</button>
|
|
57
|
+
|
|
58
|
+
{/* Scroll Container */}
|
|
59
|
+
<div
|
|
60
|
+
ref={scrollContainer}
|
|
61
|
+
onScroll={checkScroll}
|
|
62
|
+
class="flex gap-4 overflow-x-auto snap-x snap-mandatory pb-4 scrollbar-hide"
|
|
63
|
+
style={{ "scroll-behavior": "smooth" }}
|
|
64
|
+
>
|
|
65
|
+
<For each={props.items}>
|
|
66
|
+
{(item) => (
|
|
67
|
+
<div class="flex-none w-[85%] sm:w-[45%] snap-center">
|
|
68
|
+
<div class="h-full border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden bg-white dark:bg-gray-800">
|
|
69
|
+
<UIResourceRenderer content={item} />
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
)}
|
|
73
|
+
</For>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Component, Show, For } from 'solid-js'
|
|
2
|
+
|
|
3
|
+
export interface FooterComponentParams {
|
|
4
|
+
poweredBy?: string
|
|
5
|
+
executionTime?: number
|
|
6
|
+
model?: string
|
|
7
|
+
sourceCount?: number
|
|
8
|
+
customText?: string
|
|
9
|
+
links?: { label: string; url: string }[]
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const FooterRenderer: Component<{ params: FooterComponentParams }> = (props) => {
|
|
13
|
+
return (
|
|
14
|
+
<div class="mt-4 pt-3 border-t border-gray-200 dark:border-gray-700 text-xs text-gray-500 dark:text-gray-400 flex flex-wrap items-center gap-4">
|
|
15
|
+
<Show when={props.params.poweredBy}>
|
|
16
|
+
<span class="font-medium">{props.params.poweredBy}</span>
|
|
17
|
+
</Show>
|
|
18
|
+
|
|
19
|
+
<Show when={props.params.executionTime}>
|
|
20
|
+
<span class="flex items-center gap-1">
|
|
21
|
+
<svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
22
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
23
|
+
</svg>
|
|
24
|
+
{props.params.executionTime}ms
|
|
25
|
+
</span>
|
|
26
|
+
</Show>
|
|
27
|
+
|
|
28
|
+
<Show when={props.params.model}>
|
|
29
|
+
<span class="flex items-center gap-1">
|
|
30
|
+
<svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
31
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19.428 15.428a2 2 0 00-1.022-.547l-2.384-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z" />
|
|
32
|
+
</svg>
|
|
33
|
+
{props.params.model}
|
|
34
|
+
</span>
|
|
35
|
+
</Show>
|
|
36
|
+
|
|
37
|
+
<Show when={props.params.sourceCount}>
|
|
38
|
+
<span class="flex items-center gap-1">
|
|
39
|
+
<svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
40
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
|
41
|
+
</svg>
|
|
42
|
+
{props.params.sourceCount} sources
|
|
43
|
+
</span>
|
|
44
|
+
</Show>
|
|
45
|
+
|
|
46
|
+
<div class="flex-grow" />
|
|
47
|
+
|
|
48
|
+
<Show when={props.params.links}>
|
|
49
|
+
<div class="flex gap-3">
|
|
50
|
+
<For each={props.params.links}>
|
|
51
|
+
{(link) => (
|
|
52
|
+
<a
|
|
53
|
+
href={link.url}
|
|
54
|
+
target="_blank"
|
|
55
|
+
rel="noopener noreferrer"
|
|
56
|
+
class="hover:text-blue-600 dark:hover:text-blue-400 transition-colors"
|
|
57
|
+
>
|
|
58
|
+
{link.label}
|
|
59
|
+
</a>
|
|
60
|
+
)}
|
|
61
|
+
</For>
|
|
62
|
+
</div>
|
|
63
|
+
</Show>
|
|
64
|
+
</div>
|
|
65
|
+
)
|
|
66
|
+
}
|