@belgie/mcp 0.1.0 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,192 +1,28 @@
1
- import { c as WidgetContext, d as getActiveWidget, f as useConnectedWidgetContext, i as getToolResultAdapter, l as activateWidget, o as McpToolCancelledError, p as useWidget, r as errorResult, s as McpToolError, u as deactivateWidget } from "./tool-result-source-DTFIKHfH.js";
2
- import { StrictMode, useCallback, useEffect, useMemo, useRef, useState } from "react";
1
+ import { StrictMode, createContext, useContext, useEffect, useRef, useState } from "react";
3
2
  import { createRoot } from "react-dom/client";
4
3
  import { App } from "@modelcontextprotocol/ext-apps";
5
4
  import { jsx, jsxs } from "react/jsx-runtime";
6
- //#region src/app.ts
7
- function sendMessage(...args) {
8
- return getActiveWidget().sendMessage(...args);
9
- }
10
- function sendLog(...args) {
11
- return getActiveWidget().sendLog(...args);
12
- }
13
- function updateModelContext(...args) {
14
- return getActiveWidget().updateModelContext(...args);
15
- }
16
- function openLink(...args) {
17
- return getActiveWidget().openLink(...args);
18
- }
19
- function downloadFile(...args) {
20
- return getActiveWidget().downloadFile(...args);
21
- }
22
- function requestDisplayMode(...args) {
23
- return getActiveWidget().requestDisplayMode(...args);
24
- }
25
- function requestTeardown(...args) {
26
- return getActiveWidget().requestTeardown(...args);
27
- }
28
- //#endregion
29
- //#region src/use-tool-result.ts
30
- function sourceMismatchError(expectedName, actualName) {
31
- if (actualName === void 0 || actualName === expectedName) return;
32
- return /* @__PURE__ */ new Error(`useToolResult expected opening tool ${JSON.stringify(expectedName)}, received ${JSON.stringify(actualName)}`);
33
- }
34
- function openingSnapshot(adapter, lifecycle, mismatch) {
35
- if (mismatch !== void 0) return {
36
- data: void 0,
37
- error: mismatch,
38
- rawResult: lifecycle.rawResult,
39
- status: "error",
40
- isFetching: false
41
- };
42
- if (lifecycle.status === "pending") return {
43
- data: void 0,
44
- error: void 0,
45
- rawResult: void 0,
46
- status: "pending",
47
- isFetching: true
48
- };
49
- if (lifecycle.status === "cancelled") return {
50
- data: void 0,
51
- error: new McpToolCancelledError(adapter.name, lifecycle.cancellationReason),
52
- rawResult: void 0,
53
- status: "error",
54
- isFetching: false
55
- };
56
- const rawResult = lifecycle.rawResult;
57
- const callResult = adapter.parse(rawResult);
58
- return callResult.error === void 0 ? {
59
- data: callResult.result,
60
- error: void 0,
61
- rawResult,
62
- status: "success",
63
- isFetching: false
64
- } : {
65
- data: void 0,
66
- error: callResult.error,
67
- rawResult,
68
- status: "error",
69
- isFetching: false
70
- };
71
- }
72
- function useToolResult(source) {
73
- const context = useConnectedWidgetContext("useToolResult");
74
- const adapter = getToolResultAdapter(source);
75
- const [hostToolName, setHostToolName] = useState(() => context.app.getHostContext()?.toolInfo?.tool.name);
76
- const mismatch = useMemo(() => sourceMismatchError(adapter.name, hostToolName), [adapter.name, hostToolName]);
77
- const [snapshot, setSnapshot] = useState(() => openingSnapshot(adapter, context.tool, mismatch));
78
- const hasExecutedRef = useRef(false);
79
- const hasExplicitInputRef = useRef(false);
80
- const latestInputRef = useRef(context.tool.input);
81
- const latestRequestRef = useRef(0);
82
- const mountedRef = useRef(true);
83
- useEffect(() => {
84
- mountedRef.current = true;
85
- return () => {
86
- mountedRef.current = false;
87
- latestRequestRef.current += 1;
88
- };
89
- }, []);
90
- useEffect(() => {
91
- const syncHostToolName = () => {
92
- setHostToolName(context.app.getHostContext()?.toolInfo?.tool.name);
93
- };
94
- syncHostToolName();
95
- context.app.addEventListener("hostcontextchanged", syncHostToolName);
96
- return () => {
97
- context.app.removeEventListener("hostcontextchanged", syncHostToolName);
98
- };
99
- }, [context.app]);
100
- useEffect(() => {
101
- if (!hasExplicitInputRef.current && context.tool.inputReceived) latestInputRef.current = context.tool.input;
102
- }, [context.tool.input, context.tool.inputReceived]);
103
- useEffect(() => {
104
- if (!hasExecutedRef.current) setSnapshot(openingSnapshot(adapter, context.tool, mismatch));
105
- }, [
106
- adapter,
107
- context.tool,
108
- mismatch
109
- ]);
110
- const execute = useCallback(async function execute(input) {
111
- hasExecutedRef.current = true;
112
- if (arguments.length > 0) {
113
- hasExplicitInputRef.current = true;
114
- latestInputRef.current = input;
115
- }
116
- const request = ++latestRequestRef.current;
117
- if (mismatch !== void 0) {
118
- setSnapshot((current) => ({
119
- ...current,
120
- error: mismatch,
121
- status: "error",
122
- isFetching: false
123
- }));
124
- return errorResult(mismatch);
125
- }
126
- setSnapshot((current) => ({
127
- ...current,
128
- error: void 0,
129
- status: current.data === void 0 ? "pending" : "success",
130
- isFetching: true
131
- }));
132
- const execution = await adapter.execute(latestInputRef.current, context.app);
133
- if (mountedRef.current && request === latestRequestRef.current) setSnapshot((current) => execution.callResult.error === void 0 ? {
134
- data: execution.callResult.result,
135
- error: void 0,
136
- rawResult: execution.rawResult ?? current.rawResult,
137
- status: "success",
138
- isFetching: false
139
- } : {
140
- data: current.data,
141
- error: execution.callResult.error,
142
- rawResult: execution.rawResult ?? current.rawResult,
143
- status: "error",
144
- isFetching: false
145
- });
146
- return execution.callResult;
147
- }, [
148
- adapter,
149
- context.app,
150
- mismatch
151
- ]);
152
- return {
153
- data: snapshot.data,
154
- error: snapshot.error,
155
- rawResult: snapshot.rawResult,
156
- status: snapshot.status,
157
- isLoading: snapshot.isFetching && snapshot.data === void 0,
158
- isFetching: snapshot.isFetching,
159
- isSuccess: snapshot.status === "success",
160
- isError: snapshot.status === "error",
161
- execute
162
- };
163
- }
164
- //#endregion
165
5
  //#region src/index.tsx
