mountly-mcp 3.1.0 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/README.md +59 -29
  2. package/dist/bridge/iframe-entry.js +24 -16
  3. package/dist/bridge/index.d.ts +5 -5
  4. package/dist/bridge/index.js +2 -2
  5. package/dist/build/index.d.ts +3 -3
  6. package/dist/build/index.js +2 -2
  7. package/dist/{chunk-NLQDVNZP.js → chunk-AEVQKFXX.js} +12 -8
  8. package/dist/chunk-AEVQKFXX.js.map +1 -0
  9. package/dist/{chunk-SNWNF2XI.js → chunk-JVQZGKBL.js} +13 -13
  10. package/dist/chunk-JVQZGKBL.js.map +1 -0
  11. package/dist/chunk-KWVGW5Q7.js +582 -0
  12. package/dist/chunk-KWVGW5Q7.js.map +1 -0
  13. package/dist/{chunk-DQLQOMDM.js → chunk-M4WFJR3C.js} +2 -2
  14. package/dist/{chunk-DQLQOMDM.js.map → chunk-M4WFJR3C.js.map} +1 -1
  15. package/dist/{chunk-4WAKOYMK.js → chunk-MTJDRWGD.js} +2 -2
  16. package/dist/chunk-MTJDRWGD.js.map +1 -0
  17. package/dist/chunk-SADNMGP6.js +16 -0
  18. package/dist/chunk-SADNMGP6.js.map +1 -0
  19. package/dist/cli.js +21 -10
  20. package/dist/cli.js.map +1 -1
  21. package/dist/create.d.ts +10 -0
  22. package/dist/create.js +113 -0
  23. package/dist/create.js.map +1 -0
  24. package/dist/dev/host-entry.js +2 -2
  25. package/dist/dev/index.d.ts +1 -1
  26. package/dist/dev/index.js +1 -1
  27. package/dist/index.d.ts +1 -0
  28. package/dist/index.js +10 -2
  29. package/dist/json-render/{widget.d.ts → generative-view.d.ts} +9 -11
  30. package/dist/json-render/index.d.ts +1 -1
  31. package/dist/json-render/index.js +9 -8
  32. package/dist/json-render/index.js.map +1 -1
  33. package/dist/publish.d.ts +10 -0
  34. package/dist/react/context.d.ts +1 -1
  35. package/dist/react/create-view.d.ts +8 -0
  36. package/dist/react/hooks.d.ts +1 -1
  37. package/dist/react/index.d.ts +1 -1
  38. package/dist/react/index.js +6 -5
  39. package/dist/schema.d.ts +2 -2
  40. package/dist/server/index.d.ts +2 -2
  41. package/dist/server/index.js.map +1 -1
  42. package/dist/svelte/index.d.ts +10 -16
  43. package/dist/svelte/index.js +7 -3
  44. package/dist/svelte/index.js.map +1 -1
  45. package/dist/testing/index.d.ts +1 -1
  46. package/dist/testing/index.js +1 -1
  47. package/dist/testing/index.js.map +1 -1
  48. package/dist/types.d.ts +14 -4
  49. package/dist/vite/index.d.ts +6 -6
  50. package/dist/vite/index.js +7 -7
  51. package/dist/vite/index.js.map +1 -1
  52. package/dist/vue/index.d.ts +12 -17
  53. package/dist/vue/index.js +10 -6
  54. package/dist/vue/index.js.map +1 -1
  55. package/package.json +11 -15
  56. package/templates/react/.gitignore.tmpl +4 -0
  57. package/templates/react/README.md.tmpl +15 -0
  58. package/templates/react/mcp.fixtures.json.tmpl +4 -0
  59. package/templates/react/package.json.tmpl +27 -0
  60. package/templates/react/server.mjs.tmpl +70 -0
  61. package/templates/react/src/view.tsx.tmpl +160 -0
  62. package/templates/react/tsconfig.json.tmpl +15 -0
  63. package/templates/react/vite.config.ts.tmpl +22 -0
  64. package/templates/svelte/.gitignore.tmpl +4 -0
  65. package/templates/svelte/README.md.tmpl +14 -0
  66. package/templates/svelte/mcp.fixtures.json.tmpl +4 -0
  67. package/templates/svelte/package.json.tmpl +26 -0
  68. package/templates/svelte/server.mjs.tmpl +70 -0
  69. package/templates/svelte/src/Dashboard.svelte.tmpl +158 -0
  70. package/templates/svelte/src/view.ts.tmpl +14 -0
  71. package/templates/svelte/tsconfig.json.tmpl +14 -0
  72. package/templates/svelte/vite.config.ts.tmpl +22 -0
  73. package/templates/vanilla/.gitignore.tmpl +4 -0
  74. package/templates/vanilla/README.md.tmpl +20 -0
  75. package/templates/vanilla/mcp.fixtures.json.tmpl +4 -0
  76. package/templates/vanilla/package.json.tmpl +22 -0
  77. package/templates/vanilla/server.mjs.tmpl +70 -0
  78. package/templates/vanilla/src/view.ts.tmpl +177 -0
  79. package/templates/vanilla/tsconfig.json.tmpl +14 -0
  80. package/templates/vanilla/vite.config.ts.tmpl +20 -0
  81. package/templates/vue/.gitignore.tmpl +4 -0
  82. package/templates/vue/README.md.tmpl +14 -0
  83. package/templates/vue/mcp.fixtures.json.tmpl +4 -0
  84. package/templates/vue/package.json.tmpl +26 -0
  85. package/templates/vue/server.mjs.tmpl +70 -0
  86. package/templates/vue/src/Dashboard.vue.tmpl +159 -0
  87. package/templates/vue/src/view.ts.tmpl +14 -0
  88. package/templates/vue/tsconfig.json.tmpl +15 -0
  89. package/templates/vue/vite.config.ts.tmpl +22 -0
  90. package/dist/chunk-4WAKOYMK.js.map +0 -1
  91. package/dist/chunk-KRAS266U.js +0 -260
  92. package/dist/chunk-KRAS266U.js.map +0 -1
  93. package/dist/chunk-NLQDVNZP.js.map +0 -1
  94. package/dist/chunk-SNWNF2XI.js.map +0 -1
  95. package/dist/react/create-widget.d.ts +0 -11
