@belgie/mcp 0.32.0 → 0.33.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.
@@ -0,0 +1,99 @@
1
+ import { createContext, useContext } from "react";
2
+ //#region src/widget-context.ts
3
+ const WidgetContext = createContext(null);
4
+ let activeWidget = null;
5
+ function activateWidget(app) {
6
+ if (activeWidget !== null && activeWidget !== app) throw new Error("Only one connected <Widget> can be active at a time");
7
+ activeWidget = app;
8
+ }
9
+ function deactivateWidget(app) {
10
+ if (activeWidget === app) activeWidget = null;
11
+ }
12
+ function getActiveWidget() {
13
+ if (activeWidget === null) throw new Error("Tool calls require an active connected <Widget>");
14
+ return activeWidget;
15
+ }
16
+ function useWidgetContext() {
17
+ return useContext(WidgetContext);
18
+ }
19
+ function useConnectedWidgetContext(name) {
20
+ const context = useWidgetContext();
21
+ if (context == null) throw new Error(`${name} must be used within a connected <Widget>`);
22
+ return context;
23
+ }
24
+ function useWidget() {
25
+ return useConnectedWidgetContext("useWidget").app;
26
+ }
27
+ //#endregion
28
+ //#region src/tool-error.ts
29
+ function mcpToolErrorMessage(toolName, result) {
30
+ return result.content.map((content) => content.type === "text" ? content.text : "").filter(Boolean).join("\n") || `MCP tool ${JSON.stringify(toolName)} returned an error`;
31
+ }
32
+ var McpToolError = class extends Error {
33
+ toolName;
34
+ result;
35
+ constructor(toolName, result) {
36
+ super(mcpToolErrorMessage(toolName, result), { cause: result });
37
+ this.name = "McpToolError";
38
+ this.toolName = toolName;
39
+ this.result = result;
40
+ }
41
+ };
42
+ var McpToolCancelledError = class extends Error {
43
+ toolName;
44
+ reason;
45
+ constructor(toolName, reason) {
46
+ super(reason === void 0 ? `MCP tool ${JSON.stringify(toolName)} was cancelled` : `MCP tool ${JSON.stringify(toolName)} was cancelled: ${reason}`);
47
+ this.name = "McpToolCancelledError";
48
+ this.toolName = toolName;
49
+ this.reason = reason;
50
+ }
51
+ };
52
+ //#endregion
53
+ //#region src/tool-result-source.ts
54
+ const TOOL_RESULT_SOURCE = Symbol("belgie.tool-result-source");
55
+ function errorResult(error) {
56
+ return {
57
+ result: void 0,
58
+ error
59
+ };
60
+ }
61
+ function normalizeToolCallError(cause) {
62
+ return cause instanceof Error ? cause : new Error(String(cause));
63
+ }
64
+ function createToolResultAdapter(name, success) {
65
+ const parse = (response) => {
66
+ if (response.isError) return errorResult(new McpToolError(name, response));
67
+ return success(response);
68
+ };
69
+ return {
70
+ name,
71
+ parse,
72
+ async execute(input, app) {
73
+ try {
74
+ const rawResult = await app.callServerTool({
75
+ name,
76
+ ...input === void 0 ? {} : { arguments: input }
77
+ });
78
+ return {
79
+ callResult: parse(rawResult),
80
+ rawResult
81
+ };
82
+ } catch (cause) {
83
+ return {
84
+ callResult: errorResult(normalizeToolCallError(cause)),
85
+ rawResult: void 0
86
+ };
87
+ }
88
+ }
89
+ };
90
+ }
91
+ function getToolResultAdapter(source) {
92
+ const adapter = source[TOOL_RESULT_SOURCE];
93
+ if (adapter === void 0) throw new Error("useToolResult requires a generated MCP tool caller");
94
+ return adapter;
95
+ }
96
+ //#endregion
97
+ export { normalizeToolCallError as a, WidgetContext as c, getActiveWidget as d, useConnectedWidgetContext as f, getToolResultAdapter as i, activateWidget as l, createToolResultAdapter as n, McpToolCancelledError as o, useWidget as p, errorResult as r, McpToolError as s, TOOL_RESULT_SOURCE as t, deactivateWidget as u };
98
+
99
+ //# sourceMappingURL=tool-result-source-DTFIKHfH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-result-source-DTFIKHfH.js","names":[],"sources":["../src/widget-context.ts","../src/tool-error.ts","../src/tool-result-source.ts"],"sourcesContent":["import { createContext, useContext } from \"react\";\n\nimport type { App } from \"@modelcontextprotocol/ext-apps\";\nimport type { RawToolResult } from \"./tool-error\";\n\nexport type WidgetToolLifecycle = {\n input: Record<string, unknown> | undefined;\n inputReceived: boolean;\n rawResult: RawToolResult | undefined;\n cancellationReason: string | undefined;\n status: \"pending\" | \"result\" | \"cancelled\";\n version: number;\n};\n\nexport type WidgetContextValue = {\n app: App;\n tool: WidgetToolLifecycle;\n};\n\nexport const WidgetContext = createContext<WidgetContextValue | null>(null);\n\nlet activeWidget: App | null = null;\n\nexport function activateWidget(app: App): void {\n if (activeWidget !== null && activeWidget !== app) {\n throw new Error(\"Only one connected <Widget> can be active at a time\");\n }\n activeWidget = app;\n}\n\nexport function deactivateWidget(app: App): void {\n if (activeWidget === app) {\n activeWidget = null;\n }\n}\n\nexport function getActiveWidget(): App {\n if (activeWidget === null) {\n throw new Error(\"Tool calls require an active connected <Widget>\");\n }\n return activeWidget;\n}\n\nexport function useWidgetContext(): WidgetContextValue | null {\n return useContext(WidgetContext);\n}\n\nexport function useConnectedWidgetContext(name: string): WidgetContextValue {\n const context = useWidgetContext();\n if (context == null) {\n throw new Error(`${name} must be used within a connected <Widget>`);\n }\n return context;\n}\n\nexport function useWidget(): App {\n return useConnectedWidgetContext(\"useWidget\").app;\n}\n","import type { App } from \"@modelcontextprotocol/ext-apps\";\n\nexport type RawToolResult = Awaited<ReturnType<App[\"callServerTool\"]>>;\n\nexport type McpToolErrorResult = RawToolResult & { isError: true };\n\nfunction mcpToolErrorMessage(\n toolName: string,\n result: McpToolErrorResult,\n): string {\n return (\n result.content\n .map((content) => (content.type === \"text\" ? content.text : \"\"))\n .filter(Boolean)\n .join(\"\\n\") || `MCP tool ${JSON.stringify(toolName)} returned an error`\n );\n}\n\nexport class McpToolError extends Error {\n readonly toolName: string;\n readonly result: McpToolErrorResult;\n\n constructor(toolName: string, result: McpToolErrorResult) {\n super(mcpToolErrorMessage(toolName, result), { cause: result });\n this.name = \"McpToolError\";\n this.toolName = toolName;\n this.result = result;\n }\n}\n\nexport class McpToolCancelledError extends Error {\n readonly toolName: string;\n readonly reason: string | undefined;\n\n constructor(toolName: string, reason?: string) {\n super(\n reason === undefined\n ? `MCP tool ${JSON.stringify(toolName)} was cancelled`\n : `MCP tool ${JSON.stringify(toolName)} was cancelled: ${reason}`,\n );\n this.name = \"McpToolCancelledError\";\n this.toolName = toolName;\n this.reason = reason;\n }\n}\n\nexport type ToolCallError = Error;\n\nexport type ToolCallResult<Output> =\n | { result: Output; error: undefined }\n | { result: undefined; error: ToolCallError };\n","import type { App } from \"@modelcontextprotocol/ext-apps\";\n\nimport {\n McpToolError,\n type McpToolErrorResult,\n type RawToolResult,\n type ToolCallError,\n type ToolCallResult,\n} from \"./tool-error\";\n\nexport const TOOL_RESULT_SOURCE: unique symbol = Symbol(\n \"belgie.tool-result-source\",\n);\n\nexport type ToolResultExecution<Output> = {\n callResult: ToolCallResult<Output>;\n rawResult: RawToolResult | undefined;\n};\n\nexport type ToolResultAdapter<Input extends object, Output> = {\n name: string;\n execute: (\n input: Input | undefined,\n app: App,\n ) => Promise<ToolResultExecution<Output>>;\n parse: (response: RawToolResult) => ToolCallResult<Output>;\n};\n\nexport type ToolResultSource<Input extends object, Output> = {\n readonly [TOOL_RESULT_SOURCE]: ToolResultAdapter<Input, Output>;\n};\n\nexport function errorResult(error: ToolCallError): ToolCallResult<never> {\n return { result: undefined, error };\n}\n\nexport function normalizeToolCallError(cause: unknown): ToolCallError {\n return cause instanceof Error ? cause : new Error(String(cause));\n}\n\nexport function createToolResultAdapter<Input extends object, Output>(\n name: string,\n success: (response: RawToolResult) => ToolCallResult<Output>,\n): ToolResultAdapter<Input, Output> {\n const parse = (response: RawToolResult): ToolCallResult<Output> => {\n if (response.isError) {\n return errorResult(\n new McpToolError(name, response as McpToolErrorResult),\n );\n }\n return success(response);\n };\n\n return {\n name,\n parse,\n async execute(input, app) {\n try {\n const rawResult = await app.callServerTool({\n name,\n ...(input === undefined\n ? {}\n : { arguments: input as Record<string, unknown> }),\n });\n return { callResult: parse(rawResult), rawResult };\n } catch (cause: unknown) {\n return {\n callResult: errorResult(normalizeToolCallError(cause)),\n rawResult: undefined,\n };\n }\n },\n };\n}\n\nexport function getToolResultAdapter<Input extends object, Output>(\n source: ToolResultSource<Input, Output>,\n): ToolResultAdapter<Input, Output> {\n const adapter = source[TOOL_RESULT_SOURCE];\n if (adapter === undefined) {\n throw new Error(\"useToolResult requires a generated MCP tool caller\");\n }\n return adapter;\n}\n"],"mappings":";;AAmBA,MAAa,gBAAgB,cAAyC,IAAI;AAE1E,IAAI,eAA2B;AAE/B,SAAgB,eAAe,KAAgB;CAC7C,IAAI,iBAAiB,QAAQ,iBAAiB,KAC5C,MAAM,IAAI,MAAM,qDAAqD;CAEvE,eAAe;AACjB;AAEA,SAAgB,iBAAiB,KAAgB;CAC/C,IAAI,iBAAiB,KACnB,eAAe;AAEnB;AAEA,SAAgB,kBAAuB;CACrC,IAAI,iBAAiB,MACnB,MAAM,IAAI,MAAM,iDAAiD;CAEnE,OAAO;AACT;AAEA,SAAgB,mBAA8C;CAC5D,OAAO,WAAW,aAAa;AACjC;AAEA,SAAgB,0BAA0B,MAAkC;CAC1E,MAAM,UAAU,iBAAiB;CACjC,IAAI,WAAW,MACb,MAAM,IAAI,MAAM,GAAG,KAAK,0CAA0C;CAEpE,OAAO;AACT;AAEA,SAAgB,YAAiB;CAC/B,OAAO,0BAA0B,WAAW,CAAC,CAAC;AAChD;;;ACnDA,SAAS,oBACP,UACA,QACQ;CACR,OACE,OAAO,QACJ,KAAK,YAAa,QAAQ,SAAS,SAAS,QAAQ,OAAO,EAAG,CAAC,CAC/D,OAAO,OAAO,CAAC,CACf,KAAK,IAAI,KAAK,YAAY,KAAK,UAAU,QAAQ,EAAE;AAE1D;AAEA,IAAa,eAAb,cAAkC,MAAM;CACtC;CACA;CAEA,YAAY,UAAkB,QAA4B;EACxD,MAAM,oBAAoB,UAAU,MAAM,GAAG,EAAE,OAAO,OAAO,CAAC;EAC9D,KAAK,OAAO;EACZ,KAAK,WAAW;EAChB,KAAK,SAAS;CAChB;AACF;AAEA,IAAa,wBAAb,cAA2C,MAAM;CAC/C;CACA;CAEA,YAAY,UAAkB,QAAiB;EAC7C,MACE,WAAW,KAAA,IACP,YAAY,KAAK,UAAU,QAAQ,EAAE,kBACrC,YAAY,KAAK,UAAU,QAAQ,EAAE,kBAAkB,QAC7D;EACA,KAAK,OAAO;EACZ,KAAK,WAAW;EAChB,KAAK,SAAS;CAChB;AACF;;;AClCA,MAAa,qBAAoC,OAC/C,2BACF;AAoBA,SAAgB,YAAY,OAA6C;CACvE,OAAO;EAAE,QAAQ,KAAA;EAAW;CAAM;AACpC;AAEA,SAAgB,uBAAuB,OAA+B;CACpE,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AACjE;AAEA,SAAgB,wBACd,MACA,SACkC;CAClC,MAAM,SAAS,aAAoD;EACjE,IAAI,SAAS,SACX,OAAO,YACL,IAAI,aAAa,MAAM,QAA8B,CACvD;EAEF,OAAO,QAAQ,QAAQ;CACzB;CAEA,OAAO;EACL;EACA;EACA,MAAM,QAAQ,OAAO,KAAK;GACxB,IAAI;IACF,MAAM,YAAY,MAAM,IAAI,eAAe;KACzC;KACA,GAAI,UAAU,KAAA,IACV,CAAC,IACD,EAAE,WAAW,MAAiC;IACpD,CAAC;IACD,OAAO;KAAE,YAAY,MAAM,SAAS;KAAG;IAAU;GACnD,SAAS,OAAgB;IACvB,OAAO;KACL,YAAY,YAAY,uBAAuB,KAAK,CAAC;KACrD,WAAW,KAAA;IACb;GACF;EACF;CACF;AACF;AAEA,SAAgB,qBACd,QACkC;CAClC,MAAM,UAAU,OAAO;CACvB,IAAI,YAAY,KAAA,GACd,MAAM,IAAI,MAAM,oDAAoD;CAEtE,OAAO;AACT"}
@@ -0,0 +1,42 @@
1
+ import { App } from "@modelcontextprotocol/ext-apps";
2
+ //#region src/tool-error.d.ts
3
+ type RawToolResult = Awaited<ReturnType<App["callServerTool"]>>;
4
+ type McpToolErrorResult = RawToolResult & {
5
+ isError: true;
6
+ };
7
+ declare class McpToolError extends Error {
8
+ readonly toolName: string;
9
+ readonly result: McpToolErrorResult;
10
+ constructor(toolName: string, result: McpToolErrorResult);
11
+ }
12
+ declare class McpToolCancelledError extends Error {
13
+ readonly toolName: string;
14
+ readonly reason: string | undefined;
15
+ constructor(toolName: string, reason?: string);
16
+ }
17
+ type ToolCallError = Error;
18
+ type ToolCallResult<Output> = {
19
+ result: Output;
20
+ error: undefined;
21
+ } | {
22
+ result: undefined;
23
+ error: ToolCallError;
24
+ };
25
+ //#endregion
26
+ //#region src/tool-result-source.d.ts
27
+ declare const TOOL_RESULT_SOURCE: unique symbol;
28
+ type ToolResultExecution<Output> = {
29
+ callResult: ToolCallResult<Output>;
30
+ rawResult: RawToolResult | undefined;
31
+ };
32
+ type ToolResultAdapter<Input extends object, Output> = {
33
+ name: string;
34
+ execute: (input: Input | undefined, app: App) => Promise<ToolResultExecution<Output>>;
35
+ parse: (response: RawToolResult) => ToolCallResult<Output>;
36
+ };
37
+ type ToolResultSource<Input extends object, Output> = {
38
+ readonly [TOOL_RESULT_SOURCE]: ToolResultAdapter<Input, Output>;
39
+ };
40
+ //#endregion
41
+ export { RawToolResult as a, McpToolErrorResult as i, McpToolCancelledError as n, ToolCallError as o, McpToolError as r, ToolCallResult as s, ToolResultSource as t };
42
+ //# sourceMappingURL=tool-result-source-niHoRYxM.d.ts.map
package/dist/vite.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { Plugin } from "vite";
2
+ //#region src/vite.d.ts
3
+ type BelgiePluginOptions = {
4
+ srcDir?: string;
5
+ };
6
+ declare function belgie(options?: BelgiePluginOptions): Plugin;
7
+ //#endregion
8
+ export { BelgiePluginOptions, belgie };
9
+ //# sourceMappingURL=vite.d.ts.map
package/dist/vite.js CHANGED
@@ -81,14 +81,14 @@ function assertNoInvalidWidgets(invalid) {
81
81
  }
