@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.
Files changed (91) hide show
  1. package/dist/components/GenerativeUIErrorBoundary.cjs.map +1 -0
  2. package/dist/components/GenerativeUIErrorBoundary.js.map +1 -0
  3. package/dist/components/StreamingUIRenderer.cjs.map +1 -0
  4. package/dist/components/StreamingUIRenderer.js.map +1 -0
  5. package/dist/{mcp-ui-solid/src/components → components}/UIResourceRenderer.cjs +102 -97
  6. package/dist/components/UIResourceRenderer.cjs.map +1 -0
  7. package/dist/components/UIResourceRenderer.d.ts +0 -11
  8. package/dist/components/UIResourceRenderer.d.ts.map +1 -1
  9. package/dist/{mcp-ui-solid/src/components → components}/UIResourceRenderer.js +102 -97
  10. package/dist/components/UIResourceRenderer.js.map +1 -0
  11. package/dist/components.cjs +3 -3
  12. package/dist/components.d.ts +12 -0
  13. package/dist/components.js +3 -3
  14. package/dist/hooks/useStreamingUI.cjs.map +1 -0
  15. package/dist/hooks/useStreamingUI.js.map +1 -0
  16. package/dist/hooks.cjs +1 -1
  17. package/dist/hooks.d.ts +8 -0
  18. package/dist/hooks.js +1 -1
  19. package/dist/index.cjs +6 -6
  20. package/dist/index.js +6 -6
  21. package/dist/node_modules/.pnpm/dompurify@3.3.0/node_modules/dompurify/dist/purify.es.cjs +1006 -0
  22. package/dist/node_modules/.pnpm/dompurify@3.3.0/node_modules/dompurify/dist/purify.es.cjs.map +1 -0
  23. package/dist/node_modules/.pnpm/dompurify@3.3.0/node_modules/dompurify/dist/purify.es.js +1007 -0
  24. package/dist/node_modules/.pnpm/dompurify@3.3.0/node_modules/dompurify/dist/purify.es.js.map +1 -0
  25. package/dist/services/component-registry.cjs.map +1 -0
  26. package/dist/services/component-registry.js.map +1 -0
  27. package/dist/services/validation.cjs.map +1 -0
  28. package/dist/services/validation.js.map +1 -0
  29. package/dist/types-export.cjs +2 -0
  30. package/dist/types-export.cjs.map +1 -0
  31. package/dist/types-export.d.ts +13 -0
  32. package/dist/types-export.d.ts.map +1 -0
  33. package/dist/types-export.js +2 -0
  34. package/dist/types-export.js.map +1 -0
  35. package/dist/types.d.ts +265 -0
  36. package/dist/utils/logger.cjs.map +1 -0
  37. package/dist/utils/logger.js.map +1 -0
  38. package/dist/validation.cjs +1 -1
  39. package/dist/validation.js +1 -1
  40. package/package.json +25 -23
  41. package/src/components/ActionRenderer.tsx +33 -0
  42. package/src/components/ArtifactRenderer.tsx +54 -0
  43. package/src/components/CarouselRenderer.tsx +77 -0
  44. package/src/components/FooterRenderer.tsx +66 -0
  45. package/src/components/GenerativeUIErrorBoundary.tsx +259 -0
  46. package/src/components/StreamingUIRenderer.tsx +327 -0
  47. package/src/components/UIResourceRenderer.tsx +573 -0
  48. package/src/components/index.ts +14 -0
  49. package/src/hooks/index.ts +14 -0
  50. package/src/hooks/useStreamingUI.ts +447 -0
  51. package/src/index.test.ts +36 -0
  52. package/src/index.ts +70 -0
  53. package/src/services/component-registry.ts +378 -0
  54. package/src/services/index.ts +9 -0
  55. package/src/services/validation.ts +472 -0
  56. package/src/types/index.ts +320 -0
  57. package/src/types-export.ts +31 -0
  58. package/src/utils/logger.ts +74 -0
  59. package/src/validation.ts +38 -0
  60. package/src/vite-env.d.ts +11 -0
  61. package/tsconfig.json +20 -0
  62. package/tsconfig.tsbuildinfo +1 -0
  63. package/vite.config.ts +52 -0
  64. package/vite.config.ts.timestamp-1763266929437-a71eed80b91318.mjs +45 -0
  65. package/vitest.config.ts +10 -0
  66. package/dist/mcp-ui-solid/src/components/GenerativeUIErrorBoundary.cjs.map +0 -1
  67. package/dist/mcp-ui-solid/src/components/GenerativeUIErrorBoundary.js.map +0 -1
  68. package/dist/mcp-ui-solid/src/components/StreamingUIRenderer.cjs.map +0 -1
  69. package/dist/mcp-ui-solid/src/components/StreamingUIRenderer.js.map +0 -1
  70. package/dist/mcp-ui-solid/src/components/UIResourceRenderer.cjs.map +0 -1
  71. package/dist/mcp-ui-solid/src/components/UIResourceRenderer.js.map +0 -1
  72. package/dist/mcp-ui-solid/src/hooks/useStreamingUI.cjs.map +0 -1
  73. package/dist/mcp-ui-solid/src/hooks/useStreamingUI.js.map +0 -1
  74. package/dist/mcp-ui-solid/src/services/component-registry.cjs.map +0 -1
  75. package/dist/mcp-ui-solid/src/services/component-registry.js.map +0 -1
  76. package/dist/mcp-ui-solid/src/services/validation.cjs.map +0 -1
  77. package/dist/mcp-ui-solid/src/services/validation.js.map +0 -1
  78. package/dist/mcp-ui-solid/src/utils/logger.cjs.map +0 -1
  79. package/dist/mcp-ui-solid/src/utils/logger.js.map +0 -1
  80. /package/dist/{mcp-ui-solid/src/components → components}/GenerativeUIErrorBoundary.cjs +0 -0
  81. /package/dist/{mcp-ui-solid/src/components → components}/GenerativeUIErrorBoundary.js +0 -0
  82. /package/dist/{mcp-ui-solid/src/components → components}/StreamingUIRenderer.cjs +0 -0
  83. /package/dist/{mcp-ui-solid/src/components → components}/StreamingUIRenderer.js +0 -0
  84. /package/dist/{mcp-ui-solid/src/hooks → hooks}/useStreamingUI.cjs +0 -0
  85. /package/dist/{mcp-ui-solid/src/hooks → hooks}/useStreamingUI.js +0 -0
  86. /package/dist/{mcp-ui-solid/src/services → services}/component-registry.cjs +0 -0
  87. /package/dist/{mcp-ui-solid/src/services → services}/component-registry.js +0 -0
  88. /package/dist/{mcp-ui-solid/src/services → services}/validation.cjs +0 -0
  89. /package/dist/{mcp-ui-solid/src/services → services}/validation.js +0 -0
  90. /package/dist/{mcp-ui-solid/src/utils → utils}/logger.cjs +0 -0
  91. /package/dist/{mcp-ui-solid/src/utils → utils}/logger.js +0 -0
@@ -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;"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const validation = require("./mcp-ui-solid/src/services/validation.cjs");
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;
@@ -1,4 +1,4 @@
1
- import { DEFAULT_RESOURCE_LIMITS, sanitizeString, validateChartComponent, validateComponent, validateGridPosition, validateIframeDomain, validateLayout, validatePayloadSize, validateTableComponent } from "./mcp-ui-solid/src/services/validation.js";
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.28",
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
- "solid": "./dist/components/index.js",
18
- "import": "./dist/components/index.js",
19
- "require": "./dist/components/index.cjs",
20
- "types": "./dist/components/index.d.ts"
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
- "solid": "./dist/hooks/index.js",
24
- "import": "./dist/hooks/index.js",
25
- "require": "./dist/hooks/index.cjs",
26
- "types": "./dist/hooks/index.d.ts"
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
- "solid": "./dist/types/index.js",
30
- "import": "./dist/types/index.js",
31
- "require": "./dist/types/index.cjs",
32
- "types": "./dist/types/index.d.ts"
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
- "types": "./dist/validation.d.ts"
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 --skipLibCheck",
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
+ }