6
+ var WidgetContext = createContext(null);
7
+ function useWidget() {
8
+ const app = useContext(WidgetContext);
9
+ if (app == null) throw new Error("useWidget must be used within a connected <Widget>");
10
+ return app;
11
+ }
166
12
  function applyHooks(app, hooks) {
167
13
  app.onerror = hooks?.error ?? ((error) => console.error(error));
168
14
  if (!hooks) return;
169
- if (hooks.toolInput) app.addEventListener("toolinput", hooks.toolInput);
170
- if (hooks.toolInputPartial) app.addEventListener("toolinputpartial", hooks.toolInputPartial);
171
- if (hooks.toolResult) app.addEventListener("toolresult", hooks.toolResult);
172
- if (hooks.toolCancelled) app.addEventListener("toolcancelled", hooks.toolCancelled);
173
- if (hooks.hostContextChanged) app.addEventListener("hostcontextchanged", hooks.hostContextChanged);
15
+ if (hooks.toolInput) app.ontoolinput = hooks.toolInput;
16
+ if (hooks.toolInputPartial) app.ontoolinputpartial = hooks.toolInputPartial;
17
+ if (hooks.toolResult) app.ontoolresult = hooks.toolResult;
18
+ if (hooks.toolCancelled) app.ontoolcancelled = hooks.toolCancelled;
19
+ if (hooks.hostContextChanged) app.onhostcontextchanged = hooks.hostContextChanged;
20
+ if (hooks.teardown) app.onteardown = hooks.teardown;
174
21
  }