82
82
  //#endregion
83
83
  //#region src/vite.ts
84
- var VIRTUAL_PREFIX = "/_belgie/widget/";
85
- var VIRTUAL_MODULE_PREFIX = "\0belgie:widget:";
86
- var ORCHESTRATION_ENTRY_ID = "belgie:widget-build-orchestrator";
87
- var RESOLVED_ORCHESTRATION_ENTRY_ID = "\0belgie:widget-build-orchestrator";
88
- var INTERNAL_WIDGET_PATH_ENV = "BELGIE_INTERNAL_WIDGET_PATH";
89
- var MAX_INLINE_ASSET_SIZE = Number.MAX_SAFE_INTEGER;
90
- var REACT_REFRESH_PLUGIN_NAME = "vite:react-refresh";
91
- var TEXT_DECODER = new TextDecoder();
84
+ const VIRTUAL_PREFIX = "/_belgie/widget/";
85
+ const VIRTUAL_MODULE_PREFIX = "\0belgie:widget:";
86
+ const ORCHESTRATION_ENTRY_ID = "belgie:widget-build-orchestrator";
87
+ const RESOLVED_ORCHESTRATION_ENTRY_ID = "\0belgie:widget-build-orchestrator";
88
+ const INTERNAL_WIDGET_PATH_ENV = "BELGIE_INTERNAL_WIDGET_PATH";
89
+ const MAX_INLINE_ASSET_SIZE = Number.MAX_SAFE_INTEGER;
90
+ const REACT_REFRESH_PLUGIN_NAME = "vite:react-refresh";
91
+ const TEXT_DECODER = new TextDecoder();
92
92
  function getWidgetEntryPattern(srcDir) {
93
93
  const escaped = normalizePath(srcDir).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
94
94
  return new RegExp(`${escaped}\/[^/]+\/widget\\.tsx(?:\\?.*)?$`);
@@ -142,13 +142,12 @@ function ensureReactRefreshPreamble(html, base, enabled) {
142
142
  ].join("\n");
143
143
  return html.replace("<head>", `<head>\n${preamble}`);
144
144
  }