package/README.md CHANGED
@@ -1,29 +1,51 @@
1
1
  # mountly-mcp
2
2
 
3
- **Build MCP Apps from the components you already have — in React, Vue, or Svelte.**
3
+ **Build MCP Apps from React, Vue, or Svelte components — new or existing.**
4
4
 
5
5
  [MCP Apps](https://github.com/modelcontextprotocol/ext-apps) (SEP-1865) lets an
6
6
  MCP server render interactive UI inside Claude, ChatGPT and other hosts. The
7
- official SDK gives you the protocol and expects you to hand-write the view.
8
- `mountly-mcp` starts from a component instead:
7
+ official SDK gives you the protocol. `mountly-mcp` is the view layer on top:
8
+ write a component, get a `ui://` resource, a local host, and server registration
9
+ without hand-writing the handshake HTML.
9
10
 
10
11
  ```ts
11
- import { createMcpWidget } from "mountly-mcp/vue";
12
- import Dashboard from "./Dashboard.vue";
12
+ import { createMcpView } from "mountly-mcp/react";
13
+ import Dashboard from "./Dashboard";
13
14
 
14
- (globalThis as { __mountlyMcpWidget__?: unknown }).__mountlyMcpWidget__ =
15
- createMcpWidget(Dashboard);
15
+ createMcpView(Dashboard);
16
16
  ```
17
17
 
18
- `mountly-mcp build` turns that into a versioned App manifest containing one or
19
- many `ui://` resources. `registerMcpApps` installs them into the MCP server your
20
- application already owns. Your component is unchanged, and the same one can
21
- keep running on your website.
18
+ That path is the default whether the dashboard is three metric cards for one
19
+ host or a multi-View production server. Prefer the scaffolder for greenfield:
22
20
 
23
- **If you're on React and starting from scratch**, the official
24
- [`@modelcontextprotocol/ext-apps`](https://www.npmjs.com/package/@modelcontextprotocol/ext-apps)
25
- skills are the shorter path — this package is worth it when you have existing
26
- components, a Vite build, or a framework other than React.
21
+ ```bash
22
+ npx mountly-mcp create my-app --framework react
23
+ cd my-app && pnpm install && pnpm dev
24
+ ```
25
+
26
+ `--framework` takes `react`, `vue`, `svelte`, or `vanilla`. Vanilla pulls in no
27
+ framework and no adapter: a View is just `mount` / `update` / `unmount`, so
28
+ `publishMcpView` takes the object directly and the bridge drives it the same
29
+ way it drives the others.
30
+
31
+ ## Build with Agent Skills
32
+
33
+ | Skill | Try it |
34
+ | --- | --- |
35
+ | [`create-mcp-app`](../../plugins/mountly-mcp/skills/create-mcp-app/SKILL.md) | _"Create an MCP App"_ |
36
+ | [`add-app-to-server`](../../plugins/mountly-mcp/skills/add-app-to-server/SKILL.md) | _"Add UI to my MCP server"_ |
37
+ | [`convert-web-app`](../../plugins/mountly-mcp/skills/convert-web-app/SKILL.md) | _"Turn my component into an MCP App"_ |
38
+ | [`migrate-ext-apps`](../../plugins/mountly-mcp/skills/migrate-ext-apps/SKILL.md) | _"Migrate from ext-apps"_ |
39
+
40
+ ```
41
+ /plugin marketplace add jagreehal/mountly
42
+ /plugin install mountly-mcp@mountly
43
+ ```
44
+
45
+ Docs: [Agent Skills](https://mountly.dev/mcp-apps/agent-skills/).
46
+ `mountly-mcp build` emits a versioned App manifest; `registerMcpApps` installs
47
+ the Views into the MCP server you already own. Existing website components stay
48
+ reusable as-is.
27
49
 
28
50
  The wire protocol is delegated to the official `@modelcontextprotocol/sdk` and
29
51
  `@modelcontextprotocol/ext-apps` packages in full, so server transports,
@@ -33,8 +55,11 @@ reimplementation of it. Both are runtime dependencies of `mountly-mcp`.
33
55
  ## Install
34
56
 
35
57
  ```bash
36
- npm install mountly-mcp mountly
37
- npm install mountly-vue # or mountly-react / mountly-svelte
58
+ # React (default) — mountly + mountly-react included
59
+ npm install mountly-mcp react react-dom
60
+
61
+ # Vue / Svelte
62
+ npm install mountly-mcp mountly-vue vue # or mountly-svelte + svelte
38
63
  ```
39
64
 
40
65
  Install `@modelcontextprotocol/sdk` directly only when your application imports
@@ -46,12 +71,12 @@ server entry point does not require a separate SDK install.
46
71
  ```ts
47
72
  // vite.config.ts
48
73
  import vue from "@vitejs/plugin-vue";
49
- import { mountlyMcpWidget } from "mountly-mcp/vite";
74
+ import { mountlyMcpViews } from "mountly-mcp/vite";
50
75
 
51
76
  export default defineConfig({
52
77
  plugins: [
53
78
  vue(),
54
- mountlyMcpWidget({
79
+ mountlyMcpViews({
55
80
  apps: [
56
81
  {
57
82
  entry: "src/dashboard.ts",
@@ -89,7 +114,7 @@ npx mountly-mcp dev
89
114
  npx mountly-mcp dev --app weather_dashboard
90
115
  ```
91
116
 
92
- Builds the widget, serves it in a local MCP Apps host, and rebuilds on save.
117
+ Builds the View, serves it in a local MCP Apps host, and rebuilds on save.
93
118
  Config comes from the plugin already in your vite config.
94
119
 
95
120
  It's a real host, not a preview: the published official `AppBridge` drives the
@@ -249,10 +274,10 @@ renders what it can. Drop the loose branch once core relaxes those fields.
249
274
  | Entry | What's in it |
250
275
  | ---------------------- | -------------------------------------------------------- |
251
276
  | `mountly-mcp` | `runBridge`, spec types re-exported from ext-apps |
252
- | `mountly-mcp/react` | `createMcpWidget` + hooks |
253
- | `mountly-mcp/vue` | `createMcpWidget` + composables |
254
- | `mountly-mcp/svelte` | `createMcpWidget` (props-based) |
255
- | `mountly-mcp/vite` | single- and multi-View `mountlyMcpWidget()` build plugin |
277
+ | `mountly-mcp/react` | `createMcpView` + hooks |
278
+ | `mountly-mcp/vue` | `createMcpView` + composables |
279
+ | `mountly-mcp/svelte` | `createMcpView` (props-based) |
280
+ | `mountly-mcp/vite` | single- and multi-View `mountlyMcpViews()` build plugin |
256
281
  | `mountly-mcp/artifact` | versioned manifest and App artifact APIs |
257
282
  | `mountly-mcp/dev` | `startDevHost()` and in-process server connectivity |
258
283
  | `mountly-mcp/build` | `buildMcpResource` for other bundlers |
@@ -262,13 +287,18 @@ renders what it can. Drop the loose branch once core relaxes those fields.
262
287
  Types use the spec's own names (`McpUiHostContext`, `McpUiDisplayMode`, …) —
263
288
  one vocabulary, no translation layer.
264
289
 
265
- ## Agent Skill
290
+ ## Agent Skills
291
+
292
+ Install the plugin skills and ask your coding agent to create an MCP App:
293
+ [Agent Skills docs](https://mountly.dev/mcp-apps/agent-skills/) ·
294
+ [`create-mcp-app`](../../plugins/mountly-mcp/skills/create-mcp-app/SKILL.md).
266
295
 
267
- Ask your coding agent for an MCP App and let it scaffold:
268
- [`plugins/mountly-mcp/skills/create-mcp-widget`](../../../plugins/mountly-mcp/skills/create-mcp-widget/SKILL.md).
296
+ Greenfield without an agent: `npx mountly-mcp create my-app --framework react`.
269
297
 
270
298
  ## See also
271
299
 
272
- - [`docs/examples/mcp-app-demo`](../../../docs/examples/mcp-app-demo) — full demo
273
- with a sandbox-proxy preview host and an out-of-process stdio check
300
+ - [`docs/examples/mcp-release-readiness`](../../docs/examples/mcp-release-readiness) —
301
+ production-shaped Vite View (closest to `create`)
302
+ - [`docs/examples/mcp-app-demo`](../../docs/examples/mcp-app-demo) — advanced
303
+ protocol harness (not the greenfield starter)
274
304
  - `docs/how-to-test.md`
@@ -18556,7 +18556,7 @@ container holding the app. Specify either width or maxWidth, and either height o
18556
18556
  INITIALIZE_FAILED: "mountly-mcp/initialize-failed",
18557
18557
  INITIALIZE_TIMEOUT: "mountly-mcp/initialize-timeout",
18558
18558
  TOOL_CALL_FAILED: "mountly-mcp/tool-call-failed",
18559
- WIDGET_MOUNT_THREW: "mountly-mcp/widget-mount-threw",
18559
+ VIEW_MOUNT_THREW: "mountly-mcp/view-mount-threw",
18560
18560
  INVALID_ORIGIN: "mountly-mcp/invalid-origin"
18561
18561
  };
18562
18562
 
@@ -18573,7 +18573,7 @@ container holding the app. Specify either width or maxWidth, and either height o
18573
18573
  }
18574
18574
  function runBridge(options) {
18575
18575
  const {
18576
- widget: widget2,
18576
+ view: view2,
18577
18577
  container: container2,
18578
18578
  awaitToolResult: awaitToolResult2 = true,
18579
18579
  streamToolInput: streamToolInput2 = false,
@@ -18612,31 +18612,31 @@ container holding the app. Specify either width or maxWidth, and either height o
18612
18612
  if (stopped) return;
18613
18613
  try {
18614
18614
  if (!mounted) {
18615
- const r2 = widget2.mount(container2, props);
18615
+ const r2 = view2.mount(container2, props);
18616
18616
  if (r2 instanceof Promise) await r2;
18617
18617
  mounted = true;
18618
18618
  container2.setAttribute("data-mountly-mcp-state", "mounted");
18619
- } else if (widget2.update) {
18620
- const r2 = widget2.update(container2, props);
18619
+ } else if (view2.update) {
18620
+ const r2 = view2.update(container2, props);
18621
18621
  if (r2 instanceof Promise) await r2;
18622
18622
  } else {
18623
- await widget2.unmount(container2);
18623
+ await view2.unmount(container2);
18624
18624
  mounted = false;
18625
- const r2 = widget2.mount(container2, props);
18625
+ const r2 = view2.mount(container2, props);
18626
18626
  if (r2 instanceof Promise) await r2;
18627
18627
  mounted = true;
18628
18628
  }
18629
18629
  } catch (error51) {
18630
- notifyError(MCP_ERROR_CODES.WIDGET_MOUNT_THREW, error51);
18630
+ notifyError(MCP_ERROR_CODES.VIEW_MOUNT_THREW, error51);
18631
18631
  }
18632
18632
  });
18633
18633
  return pending;
18634
18634
  }
18635
- async function unmountWidget() {
18635
+ async function unmountView() {
18636
18636
  await pending;
18637
18637
  if (!mounted) return;
18638
18638
  mounted = false;
18639
- await widget2.unmount(container2);
18639
+ await view2.unmount(container2);
18640
18640
  }
18641
18641
  const handleToolInput = (params) => {
18642
18642
  toolInput = params;
@@ -18669,7 +18669,7 @@ container holding the app. Specify either width or maxWidth, and either height o
18669
18669
  stopped = true;
18670
18670
  detachTeardown();
18671
18671
  detachAppHandlers();
18672
- await unmountWidget();
18672
+ await unmountView();
18673
18673
  return await previousTeardown?.(params, extra) ?? {};
18674
18674
  };
18675
18675
  app.onteardown = bridgeTeardown;
@@ -18702,7 +18702,7 @@ container holding the app. Specify either width or maxWidth, and either height o
18702
18702
  stopped = true;
18703
18703
  detachTeardown();
18704
18704
  detachAppHandlers();
18705
- void unmountWidget();
18705
+ void unmountView();
18706
18706
  if (!options.app) void app.close().catch(() => void 0);
18707
18707
  }
18708
18708
  detachTeardown = options.onTeardown?.(stopBridge) ?? (typeof window !== "undefined" ? (() => {
@@ -18717,21 +18717,29 @@ container holding the app. Specify either width or maxWidth, and either height o
18717
18717
  };
18718
18718
  }
18719
18719
 
18720
+ // src/publish.ts
18721
+ var MCP_VIEW_GLOBAL_KEY = "__mountlyMcpView__";
18722
+ function getPublishedMcpView() {
18723
+ return globalThis[MCP_VIEW_GLOBAL_KEY];
18724
+ }
18725
+
18720
18726
  // src/bridge/iframe-entry.ts
18721
- var widget = globalThis.__mountlyMcpWidget__;
18727
+ var view = getPublishedMcpView();
18722
18728
  var awaitToolResult = globalThis.__mountlyMcpAwaitToolResult__ ?? true;
18723
18729
  var streamToolInput = globalThis.__mountlyMcpStreamToolInput__ ?? false;
18724
18730
  var availableDisplayModes = globalThis.__mountlyMcpAvailableDisplayModes__ ?? ["inline"];
18725
18731
  var appInfo = globalThis.__mountlyMcpAppInfo__;
18726
- if (!widget) {
18727
- throw new Error("[mountly-mcp] no widget on globalThis.__mountlyMcpWidget__");
18732
+ if (!view) {
18733
+ throw new Error(
18734
+ `[mountly-mcp] no View published \u2014 call createMcpView(...) (or publishMcpView) in your entry so ${MCP_VIEW_GLOBAL_KEY} is set`
18735
+ );
18728
18736
  }
18729
18737
  var container = document.getElementById("mountly-mcp-root");
18730
18738
  if (!container) {
18731
18739
  throw new Error("[mountly-mcp] #mountly-mcp-root not found in iframe DOM");
18732
18740
  }
18733
18741
  var bridge = runBridge({
18734
- widget,
18742
+ view,
18735
18743
  container,
18736
18744
  awaitToolResult,
18737
18745
  streamToolInput,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * View-side bridge that turns an MCP Apps `App` into a mountly `WidgetModule`
2
+ * View-side bridge that turns an MCP Apps `App` into a mountly view module
3
3
  * lifecycle. The full spec handshake — `ui/initialize`,
4
4
  * `ui/notifications/initialized`, `ui/notifications/tool-input(-partial)`,
5
5
  * `ui/notifications/tool-result`, `ui/notifications/tool-cancelled`,
@@ -7,15 +7,15 @@
7
7
  * `ui/notifications/size-changed` — is delegated to ext-apps's `App`.
8
8
  */
9
9
  import { App, PostMessageTransport, type McpUiDisplayMode } from "@modelcontextprotocol/ext-apps";
10
- import type { WidgetModule } from "mountly/adapter";
10
+ import type { McpView } from "../types.js";
11
11
  export interface RunBridgeOptions {
12
12
  /** Pre-constructed App (used by jsdom tests); otherwise one is created here. */
13
13
  app?: App;
14
- widget: WidgetModule;
14
+ view: McpView;
15
15
  container: Element;
16
16
  /**
17
17
  * If true (default), mount is deferred until the first tool-result arrives;
18
- * the widget renders against `{ toolInput, toolResult, hostContext, mcp }`
18
+ * the View renders against `{ toolInput, toolResult, hostContext, mcp }`
19
19
  * props on each notification.
20
20
  *
21
21
  * If false, mount fires immediately after `ui/initialize` with `{ mcp }`
@@ -27,7 +27,7 @@ export interface RunBridgeOptions {
27
27
  *
28
28
  * Off by default — the spec lets views ignore partials, and they carry
29
29
  * best-effort recovered JSON that MUST NOT drive critical operations. When
30
- * on, partials arrive as `toolInputPartial` (mounting the widget early if
30
+ * on, partials arrive as `toolInputPartial` (mounting the View early if
31
31
  * needed) and are cleared once the complete `tool-input` lands.
32
32
  */
33
33
  streamToolInput?: boolean;
@@ -2,8 +2,8 @@ import {
2
2
  App,
3
3
  PostMessageTransport,
4
4
  runBridge
5
- } from "../chunk-SNWNF2XI.js";
6
- import "../chunk-DQLQOMDM.js";
5
+ } from "../chunk-JVQZGKBL.js";
6
+ import "../chunk-M4WFJR3C.js";
7
7
  export {
8
8
  App,
9
9
  PostMessageTransport,
@@ -5,7 +5,7 @@ import type { McpAppArtifact } from "../artifact/index.js";
5
5
  * Absolute path to the iframe bridge runtime shipped with this package.
6
6
  *
7
7
  * `buildMcpResource` inlines this file's contents into the emitted HTML so
8
- * the widget can speak the MCP Apps postMessage protocol. Use this when you
8
+ * the View can speak the MCP Apps postMessage protocol. Use this when you
9
9
  * need to point another build tool at the runtime, or when you want a
10
10
  * stable, version-pinned alternative to passing `bridgeRuntimePath` yourself.
11
11
  *
@@ -50,9 +50,9 @@ export interface BuildResult {
50
50
  artifact: McpAppArtifact;
51
51
  }
52
52
  export interface BuildFromSourceOptions extends Omit<BuildSelfContainedOptions, "entry" | "cssEntry"> {
53
- /** The bundled widget JS. */
53
+ /** The bundled View JS. */
54
54
  js: string;
55
- /** The widget's CSS, if it has any. */
55
+ /** The View's CSS, if it has any. */
56
56
  css?: string;
57
57
  }
58
58
  /**
@@ -4,8 +4,8 @@ import {
4
4
  emitHtml,
5
5
  emitMeta,
6
6
  getBridgeRuntimePath
7
- } from "../chunk-4WAKOYMK.js";
8
- import "../chunk-DQLQOMDM.js";
7
+ } from "../chunk-MTJDRWGD.js";
8
+ import "../chunk-M4WFJR3C.js";
9
9
  import "../chunk-YJA4H6IB.js";
10
10
  export {
11
11
  buildMcpResource,
@@ -1,3 +1,7 @@
1
+ import {
2
+ publishMcpView
3
+ } from "./chunk-SADNMGP6.js";
4
+
1
5
  // src/react/context.ts
2
6
  import { createContext } from "react";
3
7
  var McpContext = createContext(null);
@@ -16,12 +20,12 @@ function useEnsuredContext() {
16
20
  const ctx = useContext(McpContext);
17
21
  if (!ctx) {
18
22
  throw new Error(
19
- "mountly-mcp/react: useMcpHost/useToolInput/etc must be used inside a widget wrapped with createMcpWidget()."
23
+ "mountly-mcp/react: useMcpApp/useToolInput/etc must be used inside a View wrapped with createMcpView()."
20
24
  );
21
25
  }
22
26
  return ctx;
23
27
  }
24
- function useMcpHost() {
28
+ function useMcpApp() {
25
29
  return useEnsuredContext().app;
26
30
  }
27
31
  function useToolInput() {
@@ -73,10 +77,10 @@ function useAutoResize(...args) {
73
77
  return useAutoResizeBase(...args);
74
78
  }
75
79
 
76
- // src/react/create-widget.ts
80
+ // src/react/create-view.ts
77
81
  import { createElement } from "react";
78
82
  import { createWidget } from "mountly-react";
79
- function createMcpWidget(Component, options) {
83
+ function createMcpView(Component, options) {
80
84
  const Wrapped = (props) => {
81
85
  const { mcp, toolInput, toolInputPartial, toolResult, hostContext, ...rest } = props;
82
86
  const value = {
@@ -92,12 +96,12 @@ function createMcpWidget(Component, options) {
92
96
  createElement(Component, rest)
93
97
  );
94
98
  };
95
- return createWidget(Wrapped, options);
99
+ return publishMcpView(createWidget(Wrapped, options));
96
100
  }
97
101
 
98
102
  export {
99
103
  McpContext,
100
- useMcpHost,
104
+ useMcpApp,
101
105
  useToolInput,
102
106
  useToolInputPartial,
103
107
  useToolResult,
@@ -110,6 +114,6 @@ export {
110
114
  useDocumentTheme,
111
115
  useUpdateModelContext,
112
116
  useAutoResize,
113
- createMcpWidget
117
+ createMcpView
114
118
  };
115
- //# sourceMappingURL=chunk-NLQDVNZP.js.map
119
+ //# sourceMappingURL=chunk-AEVQKFXX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react/context.ts","../src/react/hooks.ts","../src/react/create-view.ts"],"sourcesContent":["import { createContext } from \"react\";\nimport type {\n App,\n McpUiHostContext,\n McpUiToolInputNotification,\n McpUiToolInputPartialNotification,\n McpUiToolResultNotification,\n} from \"@modelcontextprotocol/ext-apps\";\n\n/**\n * Shared per-View context. The bridge populates this on each mount/update,\n * so consumers can synchronously read the initial values (no event subscription\n * race) and the React tree re-renders when the bridge calls `update()`.\n */\nexport interface McpContextValue {\n app: App;\n toolInput?: McpUiToolInputNotification[\"params\"];\n toolInputPartial?: McpUiToolInputPartialNotification[\"params\"];\n toolResult?: McpUiToolResultNotification[\"params\"];\n hostContext?: McpUiHostContext;\n}\n\nexport const McpContext = createContext<McpContextValue | null>(null);\nMcpContext.displayName = \"McpContext\";\n","import { useContext } from \"react\";\nimport {\n useAutoResize as useAutoResizeBase,\n useDocumentTheme as useDocumentThemeBase,\n useHostFonts as useHostFontsBase,\n useHostStyleVariables as useHostStyleVariablesBase,\n useHostStyles as useHostStylesBase,\n} from \"@modelcontextprotocol/ext-apps/react\";\nimport type {\n App,\n McpUiDisplayMode,\n McpUiHostContext,\n McpUiUpdateModelContextRequest,\n} from \"@modelcontextprotocol/ext-apps\";\nimport { McpContext } from \"./context.js\";\n\nfunction useEnsuredContext() {\n const ctx = useContext(McpContext);\n if (!ctx) {\n throw new Error(\n \"mountly-mcp/react: useMcpApp/useToolInput/etc must be used inside a View wrapped with createMcpView().\",\n );\n }\n return ctx;\n}\n\n/** The view-side ext-apps App. Use this to call server tools, send messages, open links, etc. */\nexport function useMcpApp(): App {\n return useEnsuredContext().app;\n}\n\n/** Complete notification params; read the tool arguments from `.arguments`. */\nexport function useToolInput<T = unknown>(): T | undefined {\n return useEnsuredContext().toolInput as T | undefined;\n}\n\n/**\n * Streaming tool arguments (`ui/notifications/tool-input-partial`), present only\n * when the bridge runs with `streamToolInput`. Best-effort recovered JSON —\n * fields may be missing or change between notifications, so render loading\n * states from it, never critical operations. Undefined once the complete\n * {@link useToolInput} arrives.\n */\nexport function useToolInputPartial<T = unknown>(): Partial<T> | undefined {\n return useEnsuredContext().toolInputPartial as Partial<T> | undefined;\n}\n\n/** Complete MCP tool result; structured data is available at `.structuredContent`. */\nexport function useToolResult<T = unknown>(): T | undefined {\n return useEnsuredContext().toolResult as T | undefined;\n}\n\n/** Latest host context snapshot (theme, styles, displayMode, container dimensions, etc.). */\nexport function useHostContext(): McpUiHostContext | undefined {\n return useEnsuredContext().hostContext;\n}\n\n/** Current display mode reported by the host. */\nexport function useDisplayMode(): McpUiDisplayMode | undefined {\n return useHostContext()?.displayMode;\n}\n\n/**\n * Request a display mode change, resolving to the mode the host actually\n * applied — which the spec allows to differ from the one asked for.\n *\n * Modes the host didn't list in `availableDisplayModes` are never requested\n * (the spec requires views to check first); the current mode comes back\n * unchanged instead.\n */\nexport function useRequestDisplayMode(): (\n mode: McpUiDisplayMode,\n) => Promise<McpUiDisplayMode | undefined> {\n const { app, hostContext } = useEnsuredContext();\n return async (mode) => {\n const available = hostContext?.availableDisplayModes;\n if (available && !available.includes(mode)) return hostContext?.displayMode;\n const result = await app.requestDisplayMode({ mode });\n return result.mode;\n };\n}\n\n/** Apply host CSS variables (and react to host-context changes). */\nexport function useHostStyleVariables(): void {\n const { app, hostContext } = useEnsuredContext();\n useHostStyleVariablesBase(app, hostContext ?? null);\n}\n\n/** Apply host-provided `@font-face`/`@import` rules. */\nexport function useHostFonts(): void {\n const { app, hostContext } = useEnsuredContext();\n useHostFontsBase(app, hostContext ?? null);\n}\n\n/** One-shot helper: apply both host style variables and host fonts. */\nexport function useHostStyles(): void {\n const { app, hostContext } = useEnsuredContext();\n useHostStylesBase(app, hostContext ?? null);\n}\n\n/** Track the document theme reactively. */\nexport function useDocumentTheme() {\n return useDocumentThemeBase();\n}\n\n/**\n * Return a function that calls `app.updateModelContext(params)`.\n *\n * Context updates are available to the model in future turns without\n * triggering an immediate response. Only the last update is kept.\n */\nexport function useUpdateModelContext(): (\n params: McpUiUpdateModelContextRequest[\"params\"],\n) => Promise<void> {\n const { app } = useEnsuredContext();\n return async (params) => {\n await app.updateModelContext(params);\n };\n}\n\n/** Manually control auto-resize (rarely needed — the bridge calls setupSizeChangedNotifications by default). */\nexport function useAutoResize(...args: Parameters<typeof useAutoResizeBase>) {\n return useAutoResizeBase(...args);\n}\n","/**\n * Wraps a React component as an MCP Apps View and publishes it for the bridge.\n * One call is enough — no manual global assign.\n */\nimport { createElement, type ComponentType } from \"react\";\nimport { createWidget } from \"mountly-react\";\nimport type { AdapterOptions } from \"mountly/adapter\";\nimport type { McpView, McpViewProps } from \"../types.js\";\nimport { publishMcpView } from \"../publish.js\";\nimport { McpContext, type McpContextValue } from \"./context.js\";\n\nexport function createMcpView<P extends object>(\n Component: ComponentType<P>,\n options?: AdapterOptions,\n): McpView {\n const Wrapped = (props: P & McpViewProps) => {\n const { mcp, toolInput, toolInputPartial, toolResult, hostContext, ...rest } =\n props as McpViewProps & P;\n const value: McpContextValue = {\n app: mcp,\n toolInput,\n toolInputPartial,\n toolResult,\n hostContext,\n };\n return createElement(\n McpContext.Provider,\n { value },\n createElement(Component as ComponentType, rest as P),\n );\n };\n return publishMcpView(createWidget(Wrapped as ComponentType<P & McpViewProps>, options));\n}\n"],"mappings":";;;;;AAAA,SAAS,qBAAqB;AAsBvB,IAAM,aAAa,cAAsC,IAAI;AACpE,WAAW,cAAc;;;ACvBzB,SAAS,kBAAkB;AAC3B;AAAA,EACE,iBAAiB;AAAA,EACjB,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,yBAAyB;AAAA,EACzB,iBAAiB;AAAA,OACZ;AASP,SAAS,oBAAoB;AAC3B,QAAM,MAAM,WAAW,UAAU;AACjC,MAAI,CAAC,KAAK;AACR,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,YAAiB;AAC/B,SAAO,kBAAkB,EAAE;AAC7B;AAGO,SAAS,eAA2C;AACzD,SAAO,kBAAkB,EAAE;AAC7B;AASO,SAAS,sBAA2D;AACzE,SAAO,kBAAkB,EAAE;AAC7B;AAGO,SAAS,gBAA4C;AAC1D,SAAO,kBAAkB,EAAE;AAC7B;AAGO,SAAS,iBAA+C;AAC7D,SAAO,kBAAkB,EAAE;AAC7B;AAGO,SAAS,iBAA+C;AAC7D,SAAO,eAAe,GAAG;AAC3B;AAUO,SAAS,wBAE2B;AACzC,QAAM,EAAE,KAAK,YAAY,IAAI,kBAAkB;AAC/C,SAAO,OAAO,SAAS;AACrB,UAAM,YAAY,aAAa;AAC/B,QAAI,aAAa,CAAC,UAAU,SAAS,IAAI,EAAG,QAAO,aAAa;AAChE,UAAM,SAAS,MAAM,IAAI,mBAAmB,EAAE,KAAK,CAAC;AACpD,WAAO,OAAO;AAAA,EAChB;AACF;AAGO,SAAS,wBAA8B;AAC5C,QAAM,EAAE,KAAK,YAAY,IAAI,kBAAkB;AAC/C,4BAA0B,KAAK,eAAe,IAAI;AACpD;AAGO,SAAS,eAAqB;AACnC,QAAM,EAAE,KAAK,YAAY,IAAI,kBAAkB;AAC/C,mBAAiB,KAAK,eAAe,IAAI;AAC3C;AAGO,SAAS,gBAAsB;AACpC,QAAM,EAAE,KAAK,YAAY,IAAI,kBAAkB;AAC/C,oBAAkB,KAAK,eAAe,IAAI;AAC5C;AAGO,SAAS,mBAAmB;AACjC,SAAO,qBAAqB;AAC9B;AAQO,SAAS,wBAEG;AACjB,QAAM,EAAE,IAAI,IAAI,kBAAkB;AAClC,SAAO,OAAO,WAAW;AACvB,UAAM,IAAI,mBAAmB,MAAM;AAAA,EACrC;AACF;AAGO,SAAS,iBAAiB,MAA4C;AAC3E,SAAO,kBAAkB,GAAG,IAAI;AAClC;;;ACvHA,SAAS,qBAAyC;AAClD,SAAS,oBAAoB;AAMtB,SAAS,cACd,WACA,SACS;AACT,QAAM,UAAU,CAAC,UAA4B;AAC3C,UAAM,EAAE,KAAK,WAAW,kBAAkB,YAAY,aAAa,GAAG,KAAK,IACzE;AACF,UAAM,QAAyB;AAAA,MAC7B,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,WAAO;AAAA,MACL,WAAW;AAAA,MACX,EAAE,MAAM;AAAA,MACR,cAAc,WAA4B,IAAS;AAAA,IACrD;AAAA,EACF;AACA,SAAO,eAAe,aAAa,SAA4C,OAAO,CAAC;AACzF;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  MCP_ERROR_CODES
3
- } from "./chunk-DQLQOMDM.js";
3
+ } from "./chunk-M4WFJR3C.js";
4
4
 
5
5
  // src/bridge/index.ts
6
6
  import {
@@ -19,7 +19,7 @@ function renderErrorBoundary(container, code, message) {
19
19
  }
20
20
  function runBridge(options) {
21
21
  const {
22
- widget,
22
+ view,
23
23
  container,
24
24
  awaitToolResult = true,
25
25
  streamToolInput = false,
@@ -58,31 +58,31 @@ function runBridge(options) {
58
58
  if (stopped) return;
59
59
  try {
60
60
  if (!mounted) {
61
- const r = widget.mount(container, props);
61
+ const r = view.mount(container, props);
62
62
  if (r instanceof Promise) await r;
63
63
  mounted = true;
64
64
  container.setAttribute("data-mountly-mcp-state", "mounted");
65
- } else if (widget.update) {
66
- const r = widget.update(container, props);
65
+ } else if (view.update) {
66
+ const r = view.update(container, props);
67
67
  if (r instanceof Promise) await r;
68
68
  } else {
69
- await widget.unmount(container);
69
+ await view.unmount(container);
70
70
  mounted = false;
71
- const r = widget.mount(container, props);
71
+ const r = view.mount(container, props);
72
72
  if (r instanceof Promise) await r;
73
73
  mounted = true;
74
74
  }
75
75
  } catch (error) {
76
- notifyError(MCP_ERROR_CODES.WIDGET_MOUNT_THREW, error);
76
+ notifyError(MCP_ERROR_CODES.VIEW_MOUNT_THREW, error);
77
77
  }
78
78
  });
79
79
  return pending;
80
80
  }
81
- async function unmountWidget() {
81
+ async function unmountView() {
82
82
  await pending;
83
83
  if (!mounted) return;
84
84
  mounted = false;
85
- await widget.unmount(container);
85
+ await view.unmount(container);
86
86
  }
87
87
  const handleToolInput = (params) => {
88
88
  toolInput = params;
@@ -115,7 +115,7 @@ function runBridge(options) {
115
115
  stopped = true;
116
116
  detachTeardown();
117
117
  detachAppHandlers();
118
- await unmountWidget();
118
+ await unmountView();
119
119
  return await previousTeardown?.(params, extra) ?? {};
120
120
  };
121
121
  app.onteardown = bridgeTeardown;
@@ -148,7 +148,7 @@ function runBridge(options) {
148
148
  stopped = true;
149
149
  detachTeardown();
150
150
  detachAppHandlers();
151
- void unmountWidget();
151
+ void unmountView();
152
152
  if (!options.app) void app.close().catch(() => void 0);
153
153
  }
154
154
  detachTeardown = options.onTeardown?.(stopBridge) ?? (typeof window !== "undefined" ? (() => {
@@ -168,4 +168,4 @@ export {
168
168
  PostMessageTransport,
169
169
  runBridge
170
170
  };
171
- //# sourceMappingURL=chunk-SNWNF2XI.js.map
171
+ //# sourceMappingURL=chunk-JVQZGKBL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/bridge/index.ts"],"sourcesContent":["/**\n * View-side bridge that turns an MCP Apps `App` into a mountly view module\n * lifecycle. The full spec handshake — `ui/initialize`,\n * `ui/notifications/initialized`, `ui/notifications/tool-input(-partial)`,\n * `ui/notifications/tool-result`, `ui/notifications/tool-cancelled`,\n * `ui/notifications/host-context-changed`, `ui/resource-teardown`,\n * `ui/notifications/size-changed` — is delegated to ext-apps's `App`.\n */\nimport {\n App,\n PostMessageTransport,\n type McpUiAppCapabilities,\n type McpUiDisplayMode,\n type McpUiToolInputNotification,\n type McpUiToolInputPartialNotification,\n type McpUiToolResultNotification,\n} from \"@modelcontextprotocol/ext-apps\";\n\nimport { MCP_ERROR_CODES } from \"../schema.js\";\nimport type { McpView, McpViewProps } from \"../types.js\";\n\nexport interface RunBridgeOptions {\n /** Pre-constructed App (used by jsdom tests); otherwise one is created here. */\n app?: App;\n view: McpView;\n container: Element;\n /**\n * If true (default), mount is deferred until the first tool-result arrives;\n * the View renders against `{ toolInput, toolResult, hostContext, mcp }`\n * props on each notification.\n *\n * If false, mount fires immediately after `ui/initialize` with `{ mcp }`\n * only — for \"stateless\" views that drive themselves via `mcp.callServerTool`.\n */\n awaitToolResult?: boolean;\n /**\n * Render progressive states from `ui/notifications/tool-input-partial`.\n *\n * Off by default — the spec lets views ignore partials, and they carry\n * best-effort recovered JSON that MUST NOT drive critical operations. When\n * on, partials arrive as `toolInputPartial` (mounting the View early if\n * needed) and are cleared once the complete `tool-input` lands.\n */\n streamToolInput?: boolean;\n /** Display modes this view supports. Declared to the host during `ui/initialize`. */\n availableDisplayModes?: ReadonlyArray<McpUiDisplayMode>;\n /** App identity sent during `ui/initialize`. */\n appInfo?: { name: string; version: string };\n /** Override for tests; defaults to `window.addEventListener('beforeunload', ...)`. */\n onTeardown?: (handler: () => void) => () => void;\n}\n\nexport interface RunningBridge {\n /** Resolves once `ui/initialize` handshake completes and the first mount (or deferred mount) is wired. */\n ready: Promise<void>;\n /** The underlying App; exposed for hosts that want to drive the view directly. */\n app: App;\n /** Synchronously triggers teardown. */\n stop(): void;\n}\n\n/**\n * `data-mountly-mcp-state` is the View's machine-readable outcome, read by\n * `verify --render`. It only ever moves forward — `mounted` once the View\n * has mounted, `error` if the boundary replaced it — so a state written here\n * can never be clobbered by a later lifecycle step.\n */\nfunction renderErrorBoundary(container: Element, code: string, message?: string): void {\n container.setAttribute(\"data-mountly-mcp-state\", \"error\");\n const doc = container.ownerDocument;\n if (!doc) return;\n const errorDiv = doc.createElement(\"div\");\n errorDiv.setAttribute(\"data-mountly-mcp-error\", code);\n if (message !== undefined) errorDiv.textContent = message;\n container.innerHTML = \"\";\n container.appendChild(errorDiv);\n}\n\nexport function runBridge(options: RunBridgeOptions): RunningBridge {\n const {\n view,\n container,\n awaitToolResult = true,\n streamToolInput = false,\n availableDisplayModes = [\"inline\"],\n appInfo = { name: \"mountly-mcp\", version: \"0.0.0\" },\n } = options;\n\n const appCapabilities: McpUiAppCapabilities = {\n availableDisplayModes: [...availableDisplayModes],\n };\n\n const app = options.app ?? new App(appInfo, appCapabilities);\n\n let toolInput: McpUiToolInputNotification[\"params\"] | undefined;\n let toolInputPartial: McpUiToolInputPartialNotification[\"params\"] | undefined;\n let toolResult: McpUiToolResultNotification[\"params\"] | undefined;\n let mounted = false;\n let stopped = false;\n let pending: Promise<void> = Promise.resolve();\n\n function currentProps(): McpViewProps {\n return {\n mcp: app,\n toolInput,\n toolInputPartial,\n toolResult,\n hostContext: app.getHostContext(),\n };\n }\n\n function notifyError(code: string, error: unknown): void {\n const message = error instanceof Error ? error.message : String(error);\n try {\n void app.sendLog({ level: \"error\", data: { code, message } }).catch(() => undefined);\n } catch {\n // ignore — log channel may not be ready\n }\n renderErrorBoundary(container, code, message);\n }\n\n function renderWith(props: McpViewProps): Promise<void> {\n pending = pending.then(async () => {\n if (stopped) return;\n try {\n if (!mounted) {\n const r = view.mount(container, props);\n if (r instanceof Promise) await r;\n mounted = true;\n container.setAttribute(\"data-mountly-mcp-state\", \"mounted\");\n } else if (view.update) {\n const r = view.update(container, props);\n if (r instanceof Promise) await r;\n } else {\n await view.unmount(container);\n mounted = false;\n const r = view.mount(container, props);\n if (r instanceof Promise) await r;\n mounted = true;\n }\n } catch (error) {\n notifyError(MCP_ERROR_CODES.VIEW_MOUNT_THREW, error);\n }\n });\n return pending;\n }\n\n async function unmountView(): Promise<void> {\n await pending;\n if (!mounted) return;\n mounted = false;\n await view.unmount(container);\n }\n\n // Event handlers MUST be registered before connect() — ext-apps will refuse\n // to attach handlers retroactively after the initialize handshake completes.\n const handleToolInput = (params: McpUiToolInputNotification[\"params\"]) => {\n toolInput = params;\n toolInputPartial = undefined;\n if (!awaitToolResult) return;\n if (mounted || toolResult !== undefined) void renderWith(currentProps());\n };\n\n const handleToolInputPartial = (params: McpUiToolInputPartialNotification[\"params\"]) => {\n // Views MAY ignore partial input per spec; opt in with `streamToolInput`.\n // Consumers wanting finer control can subscribe via app.addEventListener.\n if (!streamToolInput) return;\n toolInputPartial = params;\n void renderWith(currentProps());\n };\n\n const handleToolResult = (params: McpUiToolResultNotification[\"params\"]) => {\n toolResult = params;\n void renderWith(currentProps());\n };\n\n const handleToolCancelled = () => {\n void renderWith(currentProps());\n };\n\n const handleHostContextChanged = () => {\n if (mounted) void renderWith(currentProps());\n };\n\n app.addEventListener(\"toolinput\", handleToolInput);\n app.addEventListener(\"toolinputpartial\", handleToolInputPartial);\n app.addEventListener(\"toolresult\", handleToolResult);\n app.addEventListener(\"toolcancelled\", handleToolCancelled);\n app.addEventListener(\"hostcontextchanged\", handleHostContextChanged);\n\n const previousTeardown = app.onteardown;\n const bridgeTeardown: NonNullable<typeof app.onteardown> = async (params, extra) => {\n stopped = true;\n detachTeardown();\n detachAppHandlers();\n await unmountView();\n return (await previousTeardown?.(params, extra)) ?? {};\n };\n app.onteardown = bridgeTeardown;\n\n function detachAppHandlers(): void {\n app.removeEventListener(\"toolinput\", handleToolInput);\n app.removeEventListener(\"toolinputpartial\", handleToolInputPartial);\n app.removeEventListener(\"toolresult\", handleToolResult);\n app.removeEventListener(\"toolcancelled\", handleToolCancelled);\n app.removeEventListener(\"hostcontextchanged\", handleHostContextChanged);\n if (app.onteardown === bridgeTeardown) app.onteardown = previousTeardown;\n }\n\n const ready = (async () => {\n try {\n if (!options.app) {\n // App.connect() defaults to PostMessageTransport(window.parent, window.parent)\n // and owns automatic resize setup.\n await app.connect();\n }\n\n if (!awaitToolResult) {\n await renderWith(currentProps());\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const code = /timeout/i.test(message)\n ? MCP_ERROR_CODES.INITIALIZE_TIMEOUT\n : MCP_ERROR_CODES.INITIALIZE_FAILED;\n notifyError(code, error);\n throw error;\n }\n })();\n\n let detachTeardown: () => void = () => undefined;\n\n function stopBridge(): void {\n if (stopped) return;\n stopped = true;\n detachTeardown();\n detachAppHandlers();\n void unmountView();\n if (!options.app) void app.close().catch(() => undefined);\n }\n\n detachTeardown =\n options.onTeardown?.(stopBridge) ??\n (typeof window !== \"undefined\"\n ? (() => {\n const h = () => stopBridge();\n window.addEventListener(\"beforeunload\", h);\n return () => window.removeEventListener(\"beforeunload\", h);\n })()\n : () => undefined);\n\n return {\n ready,\n app,\n stop: stopBridge,\n };\n}\n\nexport { App, PostMessageTransport };\nexport type {\n McpUiAppCapabilities,\n McpUiHostCapabilities,\n McpUiHostContext,\n McpUiToolInputNotification,\n McpUiToolInputPartialNotification,\n McpUiToolResultNotification,\n McpUiToolCancelledNotification,\n McpUiHostContextChangedNotification,\n} from \"@modelcontextprotocol/ext-apps\";\n"],"mappings":"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","names":[]}