175
- function initialToolLifecycle() {
176
- return {
177
- input: void 0,
178
- inputReceived: false,
179
- rawResult: void 0,
180
- cancellationReason: void 0,
181
- status: "pending",
182
- version: 0
183
- };
184
- }
185
- let rootInstance = null;
22
+ var rootInstance = null;
186
23
  function Widget({ metadata, children, hooks, fallback, error: errorUI }) {
187
24
  const [connected, setConnected] = useState(false);
188
25
  const [error, setError] = useState(null);
189
- const [toolLifecycle, setToolLifecycle] = useState(initialToolLifecycle);
190
26
  const appRef = useRef(null);
191
27
  const initRef = useRef(null);
192
28
  if (initRef.current == null) initRef.current = {
@@ -195,7 +31,6 @@ function Widget({ metadata, children, hooks, fallback, error: errorUI }) {
195
31
  };
196
32
  useEffect(() => {
197
33
  let cancelled = false;
198
- let active = false;
199
34
  const { metadata: meta, hooks: initHooks } = initRef.current;
200
35
  const { capabilities, autoResize, strict, name, version, title } = meta;
201
36
  const options = {};
@@ -210,40 +45,7 @@ function Widget({ metadata, children, hooks, fallback, error: errorUI }) {
210
45
  title
211
46
  }, capabilities ?? {}, options);
212
47
  appRef.current = app;
213
- setToolLifecycle(initialToolLifecycle());
214
- app.addEventListener("toolinput", (params) => {
215
- if (!cancelled) setToolLifecycle((current) => ({
216
- ...current,
217
- input: params.arguments,
218
- inputReceived: true
219
- }));
220
- });
221
- app.addEventListener("toolresult", (params) => {
222
- if (!cancelled) setToolLifecycle((current) => ({
223
- ...current,
224
- rawResult: params,
225
- cancellationReason: void 0,
226
- status: "result",
227
- version: current.version + 1
228
- }));
229
- });
230
- app.addEventListener("toolcancelled", (params) => {
231
- if (!cancelled) setToolLifecycle((current) => ({
232
- ...current,
233
- rawResult: void 0,
234
- cancellationReason: params.reason,
235
- status: "cancelled",
236
- version: current.version + 1
237
- }));
238
- });
239
48
  applyHooks(app, initHooks);
240
- app.onteardown = async (params, extra) => {
241
- if (active) {
242
- deactivateWidget(app);
243
- active = false;
244
- }
245
- return await initHooks?.teardown?.(params, extra) ?? {};
246
- };
247
49
  (async () => {
248
50
  try {
249
51
  await initHooks?.before?.();
@@ -254,28 +56,14 @@ function Widget({ metadata, children, hooks, fallback, error: errorUI }) {
254
56
  if (!(err instanceof Error && err.message.includes("already connected"))) throw err;
255
57
  }
256
58
  if (cancelled) return;
257
- activateWidget(app);
258
- active = true;
259
59
  await initHooks?.after?.();
260
60
  if (!cancelled) setConnected(true);
261
- else {
262
- deactivateWidget(app);
263
- active = false;
264
- }
265
61
  } catch (err) {
266
- if (active) {
267
- deactivateWidget(app);
268
- active = false;
269
- }
270
62
  if (!cancelled) setError(err instanceof Error ? err : new Error(String(err)));
271
63
  }
272
64
  })();
273
65
  return () => {
274
66
  cancelled = true;
275
- if (active) {
276
- deactivateWidget(app);
277
- active = false;
278
- }
279
67
  app.close();
280
68
  if (appRef.current === app) appRef.current = null;
281
69
  };
@@ -291,10 +79,7 @@ function Widget({ metadata, children, hooks, fallback, error: errorUI }) {
291
79
  }
292
80
  if (!connected || appRef.current == null) return fallback ?? /* @__PURE__ */ jsx("div", { children: "Connecting..." });
293
81
  return /* @__PURE__ */ jsx(WidgetContext.Provider, {
294
- value: {
295
- app: appRef.current,
296
- tool: toolLifecycle
297
- },
82
+ value: appRef.current,
298
83
  children
299
84
  });
300
85
  }
@@ -307,6 +92,6 @@ function mountWidget(Widget) {
307
92
  rootInstance.render(/* @__PURE__ */ jsx(StrictMode, { children: /* @__PURE__ */ jsx(Widget, {}) }));
308
93
  }
309
94
  //#endregion
310
- export { McpToolCancelledError, McpToolError, Widget, downloadFile, mountWidget, openLink, requestDisplayMode, requestTeardown, sendLog, sendMessage, updateModelContext, useToolResult, useWidget };
95
+ export { Widget, mountWidget, useWidget };
311
96
 
312
97
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/app.ts","../src/use-tool-result.ts","../src/index.tsx"],"sourcesContent":["import type { App } from \"@modelcontextprotocol/ext-apps\";\n\nimport { getActiveWidget } from \"./widget-context\";\n\nexport function sendMessage(\n ...args: Parameters<App[\"sendMessage\"]>\n): ReturnType<App[\"sendMessage\"]> {\n return getActiveWidget().sendMessage(...args);\n}\n\nexport function sendLog(\n ...args: Parameters<App[\"sendLog\"]>\n): ReturnType<App[\"sendLog\"]> {\n return getActiveWidget().sendLog(...args);\n}\n\nexport function updateModelContext(\n ...args: Parameters<App[\"updateModelContext\"]>\n): ReturnType<App[\"updateModelContext\"]> {\n return getActiveWidget().updateModelContext(...args);\n}\n\nexport function openLink(\n ...args: Parameters<App[\"openLink\"]>\n): ReturnType<App[\"openLink\"]> {\n return getActiveWidget().openLink(...args);\n}\n\nexport function downloadFile(\n ...args: Parameters<App[\"downloadFile\"]>\n): ReturnType<App[\"downloadFile\"]> {\n return getActiveWidget().downloadFile(...args);\n}\n\nexport function requestDisplayMode(\n ...args: Parameters<App[\"requestDisplayMode\"]>\n): ReturnType<App[\"requestDisplayMode\"]> {\n return getActiveWidget().requestDisplayMode(...args);\n}\n\nexport function requestTeardown(\n ...args: Parameters<App[\"requestTeardown\"]>\n): ReturnType<App[\"requestTeardown\"]> {\n return getActiveWidget().requestTeardown(...args);\n}\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport {\n McpToolCancelledError,\n type RawToolResult,\n type ToolCallError,\n type ToolCallResult,\n} from \"./tool-error\";\nimport {\n errorResult,\n getToolResultAdapter,\n type ToolResultAdapter,\n type ToolResultSource,\n} from \"./tool-result-source\";\nimport {\n useConnectedWidgetContext,\n type WidgetToolLifecycle,\n} from \"./widget-context\";\n\nexport type ToolResultStatus = \"pending\" | \"success\" | \"error\";\n\nexport type ToolResultState<Input extends object, Output> = {\n data: Output | undefined;\n error: ToolCallError | undefined;\n rawResult: RawToolResult | undefined;\n status: ToolResultStatus;\n isLoading: boolean;\n isFetching: boolean;\n isSuccess: boolean;\n isError: boolean;\n execute: (input?: Input) => Promise<ToolCallResult<Output>>;\n};\n\ntype ResultSnapshot<Output> = {\n data: Output | undefined;\n error: ToolCallError | undefined;\n rawResult: RawToolResult | undefined;\n status: ToolResultStatus;\n isFetching: boolean;\n};\n\nfunction sourceMismatchError(\n expectedName: string,\n actualName: string | undefined,\n): Error | undefined {\n if (actualName === undefined || actualName === expectedName) {\n return undefined;\n }\n return new Error(\n `useToolResult expected opening tool ${JSON.stringify(expectedName)}, received ${JSON.stringify(actualName)}`,\n );\n}\n\nfunction openingSnapshot<Input extends object, Output>(\n adapter: ToolResultAdapter<Input, Output>,\n lifecycle: WidgetToolLifecycle,\n mismatch: Error | undefined,\n): ResultSnapshot<Output> {\n if (mismatch !== undefined) {\n return {\n data: undefined,\n error: mismatch,\n rawResult: lifecycle.rawResult,\n status: \"error\",\n isFetching: false,\n };\n }\n if (lifecycle.status === \"pending\") {\n return {\n data: undefined,\n error: undefined,\n rawResult: undefined,\n status: \"pending\",\n isFetching: true,\n };\n }\n if (lifecycle.status === \"cancelled\") {\n return {\n data: undefined,\n error: new McpToolCancelledError(\n adapter.name,\n lifecycle.cancellationReason,\n ),\n rawResult: undefined,\n status: \"error\",\n isFetching: false,\n };\n }\n\n const rawResult = lifecycle.rawResult!;\n const callResult = adapter.parse(rawResult);\n return callResult.error === undefined\n ? {\n data: callResult.result,\n error: undefined,\n rawResult,\n status: \"success\",\n isFetching: false,\n }\n : {\n data: undefined,\n error: callResult.error,\n rawResult,\n status: \"error\",\n isFetching: false,\n };\n}\n\nexport function useToolResult<Input extends object, Output>(\n source: ToolResultSource<Input, Output>,\n): ToolResultState<Input, Output> {\n const context = useConnectedWidgetContext(\"useToolResult\");\n const adapter = getToolResultAdapter(source);\n const [hostToolName, setHostToolName] = useState<string | undefined>(\n () => context.app.getHostContext()?.toolInfo?.tool.name,\n );\n const mismatch = useMemo(\n () => sourceMismatchError(adapter.name, hostToolName),\n [adapter.name, hostToolName],\n );\n const [snapshot, setSnapshot] = useState<ResultSnapshot<Output>>(() =>\n openingSnapshot(adapter, context.tool, mismatch),\n );\n const hasExecutedRef = useRef(false);\n const hasExplicitInputRef = useRef(false);\n const latestInputRef = useRef<Input | undefined>(\n context.tool.input as Input | undefined,\n );\n const latestRequestRef = useRef(0);\n const mountedRef = useRef(true);\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n latestRequestRef.current += 1;\n };\n }, []);\n\n useEffect(() => {\n const syncHostToolName = () => {\n setHostToolName(context.app.getHostContext()?.toolInfo?.tool.name);\n };\n syncHostToolName();\n context.app.addEventListener(\"hostcontextchanged\", syncHostToolName);\n return () => {\n context.app.removeEventListener(\"hostcontextchanged\", syncHostToolName);\n };\n }, [context.app]);\n\n useEffect(() => {\n if (!hasExplicitInputRef.current && context.tool.inputReceived) {\n latestInputRef.current = context.tool.input as Input | undefined;\n }\n }, [context.tool.input, context.tool.inputReceived]);\n\n useEffect(() => {\n if (!hasExecutedRef.current) {\n setSnapshot(openingSnapshot(adapter, context.tool, mismatch));\n }\n }, [adapter, context.tool, mismatch]);\n\n const execute = useCallback(\n async function execute(input?: Input): Promise<ToolCallResult<Output>> {\n hasExecutedRef.current = true;\n if (arguments.length > 0) {\n hasExplicitInputRef.current = true;\n latestInputRef.current = input;\n }\n\n const request = ++latestRequestRef.current;\n if (mismatch !== undefined) {\n setSnapshot((current) => ({\n ...current,\n error: mismatch,\n status: \"error\",\n isFetching: false,\n }));\n return errorResult(mismatch);\n }\n\n setSnapshot((current) => ({\n ...current,\n error: undefined,\n status: current.data === undefined ? \"pending\" : \"success\",\n isFetching: true,\n }));\n const execution = await adapter.execute(\n latestInputRef.current,\n context.app,\n );\n if (mountedRef.current && request === latestRequestRef.current) {\n setSnapshot((current) =>\n execution.callResult.error === undefined\n ? {\n data: execution.callResult.result,\n error: undefined,\n rawResult: execution.rawResult ?? current.rawResult,\n status: \"success\",\n isFetching: false,\n }\n : {\n data: current.data,\n error: execution.callResult.error,\n rawResult: execution.rawResult ?? current.rawResult,\n status: \"error\",\n isFetching: false,\n },\n );\n }\n return execution.callResult;\n },\n [adapter, context.app, mismatch],\n );\n\n return {\n data: snapshot.data,\n error: snapshot.error,\n rawResult: snapshot.rawResult,\n status: snapshot.status,\n isLoading: snapshot.isFetching && snapshot.data === undefined,\n isFetching: snapshot.isFetching,\n isSuccess: snapshot.status === \"success\",\n isError: snapshot.status === \"error\",\n execute,\n };\n}\n","import {\n StrictMode,\n useEffect,\n useRef,\n useState,\n type ComponentType,\n type ReactNode,\n} from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport {\n App,\n type AppEventMap,\n type AppOptions,\n type McpUiAppCapabilities,\n} from \"@modelcontextprotocol/ext-apps\";\nimport {\n WidgetContext,\n activateWidget,\n deactivateWidget,\n useWidget,\n type WidgetToolLifecycle,\n} from \"./widget-context\";\n\nexport {\n downloadFile,\n openLink,\n requestDisplayMode,\n requestTeardown,\n sendLog,\n sendMessage,\n updateModelContext,\n} from \"./app\";\n\nexport {\n McpToolCancelledError,\n McpToolError,\n type McpToolErrorResult,\n type RawToolResult,\n type ToolCallError,\n type ToolCallResult,\n} from \"./tool-error\";\n\nexport {\n useToolResult,\n type ToolResultState,\n type ToolResultStatus,\n} from \"./use-tool-result\";\n\nexport { useWidget };\n\nexport type WidgetMetadata = {\n name: string;\n version: string;\n title?: string;\n capabilities?: McpUiAppCapabilities;\n} & Pick<AppOptions, \"autoResize\" | \"strict\">;\n\nexport type WidgetHooks = {\n before?: () => void | Promise<void>;\n after?: () => void | Promise<void>;\n error?: (error: Error) => void;\n toolInput?: (params: AppEventMap[\"toolinput\"]) => void;\n toolInputPartial?: (params: AppEventMap[\"toolinputpartial\"]) => void;\n toolResult?: (params: AppEventMap[\"toolresult\"]) => void;\n toolCancelled?: (params: AppEventMap[\"toolcancelled\"]) => void;\n hostContextChanged?: (params: AppEventMap[\"hostcontextchanged\"]) => void;\n teardown?: NonNullable<App[\"onteardown\"]>;\n};\n\nexport type WidgetProps = {\n metadata: WidgetMetadata;\n children: ReactNode;\n hooks?: WidgetHooks;\n fallback?: ReactNode;\n error?: ReactNode | ((error: Error) => ReactNode);\n};\n\nfunction applyHooks(app: App, hooks: WidgetHooks | undefined): void {\n app.onerror = hooks?.error ?? ((error) => console.error(error));\n if (!hooks) {\n return;\n }\n if (hooks.toolInput) {\n app.addEventListener(\"toolinput\", hooks.toolInput);\n }\n if (hooks.toolInputPartial) {\n app.addEventListener(\"toolinputpartial\", hooks.toolInputPartial);\n }\n if (hooks.toolResult) {\n app.addEventListener(\"toolresult\", hooks.toolResult);\n }\n if (hooks.toolCancelled) {\n app.addEventListener(\"toolcancelled\", hooks.toolCancelled);\n }\n if (hooks.hostContextChanged) {\n app.addEventListener(\"hostcontextchanged\", hooks.hostContextChanged);\n }\n}\n\nfunction initialToolLifecycle(): WidgetToolLifecycle {\n return {\n input: undefined,\n inputReceived: false,\n rawResult: undefined,\n cancellationReason: undefined,\n status: \"pending\",\n version: 0,\n };\n}\n\nlet rootInstance: Root | null = null;\n\nexport function Widget({\n metadata,\n children,\n hooks,\n fallback,\n error: errorUI,\n}: WidgetProps) {\n const [connected, setConnected] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [toolLifecycle, setToolLifecycle] = useState(initialToolLifecycle);\n const appRef = useRef<App | null>(null);\n const initRef = useRef<{ metadata: WidgetMetadata; hooks: WidgetHooks | undefined } | null>(\n null,\n );\n if (initRef.current == null) {\n initRef.current = { metadata, hooks };\n }\n\n useEffect(() => {\n let cancelled = false;\n let active = false;\n const { metadata: meta, hooks: initHooks } = initRef.current!;\n const { capabilities, autoResize, strict, name, version, title } = meta;\n const options: AppOptions = {};\n if (autoResize !== undefined) {\n options.autoResize = autoResize;\n }\n if (strict !== undefined) {\n options.strict = strict;\n }\n const app = new App(\n title === undefined ? { name, version } : { name, version, title },\n capabilities ?? {},\n options,\n );\n appRef.current = app;\n setToolLifecycle(initialToolLifecycle());\n app.addEventListener(\"toolinput\", (params) => {\n if (!cancelled) {\n setToolLifecycle((current) => ({\n ...current,\n input: params.arguments,\n inputReceived: true,\n }));\n }\n });\n app.addEventListener(\"toolresult\", (params) => {\n if (!cancelled) {\n setToolLifecycle((current) => ({\n ...current,\n rawResult: params,\n cancellationReason: undefined,\n status: \"result\",\n version: current.version + 1,\n }));\n }\n });\n app.addEventListener(\"toolcancelled\", (params) => {\n if (!cancelled) {\n setToolLifecycle((current) => ({\n ...current,\n rawResult: undefined,\n cancellationReason: params.reason,\n status: \"cancelled\",\n version: current.version + 1,\n }));\n }\n });\n applyHooks(app, initHooks);\n app.onteardown = async (params, extra) => {\n if (active) {\n deactivateWidget(app);\n active = false;\n }\n return (await initHooks?.teardown?.(params, extra)) ?? {};\n };\n\n void (async () => {\n try {\n await initHooks?.before?.();\n if (cancelled) {\n return;\n }\n try {\n await app.connect();\n } catch (err: unknown) {\n if (!(err instanceof Error && err.message.includes(\"already connected\"))) {\n throw err;\n }\n }\n if (cancelled) {\n return;\n }\n activateWidget(app);\n active = true;\n await initHooks?.after?.();\n if (!cancelled) {\n setConnected(true);\n } else {\n deactivateWidget(app);\n active = false;\n }\n } catch (err: unknown) {\n if (active) {\n deactivateWidget(app);\n active = false;\n }\n if (!cancelled) {\n setError(err instanceof Error ? err : new Error(String(err)));\n }\n }\n })();\n\n return () => {\n cancelled = true;\n if (active) {\n deactivateWidget(app);\n active = false;\n }\n void app.close();\n if (appRef.current === app) {\n appRef.current = null;\n }\n };\n }, []);\n\n if (error) {\n if (typeof errorUI === \"function\") return errorUI(error);\n if (errorUI !== undefined) return errorUI;\n return (\n <div>\n <strong>ERROR:</strong> {error.message}\n </div>\n );\n }\n if (!connected || appRef.current == null) {\n return fallback ?? <div>Connecting...</div>;\n }\n\n return (\n <WidgetContext.Provider\n value={{ app: appRef.current, tool: toolLifecycle }}\n >\n {children}\n </WidgetContext.Provider>\n );\n}\n\nexport function mountWidget(Widget: ComponentType): void {\n if (!rootInstance) {\n const element = document.querySelector(\"#root\");\n if (!(element instanceof HTMLElement)) {\n throw new Error(\"Widget root #root was not found\");\n }\n rootInstance = createRoot(element);\n }\n\n rootInstance.render(\n <StrictMode>\n <Widget />\n </StrictMode>,\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.tsx"],"sourcesContent":["import {\n StrictMode,\n createContext,\n useContext,\n useEffect,\n useRef,\n useState,\n type ComponentType,\n type ReactNode,\n} from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport {\n App,\n type AppEventMap,\n type AppOptions,\n type McpUiAppCapabilities,\n} from \"@modelcontextprotocol/ext-apps\";\n\nexport type WidgetMetadata = {\n name: string;\n version: string;\n title?: string;\n capabilities?: McpUiAppCapabilities;\n} & Pick<AppOptions, \"autoResize\" | \"strict\">;\n\nexport type WidgetHooks = {\n before?: () => void | Promise<void>;\n after?: () => void | Promise<void>;\n error?: (error: Error) => void;\n toolInput?: (params: AppEventMap[\"toolinput\"]) => void;\n toolInputPartial?: (params: AppEventMap[\"toolinputpartial\"]) => void;\n toolResult?: (params: AppEventMap[\"toolresult\"]) => void;\n toolCancelled?: (params: AppEventMap[\"toolcancelled\"]) => void;\n hostContextChanged?: (params: AppEventMap[\"hostcontextchanged\"]) => void;\n teardown?: NonNullable<App[\"onteardown\"]>;\n};\n\nexport type WidgetProps = {\n metadata: WidgetMetadata;\n children: ReactNode;\n hooks?: WidgetHooks;\n fallback?: ReactNode;\n error?: ReactNode | ((error: Error) => ReactNode);\n};\n\nconst WidgetContext = createContext<App | null>(null);\n\nexport function useWidget(): App {\n const app = useContext(WidgetContext);\n if (app == null) {\n throw new Error(\"useWidget must be used within a connected <Widget>\");\n }\n return app;\n}\n\nfunction applyHooks(app: App, hooks: WidgetHooks | undefined): void {\n app.onerror = hooks?.error ?? ((error) => console.error(error));\n if (!hooks) {\n return;\n }\n if (hooks.toolInput) {\n app.ontoolinput = hooks.toolInput;\n }\n if (hooks.toolInputPartial) {\n app.ontoolinputpartial = hooks.toolInputPartial;\n }\n if (hooks.toolResult) {\n app.ontoolresult = hooks.toolResult;\n }\n if (hooks.toolCancelled) {\n app.ontoolcancelled = hooks.toolCancelled;\n }\n if (hooks.hostContextChanged) {\n app.onhostcontextchanged = hooks.hostContextChanged;\n }\n if (hooks.teardown) {\n app.onteardown = hooks.teardown;\n }\n}\n\nlet rootInstance: Root | null = null;\n\nexport function Widget({\n metadata,\n children,\n hooks,\n fallback,\n error: errorUI,\n}: WidgetProps) {\n const [connected, setConnected] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const appRef = useRef<App | null>(null);\n const initRef = useRef<{ metadata: WidgetMetadata; hooks: WidgetHooks | undefined } | null>(\n null,\n );\n if (initRef.current == null) {\n initRef.current = { metadata, hooks };\n }\n\n useEffect(() => {\n let cancelled = false;\n const { metadata: meta, hooks: initHooks } = initRef.current!;\n const { capabilities, autoResize, strict, name, version, title } = meta;\n const options: AppOptions = {};\n if (autoResize !== undefined) {\n options.autoResize = autoResize;\n }\n if (strict !== undefined) {\n options.strict = strict;\n }\n const app = new App(\n title === undefined ? { name, version } : { name, version, title },\n capabilities ?? {},\n options,\n );\n appRef.current = app;\n applyHooks(app, initHooks);\n\n void (async () => {\n try {\n await initHooks?.before?.();\n if (cancelled) {\n return;\n }\n try {\n await app.connect();\n } catch (err: unknown) {\n if (!(err instanceof Error && err.message.includes(\"already connected\"))) {\n throw err;\n }\n }\n if (cancelled) {\n return;\n }\n await initHooks?.after?.();\n if (!cancelled) {\n setConnected(true);\n }\n } catch (err: unknown) {\n if (!cancelled) {\n setError(err instanceof Error ? err : new Error(String(err)));\n }\n }\n })();\n\n return () => {\n cancelled = true;\n void app.close();\n if (appRef.current === app) {\n appRef.current = null;\n }\n };\n }, []);\n\n if (error) {\n if (typeof errorUI === \"function\") return errorUI(error);\n if (errorUI !== undefined) return errorUI;\n return (\n <div>\n <strong>ERROR:</strong> {error.message}\n </div>\n );\n }\n if (!connected || appRef.current == null) {\n return fallback ?? <div>Connecting...</div>;\n }\n\n return (\n <WidgetContext.Provider value={appRef.current}>{children}</WidgetContext.Provider>\n );\n}\n\nexport function mountWidget(Widget: ComponentType): void {\n if (!rootInstance) {\n const element = document.querySelector(\"#root\");\n if (!(element instanceof HTMLElement)) {\n throw new Error(\"Widget root #root was not found\");\n }\n rootInstance = createRoot(element);\n }\n\n rootInstance.render(\n <StrictMode>\n <Widget />\n </StrictMode>,\n );\n}\n"],"mappings":"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"}
package/dist/vite.js CHANGED
@@ -81,14 +81,14 @@ function assertNoInvalidWidgets(invalid) {
81
81
  }