145
- async function buildWidget(widget, config) {
146
- if (!config.configFile) throw new Error("belgie: isolated widget builds require a Vite config file; inline configs are not supported");
145
+ async function buildWidget(widget, config, configFile) {
147
146
  const previousWidgetPath = process.env[INTERNAL_WIDGET_PATH_ENV];
148
147
  process.env[INTERNAL_WIDGET_PATH_ENV] = widget.filePath;
149
148
  try {
150
149
  await build({
151
- configFile: config.configFile,
150
+ configFile,
152
151
  configLoader: "native",
153
152
  root: config.root,
154
153
  mode: config.mode,
@@ -278,7 +277,7 @@ function belgie(options = {}) {
278
277
  recursive: true,
279
278
  force: true
280
279
  });
281
- for (const widget of widgetMap.values()) await buildWidget(widget, resolvedConfig);
280
+ for (const widget of widgetMap.values()) await buildWidget(widget, resolvedConfig, resolvedConfig.configFile);
282
281
  },
283
282
  configureServer(server) {
284
283
  if (!resolvedSrcDir) {
@@ -332,7 +331,8 @@ function belgie(options = {}) {
332
331
  });
333
332
  },
334
333
  transform(code, id) {
335
- if (widgetEntryPattern?.test(id) && !hasDefaultExport(code)) this.warn(`Widget file "${id.split("/").pop()}" is missing a default export.`);
334
+ const normalizedId = normalizePath(id);
335
+ if (widgetEntryPattern?.test(normalizedId) && !hasDefaultExport(code)) this.warn(`Widget file "${normalizedId.split("/").pop()}" is missing a default export.`);
336
336
  return null;
337
337
  }
338
338
  };
package/dist/vite.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"vite.js","names":[],"sources":["../src/html.ts","../src/validate-widget.ts","../src/scan-widgets.ts","../src/vite.ts"],"sourcesContent":["export type WidgetHtmlDocumentOptions = {\n inlineScript?: string;\n inlineStyles?: string[];\n scripts?: string[];\n styles?: string[];\n};\n\nexport function escapeInlineScript(value: string): string {\n return value.replace(/<\\/script/gi, \"<\\\\/script\");\n}\n\nexport function escapeInlineStyle(value: string): string {\n return value.replace(/<\\/style/gi, \"<\\\\/style\");\n}\n\nexport function buildVirtualEntry(widgetFilePath: string): string {\n const normalized = widgetFilePath.replace(/\\\\/g, \"/\");\n return [\n `import { mountWidget } from \"@belgie/mcp\";`,\n `import Widget from ${JSON.stringify(normalized)};`,\n \"\",\n \"mountWidget(Widget);\",\n \"\",\n ].join(\"\\n\");\n}\n\nexport function renderWidgetHtmlDocument(options: WidgetHtmlDocumentOptions): string {\n const head = [\n '<meta charset=\"utf-8\" />',\n '<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />',\n ...(options.styles ?? []).map((href) => `<link rel=\"stylesheet\" crossorigin href=\"${href}\">`),\n ...(options.inlineStyles ?? []).map((style) => `<style>${escapeInlineStyle(style)}</style>`),\n ];\n const scripts = [\n ...(options.scripts ?? []).map((src) => `<script type=\"module\" crossorigin src=\"${src}\"></script>`),\n ...(options.inlineScript === undefined\n ? []\n : [`<script type=\"module\">${escapeInlineScript(options.inlineScript)}</script>`]),\n ];\n return [\n \"<!doctype html>\",\n \"<html>\",\n \"<head>\",\n ...head,\n \"</head>\",\n \"<body>\",\n '<div id=\"root\"></div>',\n ...scripts,\n \"</body>\",\n \"</html>\",\n \"\",\n ].join(\"\\n\");\n}\n","function stripComments(code: string): string {\n return code.replace(/\\/\\/.*$/gm, \"\").replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\");\n}\n\nexport function hasDefaultExport(code: string): boolean {\n const stripped = stripComments(code);\n return (\n /export\\s+default\\s/.test(stripped) ||\n /export\\s*\\{[^}]*\\bas\\s+default\\b[^}]*}/.test(stripped)\n );\n}\n","import { globSync, readFileSync } from \"node:fs\";\nimport { basename, dirname, resolve } from \"node:path\";\n\nimport { hasDefaultExport } from \"./validate-widget.js\";\n\nexport type WidgetCandidate = {\n name: string;\n filePath: string;\n};\n\nexport type InvalidWidget = {\n filePath: string;\n};\n\nexport type WidgetScanResult = {\n valid: WidgetCandidate[];\n invalid: InvalidWidget[];\n};\n\nexport function scanWidgetsSync(srcDir: string): WidgetScanResult {\n const pattern = resolve(srcDir, \"*/widget.tsx\");\n const candidates = globSync(pattern).map((file) => ({\n name: basename(dirname(file)),\n filePath: file,\n }));\n\n const valid: WidgetCandidate[] = [];\n const invalid: InvalidWidget[] = [];\n for (const candidate of candidates) {\n const code = readFileSync(candidate.filePath, \"utf-8\");\n if (hasDefaultExport(code)) {\n valid.push(candidate);\n } else {\n invalid.push({ filePath: candidate.filePath });\n }\n }\n\n return { valid, invalid };\n}\n\nexport function assertUniqueWidgetNames(widgets: WidgetCandidate[]): void {\n const nameMap = new Map<string, string[]>();\n for (const widget of widgets) {\n const paths = nameMap.get(widget.name) ?? [];\n paths.push(widget.filePath);\n nameMap.set(widget.name, paths);\n }\n\n for (const [name, paths] of nameMap) {\n if (paths.length > 1) {\n throw new Error(\n `belgie: duplicate widget name \"${name}\" resolved from:\\n - ${paths.join(\"\\n - \")}\\nRename one of the files to avoid the conflict.`,\n );\n }\n }\n}\n\nexport function assertNoInvalidWidgets(invalid: InvalidWidget[]): void {\n if (invalid.length === 0) {\n return;\n }\n const paths = invalid.map((widget) => widget.filePath).join(\"\\n - \");\n throw new Error(\n `belgie: widget file(s) missing a default export:\\n - ${paths}\\nAdd a default export so the widget can be built.`,\n );\n}\n\nexport function discoverWidgetsSync(srcDir: string): WidgetCandidate[] {\n const { valid } = scanWidgetsSync(srcDir);\n assertUniqueWidgetNames(valid);\n return valid;\n}\n","import { rmSync } from \"node:fs\";\nimport { isAbsolute, relative, resolve } from \"node:path\";\n\nimport { build, normalizePath, type Plugin, type ResolvedConfig, type UserConfig } from \"vite\";\n\nimport { buildVirtualEntry, renderWidgetHtmlDocument } from \"./html.js\";\nimport {\n assertNoInvalidWidgets,\n assertUniqueWidgetNames,\n scanWidgetsSync,\n type WidgetCandidate,\n} from \"./scan-widgets.js\";\nimport { hasDefaultExport } from \"./validate-widget.js\";\n\nconst VIRTUAL_PREFIX = \"/_belgie/widget/\";\nconst VIRTUAL_MODULE_PREFIX = \"\\0belgie:widget:\";\nconst ORCHESTRATION_ENTRY_ID = \"belgie:widget-build-orchestrator\";\nconst RESOLVED_ORCHESTRATION_ENTRY_ID = \"\\0belgie:widget-build-orchestrator\";\nconst INTERNAL_WIDGET_PATH_ENV = \"BELGIE_INTERNAL_WIDGET_PATH\";\nconst MAX_INLINE_ASSET_SIZE = Number.MAX_SAFE_INTEGER;\nconst REACT_REFRESH_PLUGIN_NAME = \"vite:react-refresh\";\nconst TEXT_DECODER = new TextDecoder();\n\nexport type BelgiePluginOptions = {\n srcDir?: string;\n};\n\ntype RollupInput = string | string[] | Record<string, string>;\n\ntype BuildAsset = {\n fileName: string;\n source: string | Uint8Array;\n type: \"asset\";\n};\n\ntype BuildChunk = {\n code: string;\n dynamicImports: string[];\n facadeModuleId: string | null;\n fileName: string;\n imports: string[];\n isEntry: boolean;\n type: \"chunk\";\n viteMetadata?: { importedCss?: Set<string> };\n};\n\ntype BuildArtifact = BuildAsset | BuildChunk;\n\nfunction getWidgetEntryPattern(srcDir: string): RegExp {\n const escaped = normalizePath(srcDir).replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n return new RegExp(`${escaped}\\/[^/]+\\/widget\\\\.tsx(?:\\\\?.*)?$`);\n}\n\nfunction virtualWidgetName(id: string): string | undefined {\n if (!id.startsWith(VIRTUAL_PREFIX)) {\n return undefined;\n }\n return decodeURIComponent(id.slice(VIRTUAL_PREFIX.length).split(\"?\", 1)[0] ?? \"\");\n}\n\nfunction readAsset(asset: BuildAsset): string {\n return typeof asset.source === \"string\" ? asset.source : TEXT_DECODER.decode(asset.source);\n}\n\nfunction renderWidgetBundle(name: string, bundle: Record<string, BuildArtifact>): string {\n const artifacts = Object.values(bundle);\n const chunks = artifacts.filter((artifact): artifact is BuildChunk => artifact.type === \"chunk\");\n const entries = chunks.filter((chunk) => chunk.isEntry);\n if (entries.length !== 1) {\n throw new Error(`belgie: expected one entry chunk for widget \"${name}\", received ${entries.length}`);\n }\n\n const entry = entries[0]!;\n const extraChunks = chunks.filter((chunk) => chunk !== entry);\n if (extraChunks.length > 0) {\n throw new Error(\n `belgie: widget \"${name}\" emitted extra chunks: ${extraChunks.map((chunk) => chunk.fileName).join(\", \")}`,\n );\n }\n\n const imports = [...entry.imports, ...entry.dynamicImports].filter((item) => item !== entry.fileName);\n if (imports.length > 0) {\n throw new Error(`belgie: widget \"${name}\" retained imports: ${imports.join(\", \")}`);\n }\n\n const assets = artifacts.filter((artifact): artifact is BuildAsset => artifact.type === \"asset\");\n const nonCssAssets = assets.filter((asset) => !asset.fileName.endsWith(\".css\"));\n if (nonCssAssets.length > 0) {\n throw new Error(\n `belgie: widget \"${name}\" emitted non-CSS assets: ${nonCssAssets.map((asset) => asset.fileName).join(\", \")}`,\n );\n }\n\n const assetsByName = new Map(assets.map((asset) => [asset.fileName, asset]));\n const importedCss = [...(entry.viteMetadata?.importedCss ?? [])];\n const cssNames = importedCss.length > 0 ? importedCss : assets.map((asset) => asset.fileName).sort();\n const styles = cssNames.map((cssName) => {\n const asset = assetsByName.get(cssName);\n if (asset === undefined) {\n throw new Error(`belgie: widget \"${name}\" references missing CSS asset ${cssName}`);\n }\n return readAsset(asset);\n });\n return renderWidgetHtmlDocument({ inlineScript: entry.code, inlineStyles: styles });\n}\n\nfunction restoreEnvironment(name: string, previous: string | undefined): void {\n if (previous === undefined) {\n delete process.env[name];\n } else {\n process.env[name] = previous;\n }\n}\n\nfunction ensureReactRefreshPreamble(html: string, base: string, enabled: boolean): string {\n if (!enabled || html.includes(\"@react-refresh\")) {\n return html;\n }\n const normalizedBase = base.endsWith(\"/\") ? base : `${base}/`;\n const refreshPath = `${normalizedBase}@react-refresh`;\n const preamble = [\n '<script type=\"module\">',\n `import { injectIntoGlobalHook } from ${JSON.stringify(refreshPath)};`,\n \"injectIntoGlobalHook(window);\",\n \"window.$RefreshReg$ = () => {};\",\n \"window.$RefreshSig$ = () => (type) => type;\",\n \"</script>\",\n ].join(\"\\n\");\n return html.replace(\"<head>\", `<head>\\n${preamble}`);\n}\n\nasync function buildWidget(widget: WidgetCandidate, config: ResolvedConfig): Promise<void> {\n if (!config.configFile) {\n throw new Error(\n \"belgie: isolated widget builds require a Vite config file; inline configs are not supported\",\n );\n }\n const previousWidgetPath = process.env[INTERNAL_WIDGET_PATH_ENV];\n process.env[INTERNAL_WIDGET_PATH_ENV] = widget.filePath;\n try {\n await build({\n configFile: config.configFile,\n configLoader: \"native\",\n root: config.root,\n mode: config.mode,\n ...(config.logLevel === undefined ? {} : { logLevel: config.logLevel }),\n build: {\n emptyOutDir: false,\n outDir: \"dist\",\n },\n });\n } finally {\n restoreEnvironment(INTERNAL_WIDGET_PATH_ENV, previousWidgetPath);\n }\n}\n\nexport function belgie(options: BelgiePluginOptions = {}): Plugin {\n const rawSrcDir = options.srcDir ?? \"src/widgets\";\n const requestedWidgetPath = process.env[INTERNAL_WIDGET_PATH_ENV];\n let resolvedSrcDir = \"\";\n let projectRoot = \"\";\n let resolvedConfig: ResolvedConfig | undefined;\n let widgetMap = new Map<string, WidgetCandidate>();\n let widgetEntryPattern: RegExp | undefined;\n let usesOrchestrationEntry = false;\n let isBuildCommand = false;\n\n return {\n name: \"belgie\",\n enforce: \"pre\",\n api: { srcDir: rawSrcDir },\n\n config: {\n order: \"post\",\n handler(config: UserConfig, { command }) {\n isBuildCommand = command === \"build\";\n projectRoot = config.root || process.cwd();\n resolvedSrcDir = isAbsolute(rawSrcDir) ? rawSrcDir : resolve(projectRoot, rawSrcDir);\n widgetEntryPattern = getWidgetEntryPattern(resolvedSrcDir);\n\n const { valid, invalid } = scanWidgetsSync(resolvedSrcDir);\n assertUniqueWidgetNames(valid);\n if (command === \"build\") {\n assertNoInvalidWidgets(invalid);\n }\n\n if (requestedWidgetPath !== undefined) {\n const normalizedRequestedPath = normalizePath(resolve(requestedWidgetPath));\n const widget = valid.find((candidate) => normalizePath(resolve(candidate.filePath)) === normalizedRequestedPath);\n if (widget === undefined) {\n throw new Error(\n `belgie: isolated widget build requested unknown entry ${normalizePath(requestedWidgetPath)}`,\n );\n }\n widgetMap = new Map([[widget.name, widget]]);\n return {\n appType: \"custom\",\n resolve: { dedupe: [\"react\", \"react-dom\"] },\n build: {\n assetsInlineLimit: MAX_INLINE_ASSET_SIZE,\n copyPublicDir: false,\n cssCodeSplit: false,\n emptyOutDir: false,\n license: false,\n manifest: false,\n modulePreload: false,\n outDir: \"dist\",\n reportCompressedSize: false,\n sourcemap: false,\n ssrManifest: false,\n watch: null,\n write: true,\n rolldownOptions: {\n input: `${VIRTUAL_PREFIX}${encodeURIComponent(widget.name)}`,\n output: { codeSplitting: false },\n },\n },\n };\n }\n\n widgetMap = new Map(valid.map((widget) => [widget.name, widget]));\n const existingInput = config.build?.rolldownOptions?.input as RollupInput | undefined;\n usesOrchestrationEntry = existingInput === undefined;\n return {\n resolve: { dedupe: [\"react\", \"react-dom\"] },\n build: {\n rolldownOptions: {\n input: existingInput ?? ORCHESTRATION_ENTRY_ID,\n },\n },\n optimizeDeps: {\n entries: [`${resolvedSrcDir}/*/widget.tsx`],\n include: [\"react\", \"react-dom/client\", \"react/jsx-runtime\"],\n },\n };\n },\n },\n\n configResolved(config) {\n resolvedConfig = config;\n projectRoot = config.root;\n if (!resolvedSrcDir) {\n resolvedSrcDir = isAbsolute(rawSrcDir) ? rawSrcDir : resolve(projectRoot, rawSrcDir);\n }\n },\n\n resolveId(id) {\n if (id === ORCHESTRATION_ENTRY_ID) {\n return RESOLVED_ORCHESTRATION_ENTRY_ID;\n }\n const name = virtualWidgetName(id);\n if (name !== undefined && widgetMap.has(name)) {\n return `${VIRTUAL_MODULE_PREFIX}${name}`;\n }\n return null;\n },\n\n load(id) {\n if (id === RESOLVED_ORCHESTRATION_ENTRY_ID) {\n return \"export {};\\n\";\n }\n if (id.startsWith(VIRTUAL_MODULE_PREFIX)) {\n const widget = widgetMap.get(id.slice(VIRTUAL_MODULE_PREFIX.length));\n if (widget !== undefined) {\n return buildVirtualEntry(widget.filePath);\n }\n }\n return null;\n },\n\n generateBundle: {\n order: \"post\",\n handler(_options, bundle) {\n if (requestedWidgetPath !== undefined) {\n const widget = [...widgetMap.values()][0];\n if (widget === undefined) {\n throw new Error(\"belgie: isolated widget build lost its widget entry\");\n }\n const html = renderWidgetBundle(widget.name, bundle as Record<string, BuildArtifact>);\n for (const fileName of Object.keys(bundle)) {\n delete bundle[fileName];\n }\n this.emitFile({\n type: \"asset\",\n fileName: `widgets/${widget.name}/index.html`,\n source: html,\n });\n return;\n }\n\n if (usesOrchestrationEntry) {\n for (const [fileName, artifact] of Object.entries(bundle)) {\n if (artifact.type === \"chunk\" && artifact.facadeModuleId === RESOLVED_ORCHESTRATION_ENTRY_ID) {\n delete bundle[fileName];\n }\n }\n }\n },\n },\n\n async closeBundle() {\n if (!isBuildCommand || requestedWidgetPath !== undefined || resolvedConfig === undefined || widgetMap.size === 0) {\n return;\n }\n if (!resolvedConfig.configFile) {\n throw new Error(\n \"belgie: isolated widget builds require a Vite config file; inline configs are not supported\",\n );\n }\n rmSync(resolve(projectRoot, \"dist\", \"widgets\"), { recursive: true, force: true });\n for (const widget of widgetMap.values()) {\n await buildWidget(widget, resolvedConfig);\n }\n },\n\n configureServer(server) {\n if (!resolvedSrcDir) {\n const root = server.config.root || process.cwd();\n resolvedSrcDir = isAbsolute(rawSrcDir) ? rawSrcDir : resolve(root, rawSrcDir);\n projectRoot = root;\n widgetEntryPattern = getWidgetEntryPattern(resolvedSrcDir);\n }\n\n server.watcher.add(resolvedSrcDir);\n let knownInvalid = new Set<string>();\n const rescan = () => {\n try {\n const { valid, invalid } = scanWidgetsSync(resolvedSrcDir);\n const nextInvalid = new Set(invalid.map((widget) => widget.filePath));\n\n for (const filePath of nextInvalid) {\n if (!knownInvalid.has(filePath)) {\n server.config.logger.warn(\n `[belgie] widget file \"${relative(projectRoot, filePath)}\" is missing a default export — it won't be built until fixed.`,\n );\n }\n }\n for (const filePath of knownInvalid) {\n if (!nextInvalid.has(filePath)) {\n server.config.logger.info(`[belgie] widget file \"${relative(projectRoot, filePath)}\" resolved.`);\n }\n }\n knownInvalid = nextInvalid;\n\n assertUniqueWidgetNames(valid);\n widgetMap = new Map(valid.map((widget) => [widget.name, widget]));\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n server.config.logger.error(`[belgie] widget rescan failed: ${message}`);\n }\n };\n\n rescan();\n server.watcher.on(\"add\", rescan);\n server.watcher.on(\"change\", rescan);\n server.watcher.on(\"unlink\", rescan);\n\n server.middlewares.use(async (request, response, next) => {\n try {\n const pathname = new URL(request.url ?? \"/\", \"http://localhost\").pathname;\n const match = /^\\/widgets\\/([^/]+)\\/index\\.html$/.exec(pathname);\n const name = match?.[1] === undefined ? undefined : decodeURIComponent(match[1]);\n if (name === undefined) {\n next();\n return;\n }\n if (!widgetMap.has(name)) {\n response.statusCode = 404;\n response.setHeader(\"Content-Type\", \"text/plain; charset=utf-8\");\n response.end(`Unknown widget: ${name}`);\n return;\n }\n const transformedHtml = await server.transformIndexHtml(\n pathname,\n renderWidgetHtmlDocument({ scripts: [`${VIRTUAL_PREFIX}${encodeURIComponent(name)}`] }),\n request.url,\n );\n const html = ensureReactRefreshPreamble(\n transformedHtml,\n server.config.base,\n server.config.plugins.some((plugin) => plugin.name === REACT_REFRESH_PLUGIN_NAME),\n );\n response.statusCode = 200;\n response.setHeader(\"Content-Type\", \"text/html; charset=utf-8\");\n response.end(html);\n } catch (error) {\n next(error);\n }\n });\n },\n\n transform(code, id) {\n if (widgetEntryPattern?.test(id) && !hasDefaultExport(code)) {\n this.warn(`Widget file \"${id.split(\"/\").pop()}\" is missing a default export.`);\n }\n return null;\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"vite.js","names":[],"sources":["../src/html.ts","../src/validate-widget.ts","../src/scan-widgets.ts","../src/vite.ts"],"sourcesContent":["export type WidgetHtmlDocumentOptions = {\n inlineScript?: string;\n inlineStyles?: string[];\n scripts?: string[];\n styles?: string[];\n};\n\nexport function escapeInlineScript(value: string): string {\n return value.replace(/<\\/script/gi, \"<\\\\/script\");\n}\n\nexport function escapeInlineStyle(value: string): string {\n return value.replace(/<\\/style/gi, \"<\\\\/style\");\n}\n\nexport function buildVirtualEntry(widgetFilePath: string): string {\n const normalized = widgetFilePath.replace(/\\\\/g, \"/\");\n return [\n `import { mountWidget } from \"@belgie/mcp\";`,\n `import Widget from ${JSON.stringify(normalized)};`,\n \"\",\n \"mountWidget(Widget);\",\n \"\",\n ].join(\"\\n\");\n}\n\nexport function renderWidgetHtmlDocument(options: WidgetHtmlDocumentOptions): string {\n const head = [\n '<meta charset=\"utf-8\" />',\n '<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />',\n ...(options.styles ?? []).map((href) => `<link rel=\"stylesheet\" crossorigin href=\"${href}\">`),\n ...(options.inlineStyles ?? []).map((style) => `<style>${escapeInlineStyle(style)}</style>`),\n ];\n const scripts = [\n ...(options.scripts ?? []).map((src) => `<script type=\"module\" crossorigin src=\"${src}\"></script>`),\n ...(options.inlineScript === undefined\n ? []\n : [`<script type=\"module\">${escapeInlineScript(options.inlineScript)}</script>`]),\n ];\n return [\n \"<!doctype html>\",\n \"<html>\",\n \"<head>\",\n ...head,\n \"</head>\",\n \"<body>\",\n '<div id=\"root\"></div>',\n ...scripts,\n \"</body>\",\n \"</html>\",\n \"\",\n ].join(\"\\n\");\n}\n","function stripComments(code: string): string {\n return code.replace(/\\/\\/.*$/gm, \"\").replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\");\n}\n\nexport function hasDefaultExport(code: string): boolean {\n const stripped = stripComments(code);\n return (\n /export\\s+default\\s/.test(stripped) ||\n /export\\s*\\{[^}]*\\bas\\s+default\\b[^}]*}/.test(stripped)\n );\n}\n","import { globSync, readFileSync } from \"node:fs\";\nimport { basename, dirname, resolve } from \"node:path\";\n\nimport { hasDefaultExport } from \"./validate-widget.js\";\n\nexport type WidgetCandidate = {\n name: string;\n filePath: string;\n};\n\nexport type InvalidWidget = {\n filePath: string;\n};\n\nexport type WidgetScanResult = {\n valid: WidgetCandidate[];\n invalid: InvalidWidget[];\n};\n\nexport function scanWidgetsSync(srcDir: string): WidgetScanResult {\n const pattern = resolve(srcDir, \"*/widget.tsx\");\n const candidates = globSync(pattern).map((file) => ({\n name: basename(dirname(file)),\n filePath: file,\n }));\n\n const valid: WidgetCandidate[] = [];\n const invalid: InvalidWidget[] = [];\n for (const candidate of candidates) {\n const code = readFileSync(candidate.filePath, \"utf-8\");\n if (hasDefaultExport(code)) {\n valid.push(candidate);\n } else {\n invalid.push({ filePath: candidate.filePath });\n }\n }\n\n return { valid, invalid };\n}\n\nexport function assertUniqueWidgetNames(widgets: WidgetCandidate[]): void {\n const nameMap = new Map<string, string[]>();\n for (const widget of widgets) {\n const paths = nameMap.get(widget.name) ?? [];\n paths.push(widget.filePath);\n nameMap.set(widget.name, paths);\n }\n\n for (const [name, paths] of nameMap) {\n if (paths.length > 1) {\n throw new Error(\n `belgie: duplicate widget name \"${name}\" resolved from:\\n - ${paths.join(\"\\n - \")}\\nRename one of the files to avoid the conflict.`,\n );\n }\n }\n}\n\nexport function assertNoInvalidWidgets(invalid: InvalidWidget[]): void {\n if (invalid.length === 0) {\n return;\n }\n const paths = invalid.map((widget) => widget.filePath).join(\"\\n - \");\n throw new Error(\n `belgie: widget file(s) missing a default export:\\n - ${paths}\\nAdd a default export so the widget can be built.`,\n );\n}\n\nexport function discoverWidgetsSync(srcDir: string): WidgetCandidate[] {\n const { valid } = scanWidgetsSync(srcDir);\n assertUniqueWidgetNames(valid);\n return valid;\n}\n","import { rmSync } from \"node:fs\";\nimport { isAbsolute, relative, resolve } from \"node:path\";\n\nimport { build, normalizePath, type Plugin, type ResolvedConfig, type UserConfig } from \"vite\";\n\nimport { buildVirtualEntry, renderWidgetHtmlDocument } from \"./html.js\";\nimport {\n assertNoInvalidWidgets,\n assertUniqueWidgetNames,\n scanWidgetsSync,\n type WidgetCandidate,\n} from \"./scan-widgets.js\";\nimport { hasDefaultExport } from \"./validate-widget.js\";\n\nconst VIRTUAL_PREFIX = \"/_belgie/widget/\";\nconst VIRTUAL_MODULE_PREFIX = \"\\0belgie:widget:\";\nconst ORCHESTRATION_ENTRY_ID = \"belgie:widget-build-orchestrator\";\nconst RESOLVED_ORCHESTRATION_ENTRY_ID = \"\\0belgie:widget-build-orchestrator\";\nconst INTERNAL_WIDGET_PATH_ENV = \"BELGIE_INTERNAL_WIDGET_PATH\";\nconst MAX_INLINE_ASSET_SIZE = Number.MAX_SAFE_INTEGER;\nconst REACT_REFRESH_PLUGIN_NAME = \"vite:react-refresh\";\nconst TEXT_DECODER = new TextDecoder();\n\nexport type BelgiePluginOptions = {\n srcDir?: string;\n};\n\ntype RollupInput = string | string[] | Record<string, string>;\n\ntype BuildAsset = {\n fileName: string;\n source: string | Uint8Array;\n type: \"asset\";\n};\n\ntype BuildChunk = {\n code: string;\n dynamicImports: string[];\n facadeModuleId: string | null;\n fileName: string;\n imports: string[];\n isEntry: boolean;\n type: \"chunk\";\n viteMetadata?: { importedCss?: Set<string> };\n};\n\ntype BuildArtifact = BuildAsset | BuildChunk;\n\nfunction getWidgetEntryPattern(srcDir: string): RegExp {\n const escaped = normalizePath(srcDir).replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n return new RegExp(`${escaped}\\/[^/]+\\/widget\\\\.tsx(?:\\\\?.*)?$`);\n}\n\nfunction virtualWidgetName(id: string): string | undefined {\n if (!id.startsWith(VIRTUAL_PREFIX)) {\n return undefined;\n }\n return decodeURIComponent(id.slice(VIRTUAL_PREFIX.length).split(\"?\", 1)[0] ?? \"\");\n}\n\nfunction readAsset(asset: BuildAsset): string {\n return typeof asset.source === \"string\" ? asset.source : TEXT_DECODER.decode(asset.source);\n}\n\nfunction renderWidgetBundle(name: string, bundle: Record<string, BuildArtifact>): string {\n const artifacts = Object.values(bundle);\n const chunks = artifacts.filter((artifact): artifact is BuildChunk => artifact.type === \"chunk\");\n const entries = chunks.filter((chunk) => chunk.isEntry);\n if (entries.length !== 1) {\n throw new Error(`belgie: expected one entry chunk for widget \"${name}\", received ${entries.length}`);\n }\n\n const entry = entries[0]!;\n const extraChunks = chunks.filter((chunk) => chunk !== entry);\n if (extraChunks.length > 0) {\n throw new Error(\n `belgie: widget \"${name}\" emitted extra chunks: ${extraChunks.map((chunk) => chunk.fileName).join(\", \")}`,\n );\n }\n\n const imports = [...entry.imports, ...entry.dynamicImports].filter((item) => item !== entry.fileName);\n if (imports.length > 0) {\n throw new Error(`belgie: widget \"${name}\" retained imports: ${imports.join(\", \")}`);\n }\n\n const assets = artifacts.filter((artifact): artifact is BuildAsset => artifact.type === \"asset\");\n const nonCssAssets = assets.filter((asset) => !asset.fileName.endsWith(\".css\"));\n if (nonCssAssets.length > 0) {\n throw new Error(\n `belgie: widget \"${name}\" emitted non-CSS assets: ${nonCssAssets.map((asset) => asset.fileName).join(\", \")}`,\n );\n }\n\n const assetsByName = new Map(assets.map((asset) => [asset.fileName, asset]));\n const importedCss = [...(entry.viteMetadata?.importedCss ?? [])];\n const cssNames = importedCss.length > 0 ? importedCss : assets.map((asset) => asset.fileName).sort();\n const styles = cssNames.map((cssName) => {\n const asset = assetsByName.get(cssName);\n if (asset === undefined) {\n throw new Error(`belgie: widget \"${name}\" references missing CSS asset ${cssName}`);\n }\n return readAsset(asset);\n });\n return renderWidgetHtmlDocument({ inlineScript: entry.code, inlineStyles: styles });\n}\n\nfunction restoreEnvironment(name: string, previous: string | undefined): void {\n if (previous === undefined) {\n delete process.env[name];\n } else {\n process.env[name] = previous;\n }\n}\n\nfunction ensureReactRefreshPreamble(html: string, base: string, enabled: boolean): string {\n if (!enabled || html.includes(\"@react-refresh\")) {\n return html;\n }\n const normalizedBase = base.endsWith(\"/\") ? base : `${base}/`;\n const refreshPath = `${normalizedBase}@react-refresh`;\n const preamble = [\n '<script type=\"module\">',\n `import { injectIntoGlobalHook } from ${JSON.stringify(refreshPath)};`,\n \"injectIntoGlobalHook(window);\",\n \"window.$RefreshReg$ = () => {};\",\n \"window.$RefreshSig$ = () => (type) => type;\",\n \"</script>\",\n ].join(\"\\n\");\n return html.replace(\"<head>\", `<head>\\n${preamble}`);\n}\n\nasync function buildWidget(\n widget: WidgetCandidate,\n config: ResolvedConfig,\n configFile: string,\n): Promise<void> {\n const previousWidgetPath = process.env[INTERNAL_WIDGET_PATH_ENV];\n process.env[INTERNAL_WIDGET_PATH_ENV] = widget.filePath;\n try {\n await build({\n configFile,\n configLoader: \"native\",\n root: config.root,\n mode: config.mode,\n ...(config.logLevel === undefined ? {} : { logLevel: config.logLevel }),\n build: {\n emptyOutDir: false,\n outDir: \"dist\",\n },\n });\n } finally {\n restoreEnvironment(INTERNAL_WIDGET_PATH_ENV, previousWidgetPath);\n }\n}\n\nexport function belgie(options: BelgiePluginOptions = {}): Plugin {\n const rawSrcDir = options.srcDir ?? \"src/widgets\";\n const requestedWidgetPath = process.env[INTERNAL_WIDGET_PATH_ENV];\n let resolvedSrcDir = \"\";\n let projectRoot = \"\";\n let resolvedConfig: ResolvedConfig | undefined;\n let widgetMap = new Map<string, WidgetCandidate>();\n let widgetEntryPattern: RegExp | undefined;\n let usesOrchestrationEntry = false;\n let isBuildCommand = false;\n\n return {\n name: \"belgie\",\n enforce: \"pre\",\n api: { srcDir: rawSrcDir },\n\n config: {\n order: \"post\",\n handler(config: UserConfig, { command }) {\n isBuildCommand = command === \"build\";\n projectRoot = config.root || process.cwd();\n resolvedSrcDir = isAbsolute(rawSrcDir) ? rawSrcDir : resolve(projectRoot, rawSrcDir);\n widgetEntryPattern = getWidgetEntryPattern(resolvedSrcDir);\n\n const { valid, invalid } = scanWidgetsSync(resolvedSrcDir);\n assertUniqueWidgetNames(valid);\n if (command === \"build\") {\n assertNoInvalidWidgets(invalid);\n }\n\n if (requestedWidgetPath !== undefined) {\n const normalizedRequestedPath = normalizePath(resolve(requestedWidgetPath));\n const widget = valid.find((candidate) => normalizePath(resolve(candidate.filePath)) === normalizedRequestedPath);\n if (widget === undefined) {\n throw new Error(\n `belgie: isolated widget build requested unknown entry ${normalizePath(requestedWidgetPath)}`,\n );\n }\n widgetMap = new Map([[widget.name, widget]]);\n return {\n appType: \"custom\",\n resolve: { dedupe: [\"react\", \"react-dom\"] },\n build: {\n assetsInlineLimit: MAX_INLINE_ASSET_SIZE,\n copyPublicDir: false,\n cssCodeSplit: false,\n emptyOutDir: false,\n license: false,\n manifest: false,\n modulePreload: false,\n outDir: \"dist\",\n reportCompressedSize: false,\n sourcemap: false,\n ssrManifest: false,\n watch: null,\n write: true,\n rolldownOptions: {\n input: `${VIRTUAL_PREFIX}${encodeURIComponent(widget.name)}`,\n output: { codeSplitting: false },\n },\n },\n };\n }\n\n widgetMap = new Map(valid.map((widget) => [widget.name, widget]));\n const existingInput = config.build?.rolldownOptions?.input as RollupInput | undefined;\n usesOrchestrationEntry = existingInput === undefined;\n return {\n resolve: { dedupe: [\"react\", \"react-dom\"] },\n build: {\n rolldownOptions: {\n input: existingInput ?? ORCHESTRATION_ENTRY_ID,\n },\n },\n optimizeDeps: {\n entries: [`${resolvedSrcDir}/*/widget.tsx`],\n include: [\"react\", \"react-dom/client\", \"react/jsx-runtime\"],\n },\n };\n },\n },\n\n configResolved(config) {\n resolvedConfig = config;\n projectRoot = config.root;\n if (!resolvedSrcDir) {\n resolvedSrcDir = isAbsolute(rawSrcDir) ? rawSrcDir : resolve(projectRoot, rawSrcDir);\n }\n },\n\n resolveId(id) {\n if (id === ORCHESTRATION_ENTRY_ID) {\n return RESOLVED_ORCHESTRATION_ENTRY_ID;\n }\n const name = virtualWidgetName(id);\n if (name !== undefined && widgetMap.has(name)) {\n return `${VIRTUAL_MODULE_PREFIX}${name}`;\n }\n return null;\n },\n\n load(id) {\n if (id === RESOLVED_ORCHESTRATION_ENTRY_ID) {\n return \"export {};\\n\";\n }\n if (id.startsWith(VIRTUAL_MODULE_PREFIX)) {\n const widget = widgetMap.get(id.slice(VIRTUAL_MODULE_PREFIX.length));\n if (widget !== undefined) {\n return buildVirtualEntry(widget.filePath);\n }\n }\n return null;\n },\n\n generateBundle: {\n order: \"post\",\n handler(_options, bundle) {\n if (requestedWidgetPath !== undefined) {\n const widget = [...widgetMap.values()][0];\n if (widget === undefined) {\n throw new Error(\"belgie: isolated widget build lost its widget entry\");\n }\n const html = renderWidgetBundle(widget.name, bundle as Record<string, BuildArtifact>);\n for (const fileName of Object.keys(bundle)) {\n delete bundle[fileName];\n }\n this.emitFile({\n type: \"asset\",\n fileName: `widgets/${widget.name}/index.html`,\n source: html,\n });\n return;\n }\n\n if (usesOrchestrationEntry) {\n for (const [fileName, artifact] of Object.entries(bundle)) {\n if (artifact.type === \"chunk\" && artifact.facadeModuleId === RESOLVED_ORCHESTRATION_ENTRY_ID) {\n delete bundle[fileName];\n }\n }\n }\n },\n },\n\n async closeBundle() {\n if (!isBuildCommand || requestedWidgetPath !== undefined || resolvedConfig === undefined || widgetMap.size === 0) {\n return;\n }\n if (!resolvedConfig.configFile) {\n throw new Error(\n \"belgie: isolated widget builds require a Vite config file; inline configs are not supported\",\n );\n }\n rmSync(resolve(projectRoot, \"dist\", \"widgets\"), { recursive: true, force: true });\n for (const widget of widgetMap.values()) {\n await buildWidget(widget, resolvedConfig, resolvedConfig.configFile);\n }\n },\n\n configureServer(server) {\n if (!resolvedSrcDir) {\n const root = server.config.root || process.cwd();\n resolvedSrcDir = isAbsolute(rawSrcDir) ? rawSrcDir : resolve(root, rawSrcDir);\n projectRoot = root;\n widgetEntryPattern = getWidgetEntryPattern(resolvedSrcDir);\n }\n\n server.watcher.add(resolvedSrcDir);\n let knownInvalid = new Set<string>();\n const rescan = () => {\n try {\n const { valid, invalid } = scanWidgetsSync(resolvedSrcDir);\n const nextInvalid = new Set(invalid.map((widget) => widget.filePath));\n\n for (const filePath of nextInvalid) {\n if (!knownInvalid.has(filePath)) {\n server.config.logger.warn(\n `[belgie] widget file \"${relative(projectRoot, filePath)}\" is missing a default export — it won't be built until fixed.`,\n );\n }\n }\n for (const filePath of knownInvalid) {\n if (!nextInvalid.has(filePath)) {\n server.config.logger.info(`[belgie] widget file \"${relative(projectRoot, filePath)}\" resolved.`);\n }\n }\n knownInvalid = nextInvalid;\n\n assertUniqueWidgetNames(valid);\n widgetMap = new Map(valid.map((widget) => [widget.name, widget]));\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n server.config.logger.error(`[belgie] widget rescan failed: ${message}`);\n }\n };\n\n rescan();\n server.watcher.on(\"add\", rescan);\n server.watcher.on(\"change\", rescan);\n server.watcher.on(\"unlink\", rescan);\n\n server.middlewares.use(async (request, response, next) => {\n try {\n const pathname = new URL(request.url ?? \"/\", \"http://localhost\").pathname;\n const match = /^\\/widgets\\/([^/]+)\\/index\\.html$/.exec(pathname);\n const name = match?.[1] === undefined ? undefined : decodeURIComponent(match[1]);\n if (name === undefined) {\n next();\n return;\n }\n if (!widgetMap.has(name)) {\n response.statusCode = 404;\n response.setHeader(\"Content-Type\", \"text/plain; charset=utf-8\");\n response.end(`Unknown widget: ${name}`);\n return;\n }\n const transformedHtml = await server.transformIndexHtml(\n pathname,\n renderWidgetHtmlDocument({ scripts: [`${VIRTUAL_PREFIX}${encodeURIComponent(name)}`] }),\n request.url,\n );\n const html = ensureReactRefreshPreamble(\n transformedHtml,\n server.config.base,\n server.config.plugins.some((plugin) => plugin.name === REACT_REFRESH_PLUGIN_NAME),\n );\n response.statusCode = 200;\n response.setHeader(\"Content-Type\", \"text/html; charset=utf-8\");\n response.end(html);\n } catch (error) {\n next(error);\n }\n });\n },\n\n transform(code, id) {\n const normalizedId = normalizePath(id);\n if (widgetEntryPattern?.test(normalizedId) && !hasDefaultExport(code)) {\n this.warn(`Widget file \"${normalizedId.split(\"/\").pop()}\" is missing a default export.`);\n }\n return null;\n },\n };\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,50 +1,74 @@
1
1
  {
2
+ "author": "Matt LeMay <mplemay@users.noreply.github.com>",
3
+ "bin": {
4
+ "belgie-mcp": "./dist/cli.js"
5
+ },
6
+ "bugs": {
7
+ "url": "https://github.com/mplemay/belgie/issues"
8
+ },
2
9
  "dependencies": {
10
+ "@modelcontextprotocol/sdk": "^1.29.0",
11
+ "open": "^11.0.0",
3
12
  "react": "19.2.6",
4
- "react-dom": "19.2.6"
13
+ "react-dom": "19.2.6",
14
+ "zod": "^4.4.3"
5
15
  },
16
+ "description": "TypeScript support for Belgie MCP widgets and generated tool clients.",
6
17
  "devDependencies": {
18
+ "@arethetypeswrong/core": "^0.18.5",
7
19
  "@modelcontextprotocol/ext-apps": "^1.7.4",
8
20
  "@types/node": "25.9.1",
9
21
  "@types/react": "19.2.15",
10
22
  "@types/react-dom": "19.2.3",
11
- "typescript": "~6.0.3",
12
- "vite": "8.1.3"
23
+ "@vitest/coverage-v8": "^4.1.10",
24
+ "jsdom": "^29.1.1",
25
+ "publint": "^0.3.21",
26
+ "tsdown": "^0.22.11",
27
+ "typescript": "^7.0.2",
28
+ "vite": "8.1.3",
29
+ "vitest": "^4.1.10"
13
30
  },
14
31
  "engines": {
15
32
  "node": ">=22"
16
33
  },
17
34
  "exports": {
18
- ".": {
19
- "import": "./dist/index.js",
20
- "types": "./types/index.d.ts"
21
- },
22
- "./vite": {
23
- "import": "./dist/vite.js",
24
- "types": "./types/vite.d.ts"
25
- }
35
+ ".": "./dist/index.js",
36
+ "./codegen": "./dist/codegen.js",
37
+ "./internal": "./dist/internal.js",
38
+ "./vite": "./dist/vite.js",
39
+ "./package.json": "./package.json"
26
40
  },
27
41
  "files": [
28
- "dist",
29
- "types"
42
+ "dist"
30
43
  ],
31
- "main": "dist/index.js",
44
+ "homepage": "https://github.com/mplemay/belgie#readme",
45
+ "license": "MIT",
46
+ "main": "./dist/index.js",
47
+ "module": "./dist/index.js",
32
48
  "name": "@belgie/mcp",
33
49
  "peerDependencies": {
34
50
  "@modelcontextprotocol/ext-apps": ">=1.0.0",
35
51
  "vite": ">=8"
36
52
  },
37
53
  "private": false,
54
+ "publishConfig": {
55
+ "access": "public"
56
+ },
38
57
  "repository": {
39
58
  "directory": "packages/mcp",
40
59
  "type": "git",
41
60
  "url": "https://github.com/mplemay/belgie"
42
61
  },
43
62
  "scripts": {
44
- "build": "vite build && node ./node_modules/typescript/bin/tsc",
45
- "clean": "rm -rf dist types"
63
+ "build": "tsdown",
64
+ "check": "tsc --noEmit",
65
+ "dev": "tsdown --watch",
66
+ "prepublishOnly": "npm test",
67
+ "test": "npm run build && npm run test:coverage && npm run check",
68
+ "test:coverage": "vitest run --coverage",
69
+ "test:watch": "vitest"
46
70
  },
47
71
  "type": "module",
48
- "types": "types/index.d.ts",
49
- "version": "0.32.0"
72
+ "types": "./dist/index.d.ts",
73
+ "version": "0.33.0"
50
74
  }
package/types/html.d.ts DELETED
@@ -1,10 +0,0 @@
1
- export type WidgetHtmlDocumentOptions = {
2
- inlineScript?: string;
3
- inlineStyles?: string[];
4
- scripts?: string[];
5
- styles?: string[];
6
- };
7
- export declare function escapeInlineScript(value: string): string;
8
- export declare function escapeInlineStyle(value: string): string;
9
- export declare function buildVirtualEntry(widgetFilePath: string): string;
10
- export declare function renderWidgetHtmlDocument(options: WidgetHtmlDocumentOptions): string;
package/types/index.d.ts DELETED
@@ -1,29 +0,0 @@
1
- import { type ComponentType, type ReactNode } from "react";
2
- import { App, type AppEventMap, type AppOptions, type McpUiAppCapabilities } from "@modelcontextprotocol/ext-apps";
3
- export type WidgetMetadata = {
4
- name: string;
5
- version: string;
6
- title?: string;
7
- capabilities?: McpUiAppCapabilities;
8
- } & Pick<AppOptions, "autoResize" | "strict">;
9
- export type WidgetHooks = {
10
- before?: () => void | Promise<void>;
11
- after?: () => void | Promise<void>;
12
- error?: (error: Error) => void;
13
- toolInput?: (params: AppEventMap["toolinput"]) => void;
14
- toolInputPartial?: (params: AppEventMap["toolinputpartial"]) => void;
15
- toolResult?: (params: AppEventMap["toolresult"]) => void;
16
- toolCancelled?: (params: AppEventMap["toolcancelled"]) => void;
17
- hostContextChanged?: (params: AppEventMap["hostcontextchanged"]) => void;
18
- teardown?: NonNullable<App["onteardown"]>;
19
- };
20
- export type WidgetProps = {
21
- metadata: WidgetMetadata;
22
- children: ReactNode;
23
- hooks?: WidgetHooks;
24
- fallback?: ReactNode;
25
- error?: ReactNode | ((error: Error) => ReactNode);
26
- };
27
- export declare function useWidget(): App;
28
- export declare function Widget({ metadata, children, hooks, fallback, error: errorUI, }: WidgetProps): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react/jsx-runtime").JSX.Element | null | undefined;
29
- export declare function mountWidget(Widget: ComponentType): void;
@@ -1,15 +0,0 @@
1
- export type WidgetCandidate = {
2
- name: string;
3
- filePath: string;
4
- };
5
- export type InvalidWidget = {
6
- filePath: string;
7
- };
8
- export type WidgetScanResult = {
9
- valid: WidgetCandidate[];
10
- invalid: InvalidWidget[];
11
- };
12
- export declare function scanWidgetsSync(srcDir: string): WidgetScanResult;
13
- export declare function assertUniqueWidgetNames(widgets: WidgetCandidate[]): void;
14
- export declare function assertNoInvalidWidgets(invalid: InvalidWidget[]): void;
15
- export declare function discoverWidgetsSync(srcDir: string): WidgetCandidate[];
@@ -1 +0,0 @@
1
- export declare function hasDefaultExport(code: string): boolean;
package/types/vite.d.ts DELETED
@@ -1,5 +0,0 @@
1
- import { type Plugin } from "vite";
2
- export type BelgiePluginOptions = {
3
- srcDir?: string;
4
- };
5
- export declare function belgie(options?: BelgiePluginOptions): Plugin;