82
82
  //#endregion
83
83
  //#region src/vite.ts
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();
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();
92
92
  function getWidgetEntryPattern(srcDir) {
93
93
  const escaped = normalizePath(srcDir).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
94
94
  return new RegExp(`${escaped}\/[^/]+\/widget\\.tsx(?:\\?.*)?$`);
@@ -142,12 +142,13 @@ 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, configFile) {
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");
146
147
  const previousWidgetPath = process.env[INTERNAL_WIDGET_PATH_ENV];
147
148
  process.env[INTERNAL_WIDGET_PATH_ENV] = widget.filePath;
148
149
  try {
149
150
  await build({
150
- configFile,
151
+ configFile: config.configFile,
151
152
  configLoader: "native",
152
153
  root: config.root,
153
154
  mode: config.mode,
@@ -277,7 +278,7 @@ function belgie(options = {}) {
277
278
  recursive: true,
278
279
  force: true
279
280
  });
280
- for (const widget of widgetMap.values()) await buildWidget(widget, resolvedConfig, resolvedConfig.configFile);
281
+ for (const widget of widgetMap.values()) await buildWidget(widget, resolvedConfig);
281
282
  },
282
283
  configureServer(server) {
283
284
  if (!resolvedSrcDir) {
@@ -331,8 +332,7 @@ function belgie(options = {}) {
331
332
  });
332
333
  },
333
334
  transform(code, id) {
334
- const normalizedId = normalizePath(id);
335
- if (widgetEntryPattern?.test(normalizedId) && !hasDefaultExport(code)) this.warn(`Widget file "${normalizedId.split("/").pop()}" is missing a default export.`);
335
+ if (widgetEntryPattern?.test(id) && !hasDefaultExport(code)) this.warn(`Widget file "${id.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(\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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"}
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":";;;;AAOA,SAAgB,mBAAmB,OAAuB;CACxD,OAAO,MAAM,QAAQ,eAAe,YAAY;AAClD;AAEA,SAAgB,kBAAkB,OAAuB;CACvD,OAAO,MAAM,QAAQ,cAAc,WAAW;AAChD;AAEA,SAAgB,kBAAkB,gBAAgC;CAChE,MAAM,aAAa,eAAe,QAAQ,OAAO,GAAG;CACpD,OAAO;EACL;EACA,sBAAsB,KAAK,UAAU,UAAU,EAAE;EACjD;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;AACb;AAEA,SAAgB,yBAAyB,SAA4C;CACnF,MAAM,OAAO;EACX;EACA;EACA,IAAI,QAAQ,UAAU,CAAC,EAAA,CAAG,KAAK,SAAS,4CAA4C,KAAK,GAAG;EAC5F,IAAI,QAAQ,gBAAgB,CAAC,EAAA,CAAG,KAAK,UAAU,UAAU,kBAAkB,KAAK,EAAE,SAAS;CAC7F;CACA,MAAM,UAAU,CACd,IAAI,QAAQ,WAAW,CAAC,EAAA,CAAG,KAAK,QAAQ,0CAA0C,IAAI,aAAY,GAClG,GAAI,QAAQ,iBAAiB,KAAA,IACzB,CAAC,IACD,CAAC,yBAAyB,mBAAmB,QAAQ,YAAY,EAAE,WAAU,CACnF;CACA,OAAO;EACL;EACA;EACA;EACA,GAAG;EACH;EACA;EACA;EACA,GAAG;EACH;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;AACb;;;ACpDA,SAAS,cAAc,MAAsB;CAC3C,OAAO,KAAK,QAAQ,aAAa,EAAE,CAAC,CAAC,QAAQ,qBAAqB,EAAE;AACtE;AAEA,SAAgB,iBAAiB,MAAuB;CACtD,MAAM,WAAW,cAAc,IAAI;CACnC,OACE,qBAAqB,KAAK,QAAQ,KAClC,yCAAyC,KAAK,QAAQ;AAE1D;;;ACSA,SAAgB,gBAAgB,QAAkC;CAEhE,MAAM,aAAa,SADH,QAAQ,QAAQ,cACJ,CAAO,CAAC,CAAC,KAAK,UAAU;EAClD,MAAM,SAAS,QAAQ,IAAI,CAAC;EAC5B,UAAU;CACZ,EAAE;CAEF,MAAM,QAA2B,CAAC;CAClC,MAAM,UAA2B,CAAC;CAClC,KAAK,MAAM,aAAa,YAEtB,IAAI,iBADS,aAAa,UAAU,UAAU,OACzB,CAAI,GACvB,MAAM,KAAK,SAAS;MAEpB,QAAQ,KAAK,EAAE,UAAU,UAAU,SAAS,CAAC;CAIjD,OAAO;EAAE;EAAO;CAAQ;AAC1B;AAEA,SAAgB,wBAAwB,SAAkC;CACxE,MAAM,0BAAU,IAAI,IAAsB;CAC1C,KAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,QAAQ,QAAQ,IAAI,OAAO,IAAI,KAAK,CAAC;EAC3C,MAAM,KAAK,OAAO,QAAQ;EAC1B,QAAQ,IAAI,OAAO,MAAM,KAAK;CAChC;CAEA,KAAK,MAAM,CAAC,MAAM,UAAU,SAC1B,IAAI,MAAM,SAAS,GACjB,MAAM,IAAI,MACR,kCAAkC,KAAK,wBAAwB,MAAM,KAAK,QAAQ,EAAE,iDACtF;AAGN;AAEA,SAAgB,uBAAuB,SAAgC;CACrE,IAAI,QAAQ,WAAW,GACrB;CAEF,MAAM,QAAQ,QAAQ,KAAK,WAAW,OAAO,QAAQ,CAAC,CAAC,KAAK,QAAQ;CACpE,MAAM,IAAI,MACR,yDAAyD,MAAM,mDACjE;AACF;;;ACnDA,IAAM,iBAAiB;AACvB,IAAM,wBAAwB;AAC9B,IAAM,yBAAyB;AAC/B,IAAM,kCAAkC;AACxC,IAAM,2BAA2B;AACjC,IAAM,wBAAwB,OAAO;AACrC,IAAM,4BAA4B;AAClC,IAAM,eAAe,IAAI,YAAY;AA2BrC,SAAS,sBAAsB,QAAwB;CACrD,MAAM,UAAU,cAAc,MAAM,CAAC,CAAC,QAAQ,uBAAuB,MAAM;CAC3E,OAAO,IAAI,OAAO,GAAG,QAAQ,iCAAiC;AAChE;AAEA,SAAS,kBAAkB,IAAgC;CACzD,IAAI,CAAC,GAAG,WAAW,cAAc,GAC/B;CAEF,OAAO,mBAAmB,GAAG,MAAM,EAAqB,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE;AAClF;AAEA,SAAS,UAAU,OAA2B;CAC5C,OAAO,OAAO,MAAM,WAAW,WAAW,MAAM,SAAS,aAAa,OAAO,MAAM,MAAM;AAC3F;AAEA,SAAS,mBAAmB,MAAc,QAA+C;CACvF,MAAM,YAAY,OAAO,OAAO,MAAM;CACtC,MAAM,SAAS,UAAU,QAAQ,aAAqC,SAAS,SAAS,OAAO;CAC/F,MAAM,UAAU,OAAO,QAAQ,UAAU,MAAM,OAAO;CACtD,IAAI,QAAQ,WAAW,GACrB,MAAM,IAAI,MAAM,gDAAgD,KAAK,cAAc,QAAQ,QAAQ;CAGrG,MAAM,QAAQ,QAAQ;CACtB,MAAM,cAAc,OAAO,QAAQ,UAAU,UAAU,KAAK;CAC5D,IAAI,YAAY,SAAS,GACvB,MAAM,IAAI,MACR,mBAAmB,KAAK,0BAA0B,YAAY,KAAK,UAAU,MAAM,QAAQ,CAAC,CAAC,KAAK,IAAI,GACxG;CAGF,MAAM,UAAU,CAAC,GAAG,MAAM,SAAS,GAAG,MAAM,cAAc,CAAC,CAAC,QAAQ,SAAS,SAAS,MAAM,QAAQ;CACpG,IAAI,QAAQ,SAAS,GACnB,MAAM,IAAI,MAAM,mBAAmB,KAAK,sBAAsB,QAAQ,KAAK,IAAI,GAAG;CAGpF,MAAM,SAAS,UAAU,QAAQ,aAAqC,SAAS,SAAS,OAAO;CAC/F,MAAM,eAAe,OAAO,QAAQ,UAAU,CAAC,MAAM,SAAS,SAAS,MAAM,CAAC;CAC9E,IAAI,aAAa,SAAS,GACxB,MAAM,IAAI,MACR,mBAAmB,KAAK,4BAA4B,aAAa,KAAK,UAAU,MAAM,QAAQ,CAAC,CAAC,KAAK,IAAI,GAC3G;CAGF,MAAM,eAAe,IAAI,IAAI,OAAO,KAAK,UAAU,CAAC,MAAM,UAAU,KAAK,CAAC,CAAC;CAC3E,MAAM,cAAc,CAAC,GAAI,MAAM,cAAc,eAAe,CAAC,CAAE;CAE/D,MAAM,UADW,YAAY,SAAS,IAAI,cAAc,OAAO,KAAK,UAAU,MAAM,QAAQ,CAAC,CAAC,KAAK,EAAA,CAC3E,KAAK,YAAY;EACvC,MAAM,QAAQ,aAAa,IAAI,OAAO;EACtC,IAAI,UAAU,KAAA,GACZ,MAAM,IAAI,MAAM,mBAAmB,KAAK,iCAAiC,SAAS;EAEpF,OAAO,UAAU,KAAK;CACxB,CAAC;CACD,OAAO,yBAAyB;EAAE,cAAc,MAAM;EAAM,cAAc;CAAO,CAAC;AACpF;AAEA,SAAS,mBAAmB,MAAc,UAAoC;CAC5E,IAAI,aAAa,KAAA,GACf,OAAO,QAAQ,IAAI;MAEnB,QAAQ,IAAI,QAAQ;AAExB;AAEA,SAAS,2BAA2B,MAAc,MAAc,SAA0B;CACxF,IAAI,CAAC,WAAW,KAAK,SAAS,gBAAgB,GAC5C,OAAO;CAGT,MAAM,cAAc,GADG,KAAK,SAAS,GAAG,IAAI,OAAO,GAAG,KAAK,GACrB;CACtC,MAAM,WAAW;EACf;EACA,wCAAwC,KAAK,UAAU,WAAW,EAAE;EACpE;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;CACX,OAAO,KAAK,QAAQ,UAAU,WAAW,UAAU;AACrD;AAEA,eAAe,YAAY,QAAyB,QAAuC;CACzF,IAAI,CAAC,OAAO,YACV,MAAM,IAAI,MACR,6FACF;CAEF,MAAM,qBAAqB,QAAQ,IAAI;CACvC,QAAQ,IAAI,4BAA4B,OAAO;CAC/C,IAAI;EACF,MAAM,MAAM;GACV,YAAY,OAAO;GACnB,cAAc;GACd,MAAM,OAAO;GACb,MAAM,OAAO;GACb,GAAI,OAAO,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU,OAAO,SAAS;GACrE,OAAO;IACL,aAAa;IACb,QAAQ;GACV;EACF,CAAC;CACH,UAAU;EACR,mBAAmB,0BAA0B,kBAAkB;CACjE;AACF;AAEA,SAAgB,OAAO,UAA+B,CAAC,GAAW;CAChE,MAAM,YAAY,QAAQ,UAAU;CACpC,MAAM,sBAAsB,QAAQ,IAAI;CACxC,IAAI,iBAAiB;CACrB,IAAI,cAAc;CAClB,IAAI;CACJ,IAAI,4BAAY,IAAI,IAA6B;CACjD,IAAI;CACJ,IAAI,yBAAyB;CAC7B,IAAI,iBAAiB;CAErB,OAAO;EACL,MAAM;EACN,SAAS;EACT,KAAK,EAAE,QAAQ,UAAU;EAEzB,QAAQ;GACN,OAAO;GACP,QAAQ,QAAoB,EAAE,WAAW;IACvC,iBAAiB,YAAY;IAC7B,cAAc,OAAO,QAAQ,QAAQ,IAAI;IACzC,iBAAiB,WAAW,SAAS,IAAI,YAAY,QAAQ,aAAa,SAAS;IACnF,qBAAqB,sBAAsB,cAAc;IAEzD,MAAM,EAAE,OAAO,YAAY,gBAAgB,cAAc;IACzD,wBAAwB,KAAK;IAC7B,IAAI,YAAY,SACd,uBAAuB,OAAO;IAGhC,IAAI,wBAAwB,KAAA,GAAW;KACrC,MAAM,0BAA0B,cAAc,QAAQ,mBAAmB,CAAC;KAC1E,MAAM,SAAS,MAAM,MAAM,cAAc,cAAc,QAAQ,UAAU,QAAQ,CAAC,MAAM,uBAAuB;KAC/G,IAAI,WAAW,KAAA,GACb,MAAM,IAAI,MACR,yDAAyD,cAAc,mBAAmB,GAC5F;KAEF,4BAAY,IAAI,IAAI,CAAC,CAAC,OAAO,MAAM,MAAM,CAAC,CAAC;KAC3C,OAAO;MACL,SAAS;MACT,SAAS,EAAE,QAAQ,CAAC,SAAS,WAAW,EAAE;MAC1C,OAAO;OACL,mBAAmB;OACnB,eAAe;OACf,cAAc;OACd,aAAa;OACb,SAAS;OACT,UAAU;OACV,eAAe;OACf,QAAQ;OACR,sBAAsB;OACtB,WAAW;OACX,aAAa;OACb,OAAO;OACP,OAAO;OACP,iBAAiB;QACf,OAAO,GAAG,iBAAiB,mBAAmB,OAAO,IAAI;QACzD,QAAQ,EAAE,eAAe,MAAM;OACjC;MACF;KACF;IACF;IAEA,YAAY,IAAI,IAAI,MAAM,KAAK,WAAW,CAAC,OAAO,MAAM,MAAM,CAAC,CAAC;IAChE,MAAM,gBAAgB,OAAO,OAAO,iBAAiB;IACrD,yBAAyB,kBAAkB,KAAA;IAC3C,OAAO;KACL,SAAS,EAAE,QAAQ,CAAC,SAAS,WAAW,EAAE;KAC1C,OAAO,EACL,iBAAiB,EACf,OAAO,iBAAiB,uBAC1B,EACF;KACA,cAAc;MACZ,SAAS,CAAC,GAAG,eAAe,cAAc;MAC1C,SAAS;OAAC;OAAS;OAAoB;MAAmB;KAC5D;IACF;GACF;EACF;EAEA,eAAe,QAAQ;GACrB,iBAAiB;GACjB,cAAc,OAAO;GACrB,IAAI,CAAC,gBACH,iBAAiB,WAAW,SAAS,IAAI,YAAY,QAAQ,aAAa,SAAS;EAEvF;EAEA,UAAU,IAAI;GACZ,IAAI,OAAO,wBACT,OAAO;GAET,MAAM,OAAO,kBAAkB,EAAE;GACjC,IAAI,SAAS,KAAA,KAAa,UAAU,IAAI,IAAI,GAC1C,OAAO,GAAG,wBAAwB;GAEpC,OAAO;EACT;EAEA,KAAK,IAAI;GACP,IAAI,OAAO,iCACT,OAAO;GAET,IAAI,GAAG,WAAW,qBAAqB,GAAG;IACxC,MAAM,SAAS,UAAU,IAAI,GAAG,MAAM,EAA4B,CAAC;IACnE,IAAI,WAAW,KAAA,GACb,OAAO,kBAAkB,OAAO,QAAQ;GAE5C;GACA,OAAO;EACT;EAEA,gBAAgB;GACd,OAAO;GACP,QAAQ,UAAU,QAAQ;IACxB,IAAI,wBAAwB,KAAA,GAAW;KACrC,MAAM,SAAS,CAAC,GAAG,UAAU,OAAO,CAAC,CAAC,CAAC;KACvC,IAAI,WAAW,KAAA,GACb,MAAM,IAAI,MAAM,qDAAqD;KAEvE,MAAM,OAAO,mBAAmB,OAAO,MAAM,MAAuC;KACpF,KAAK,MAAM,YAAY,OAAO,KAAK,MAAM,GACvC,OAAO,OAAO;KAEhB,KAAK,SAAS;MACZ,MAAM;MACN,UAAU,WAAW,OAAO,KAAK;MACjC,QAAQ;KACV,CAAC;KACD;IACF;IAEA,IAAI;UACG,MAAM,CAAC,UAAU,aAAa,OAAO,QAAQ,MAAM,GACtD,IAAI,SAAS,SAAS,WAAW,SAAS,mBAAmB,iCAC3D,OAAO,OAAO;IAAA;GAItB;EACF;EAEA,MAAM,cAAc;GAClB,IAAI,CAAC,kBAAkB,wBAAwB,KAAA,KAAa,mBAAmB,KAAA,KAAa,UAAU,SAAS,GAC7G;GAEF,IAAI,CAAC,eAAe,YAClB,MAAM,IAAI,MACR,6FACF;GAEF,OAAO,QAAQ,aAAa,QAAQ,SAAS,GAAG;IAAE,WAAW;IAAM,OAAO;GAAK,CAAC;GAChF,KAAK,MAAM,UAAU,UAAU,OAAO,GACpC,MAAM,YAAY,QAAQ,cAAc;EAE5C;EAEA,gBAAgB,QAAQ;GACtB,IAAI,CAAC,gBAAgB;IACnB,MAAM,OAAO,OAAO,OAAO,QAAQ,QAAQ,IAAI;IAC/C,iBAAiB,WAAW,SAAS,IAAI,YAAY,QAAQ,MAAM,SAAS;IAC5E,cAAc;IACd,qBAAqB,sBAAsB,cAAc;GAC3D;GAEA,OAAO,QAAQ,IAAI,cAAc;GACjC,IAAI,+BAAe,IAAI,IAAY;GACnC,MAAM,eAAe;IACnB,IAAI;KACF,MAAM,EAAE,OAAO,YAAY,gBAAgB,cAAc;KACzD,MAAM,cAAc,IAAI,IAAI,QAAQ,KAAK,WAAW,OAAO,QAAQ,CAAC;KAEpE,KAAK,MAAM,YAAY,aACrB,IAAI,CAAC,aAAa,IAAI,QAAQ,GAC5B,OAAO,OAAO,OAAO,KACnB,yBAAyB,SAAS,aAAa,QAAQ,EAAE,+DAC3D;KAGJ,KAAK,MAAM,YAAY,cACrB,IAAI,CAAC,YAAY,IAAI,QAAQ,GAC3B,OAAO,OAAO,OAAO,KAAK,yBAAyB,SAAS,aAAa,QAAQ,EAAE,YAAY;KAGnG,eAAe;KAEf,wBAAwB,KAAK;KAC7B,YAAY,IAAI,IAAI,MAAM,KAAK,WAAW,CAAC,OAAO,MAAM,MAAM,CAAC,CAAC;IAClE,SAAS,OAAO;KACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;KACrE,OAAO,OAAO,OAAO,MAAM,kCAAkC,SAAS;IACxE;GACF;GAEA,OAAO;GACP,OAAO,QAAQ,GAAG,OAAO,MAAM;GAC/B,OAAO,QAAQ,GAAG,UAAU,MAAM;GAClC,OAAO,QAAQ,GAAG,UAAU,MAAM;GAElC,OAAO,YAAY,IAAI,OAAO,SAAS,UAAU,SAAS;IACxD,IAAI;KACF,MAAM,WAAW,IAAI,IAAI,QAAQ,OAAO,KAAK,kBAAkB,CAAC,CAAC;KACjE,MAAM,QAAQ,oCAAoC,KAAK,QAAQ;KAC/D,MAAM,OAAO,QAAQ,OAAO,KAAA,IAAY,KAAA,IAAY,mBAAmB,MAAM,EAAE;KAC/E,IAAI,SAAS,KAAA,GAAW;MACtB,KAAK;MACL;KACF;KACA,IAAI,CAAC,UAAU,IAAI,IAAI,GAAG;MACxB,SAAS,aAAa;MACtB,SAAS,UAAU,gBAAgB,2BAA2B;MAC9D,SAAS,IAAI,mBAAmB,MAAM;MACtC;KACF;KAMA,MAAM,OAAO,2BACX,MAN4B,OAAO,mBACnC,UACA,yBAAyB,EAAE,SAAS,CAAC,GAAG,iBAAiB,mBAAmB,IAAI,GAAG,EAAE,CAAC,GACtF,QAAQ,GACV,GAGE,OAAO,OAAO,MACd,OAAO,OAAO,QAAQ,MAAM,WAAW,OAAO,SAAS,yBAAyB,CAClF;KACA,SAAS,aAAa;KACtB,SAAS,UAAU,gBAAgB,0BAA0B;KAC7D,SAAS,IAAI,IAAI;IACnB,SAAS,OAAO;KACd,KAAK,KAAK;IACZ;GACF,CAAC;EACH;EAEA,UAAU,MAAM,IAAI;GAClB,IAAI,oBAAoB,KAAK,EAAE,KAAK,CAAC,iBAAiB,IAAI,GACxD,KAAK,KAAK,gBAAgB,GAAG,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,+BAA+B;GAE/E,OAAO;EACT;CACF;AACF"}