@noodleseed/assistant 1.22.0 → 1.24.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.
Files changed (48) hide show
  1. package/README.md +43 -8
  2. package/dist/app-view-element-DDtXu08a.d.ts +40 -0
  3. package/dist/app-view-element-DSPtyEul.d.cts +40 -0
  4. package/dist/app-view.cjs +18666 -0
  5. package/dist/app-view.cjs.map +1 -0
  6. package/dist/app-view.d.cts +9 -0
  7. package/dist/app-view.d.ts +9 -0
  8. package/dist/app-view.js +15 -0
  9. package/dist/app-view.js.map +1 -0
  10. package/dist/{appearance-Cc-eqSbp.d.cts → appearance-0nS2LFjb.d.cts} +1 -0
  11. package/dist/{appearance-Cc-eqSbp.d.ts → appearance-0nS2LFjb.d.ts} +1 -0
  12. package/dist/chunk-5NBHHNI3.js +180 -0
  13. package/dist/chunk-5NBHHNI3.js.map +1 -0
  14. package/dist/{chunk-6TT3R555.js → chunk-6PVDV7SO.js} +823 -4062
  15. package/dist/chunk-6PVDV7SO.js.map +1 -0
  16. package/dist/{chunk-ZPZHPXIQ.js → chunk-IBDP6PXQ.js} +9 -3882
  17. package/dist/chunk-IBDP6PXQ.js.map +1 -0
  18. package/dist/chunk-P223CYPO.js +3880 -0
  19. package/dist/chunk-P223CYPO.js.map +1 -0
  20. package/dist/chunk-XKTUXFGX.js +3323 -0
  21. package/dist/chunk-XKTUXFGX.js.map +1 -0
  22. package/dist/{client-BZ7xPwfW.d.cts → client-By4gqB1k.d.cts} +2 -2
  23. package/dist/{client-BkJlpN5N.d.ts → client-Cf38TgwN.d.ts} +2 -2
  24. package/dist/client.d.cts +2 -2
  25. package/dist/client.d.ts +2 -2
  26. package/dist/client.js +2 -1
  27. package/dist/embed.global.js +87 -73
  28. package/dist/index.cjs +110 -37
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.d.cts +3 -3
  31. package/dist/index.d.ts +3 -3
  32. package/dist/index.js +4 -2
  33. package/dist/index.js.map +1 -1
  34. package/dist/react/client.d.cts +2 -2
  35. package/dist/react/client.d.ts +2 -2
  36. package/dist/react/client.js +2 -1
  37. package/dist/react/client.js.map +1 -1
  38. package/dist/react.cjs +298 -69
  39. package/dist/react.cjs.map +1 -1
  40. package/dist/react.d.cts +8 -9
  41. package/dist/react.d.ts +8 -9
  42. package/dist/react.js +31 -41
  43. package/dist/react.js.map +1 -1
  44. package/dist/server.d.cts +1 -1
  45. package/dist/server.d.ts +1 -1
  46. package/package.json +16 -2
  47. package/dist/chunk-6TT3R555.js.map +0 -1
  48. package/dist/chunk-ZPZHPXIQ.js.map +0 -1
package/dist/react.d.cts CHANGED
@@ -1,26 +1,25 @@
1
1
  import { ReactElement, RefAttributes } from 'react';
2
- import { a as AssistantThemeMode } from './appearance-Cc-eqSbp.cjs';
2
+ import { a as AssistantThemeMode } from './appearance-0nS2LFjb.cjs';
3
3
  import { AssistantAppearance, AssistantAppearanceWarning, NoodleAssistantElement } from './index.cjs';
4
- import { c as AssistantClient, d as AssistantViewAvailableDetail, A as AssistantPageContext, a as AssistantContext, e as AssistantModelContextUpdate, f as AssistantClientEvent, g as AssistantErrorDetail } from './client-BZ7xPwfW.cjs';
4
+ import { A as AssistantClient, a as AssistantViewAvailableDetail, b as AssistantPageContext, c as AssistantContext, f as AssistantModelContextUpdate, g as AssistantClientEvent, e as AssistantErrorDetail } from './client-By4gqB1k.cjs';
5
+ import { a as AssistantAppViewErrorDetail } from './app-view-element-DSPtyEul.cjs';
5
6
  import 'ai';
6
7
 
7
8
  interface NoodleAppViewProps {
8
9
  readonly client: AssistantClient;
9
10
  readonly view: AssistantViewAvailableDetail;
10
11
  readonly theme?: 'light' | 'dark';
12
+ /** Permit App-requested fullscreen presentation. Defaults to inline-only. */
13
+ readonly allowFullscreen?: boolean;
11
14
  readonly className?: string;
12
- readonly onError?: (failure: {
13
- readonly code: 'view_render_timeout';
14
- readonly retryable: false;
15
- }) => void;
15
+ readonly onError?: (failure: AssistantAppViewErrorDetail) => void;
16
16
  }
17
17
  /**
18
18
  * Securely hosts one service-resolved MCP App inside a customer-owned React renderer.
19
19
  *
20
- * The bridge lifetime follows semantic view identity, so ordinary parent rerenders cannot reset an
21
- * in-progress App interaction.
20
+ * Compatibility adapter for the framework-neutral `<noodle-app-view>` host.
22
21
  */
23
- declare function NoodleAppView({ client, view, theme, className, onError, }: NoodleAppViewProps): ReactElement;
22
+ declare function NoodleAppView({ client, view, theme, allowFullscreen, className, onError, }: NoodleAppViewProps): ReactElement;
24
23
 
25
24
  interface NoodleAssistantProps<TPageContext extends AssistantPageContext = AssistantContext> {
26
25
  /** In-app mount: the customer backend route that exchanges an embed secret for a session. */
package/dist/react.d.ts CHANGED
@@ -1,26 +1,25 @@
1
1
  import { ReactElement, RefAttributes } from 'react';
2
- import { a as AssistantThemeMode } from './appearance-Cc-eqSbp.js';
2
+ import { a as AssistantThemeMode } from './appearance-0nS2LFjb.js';
3
3
  import { AssistantAppearance, AssistantAppearanceWarning, NoodleAssistantElement } from './index.js';
4
- import { c as AssistantClient, d as AssistantViewAvailableDetail, A as AssistantPageContext, a as AssistantContext, e as AssistantModelContextUpdate, f as AssistantClientEvent, g as AssistantErrorDetail } from './client-BkJlpN5N.js';
4
+ import { A as AssistantClient, a as AssistantViewAvailableDetail, b as AssistantPageContext, c as AssistantContext, f as AssistantModelContextUpdate, g as AssistantClientEvent, e as AssistantErrorDetail } from './client-Cf38TgwN.js';
5
+ import { a as AssistantAppViewErrorDetail } from './app-view-element-DDtXu08a.js';
5
6
  import 'ai';
6
7
 
7
8
  interface NoodleAppViewProps {
8
9
  readonly client: AssistantClient;
9
10
  readonly view: AssistantViewAvailableDetail;
10
11
  readonly theme?: 'light' | 'dark';
12
+ /** Permit App-requested fullscreen presentation. Defaults to inline-only. */
13
+ readonly allowFullscreen?: boolean;
11
14
  readonly className?: string;
12
- readonly onError?: (failure: {
13
- readonly code: 'view_render_timeout';
14
- readonly retryable: false;
15
- }) => void;
15
+ readonly onError?: (failure: AssistantAppViewErrorDetail) => void;
16
16
  }
17
17
  /**
18
18
  * Securely hosts one service-resolved MCP App inside a customer-owned React renderer.
19
19
  *
20
- * The bridge lifetime follows semantic view identity, so ordinary parent rerenders cannot reset an
21
- * in-progress App interaction.
20
+ * Compatibility adapter for the framework-neutral `<noodle-app-view>` host.
22
21
  */
23
- declare function NoodleAppView({ client, view, theme, className, onError, }: NoodleAppViewProps): ReactElement;
22
+ declare function NoodleAppView({ client, view, theme, allowFullscreen, className, onError, }: NoodleAppViewProps): ReactElement;
24
23
 
25
24
  interface NoodleAssistantProps<TPageContext extends AssistantPageContext = AssistantContext> {
26
25
  /** In-app mount: the customer backend route that exchanges an embed secret for a session. */
package/dist/react.js CHANGED
@@ -1,10 +1,13 @@
1
1
  import {
2
- mountAssistantApp,
3
- registerNoodleAssistant,
4
- unmountAssistantApp,
5
- updateAssistantAppTheme
6
- } from "./chunk-6TT3R555.js";
7
- import "./chunk-ZPZHPXIQ.js";
2
+ registerNoodleAssistant
3
+ } from "./chunk-6PVDV7SO.js";
4
+ import {
5
+ APP_VIEW_TAG_NAME,
6
+ registerNoodleAppView
7
+ } from "./chunk-5NBHHNI3.js";
8
+ import "./chunk-XKTUXFGX.js";
9
+ import "./chunk-IBDP6PXQ.js";
10
+ import "./chunk-P223CYPO.js";
8
11
  import "./chunk-3YYTUJPJ.js";
9
12
  import "./chunk-5FUTL2UF.js";
10
13
 
@@ -23,48 +26,35 @@ function NoodleAppView({
23
26
  client,
24
27
  view,
25
28
  theme = "light",
29
+ allowFullscreen = false,
26
30
  className,
27
31
  onError
28
32
  }) {
29
- const container = useRef(null);
30
- const mounted = useRef(null);
31
- const current = useRef({ view, theme, onError });
32
- const viewId = view.id;
33
- const resourceUri = view.resourceUri;
34
- useEffect(() => {
35
- current.current = { view, theme, onError };
36
- });
33
+ const elementRef = useRef(null);
34
+ const onErrorRef = useRef(onError);
35
+ onErrorRef.current = onError;
37
36
  useEffect(() => {
38
- const host = container.current;
39
- if (!host) return;
40
- const initialView = { ...current.current.view, id: viewId, resourceUri };
41
- const sandboxUrl = client.appSandboxUrl?.();
42
- const card = mountAssistantApp(
43
- initialView,
44
- {
45
- client,
46
- sendMessage: (message) => client.sendMessage(message),
47
- updateModelContext: (update) => client.updateModelContext(update),
48
- theme: current.current.theme
49
- },
50
- {
51
- ...sandboxUrl ? { sandboxUrl } : {},
52
- getDetail: () => current.current.view,
53
- onRenderFailure: (failure) => current.current.onError?.(failure)
54
- }
55
- );
56
- if (!card) return;
57
- mounted.current = card;
58
- host.replaceChildren(card);
37
+ const element = elementRef.current;
38
+ if (!element) return;
39
+ const handleError = (event) => {
40
+ onErrorRef.current?.(event.detail);
41
+ };
42
+ element.addEventListener("assistant-error", handleError);
43
+ registerNoodleAppView();
59
44
  return () => {
60
- if (mounted.current === card) mounted.current = null;
61
- void unmountAssistantApp(card);
45
+ element.removeEventListener("assistant-error", handleError);
62
46
  };
63
- }, [client, resourceUri, viewId]);
47
+ }, []);
64
48
  useEffect(() => {
65
- if (mounted.current) updateAssistantAppTheme(mounted.current, theme);
66
- }, [theme]);
67
- return createElement("div", { ref: container, className });
49
+ const element = elementRef.current;
50
+ if (!element) return;
51
+ if (element.client !== client) element.view = void 0;
52
+ element.allowFullscreen = allowFullscreen;
53
+ element.client = client;
54
+ element.theme = theme;
55
+ element.view = view;
56
+ }, [allowFullscreen, client, theme, view]);
57
+ return createElement(APP_VIEW_TAG_NAME, { ref: elementRef, class: className });
68
58
  }
69
59
 
70
60
  // src/react.ts
package/dist/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/react.ts","../src/react-app-view.ts"],"sourcesContent":["import {\n createElement,\n forwardRef,\n type ReactElement,\n type RefAttributes,\n useEffect,\n useImperativeHandle,\n useRef,\n} from 'react';\nimport type { AssistantThemeMode } from './appearance.js';\nimport type { AssistantAppearance, AssistantAppearanceWarning } from './host-appearance.js';\n\nexport type { AssistantAppearance, AssistantAppearanceWarning } from './host-appearance.js';\n\nimport type {\n AssistantClientEvent,\n AssistantContext,\n AssistantModelContextUpdate,\n AssistantPageContext,\n} from './client.js';\nimport { type NoodleAssistantElement, registerNoodleAssistant } from './element.js';\nimport type { AssistantErrorDetail } from './transport.js';\n\nexport { NoodleAppView, type NoodleAppViewProps } from './react-app-view.js';\n\nexport interface NoodleAssistantProps<\n TPageContext extends AssistantPageContext = AssistantContext,\n> {\n /** In-app mount: the customer backend route that exchanges an embed secret for a session. */\n readonly sessionEndpoint?: string;\n /** Public mount: the non-secret embed id `noodle deploy` printed. Exclusive with `sessionEndpoint`. */\n readonly embedId?: string;\n /** Only for a dev or self-hosted service; a published page needs no origin. */\n readonly serviceUrl?: string;\n readonly theme?: AssistantThemeMode;\n readonly appearance?: AssistantAppearance;\n readonly open?: boolean;\n readonly className?: string;\n readonly context?: AssistantContext;\n readonly pageContext?: TPageContext;\n readonly modelContext?: AssistantModelContextUpdate;\n readonly onEvent?: (event: AssistantClientEvent) => void;\n /**\n * Fires at most once per component instance, when the element's shadow DOM is rendered and its\n * imperative API (`sendMessage`, `confirmTool`, …) is callable — NOT when a session exists (listen\n * for the `session_started` client event via `onEvent` for that). It fires whether the element\n * upgraded before or after this component mounted, and the first callback identity wins: a later\n * re-render with a different `onReady` is never invoked.\n */\n readonly onReady?: () => void;\n readonly onError?: (error: AssistantErrorDetail) => void;\n readonly onAppearanceWarning?: (warning: AssistantAppearanceWarning) => void;\n readonly onSessionExpired?: () => void;\n}\n\nconst NoodleAssistantWithRef = forwardRef<NoodleAssistantElement, NoodleAssistantProps>(\n function NoodleAssistant(props, forwardedRef): ReactElement {\n const ref = useRef<NoodleAssistantElement>(null);\n const readyNotified = useRef(false);\n useImperativeHandle(forwardedRef, () => ref.current as NoodleAssistantElement, []);\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n const ready = () => {\n if (readyNotified.current) return;\n readyNotified.current = true;\n // The one observable breadcrumb for the readiness path: integrators could previously\n // neither convict nor exonerate this callback for a field failure.\n console.debug('[noodle-assistant] ready');\n props.onReady?.();\n };\n const error = (event: Event) =>\n props.onError?.((event as CustomEvent<AssistantErrorDetail>).detail);\n const expired = () => props.onSessionExpired?.();\n const assistantEvent = (event: Event) =>\n props.onEvent?.((event as CustomEvent<AssistantClientEvent>).detail);\n const appearanceWarning = (event: Event) =>\n props.onAppearanceWarning?.((event as CustomEvent<AssistantAppearanceWarning>).detail);\n element.addEventListener('assistant-ready', ready);\n element.addEventListener('assistant-error', error);\n element.addEventListener('assistant-session-expired', expired);\n element.addEventListener('assistant-event', assistantEvent);\n element.addEventListener('assistant-appearance-warning', appearanceWarning);\n registerNoodleAssistant();\n element.sessionEndpoint = props.sessionEndpoint ?? '';\n element.embedId = props.embedId ?? '';\n element.serviceUrl = props.serviceUrl ?? '';\n element.appearance = props.appearance;\n element.toggleAttribute('open', props.open === true);\n if (props.context) element.updateContext(props.context);\n if (props.pageContext) element.updatePageContext(props.pageContext);\n if (props.modelContext) element.updateModelContext(props.modelContext);\n // The canonical entry may have registered and upgraded the element before this effect ran.\n // Readiness is sticky once the shadow root exists, so late React listeners still fire once.\n if (element.shadowRoot) ready();\n return () => {\n element.removeEventListener('assistant-ready', ready);\n element.removeEventListener('assistant-error', error);\n element.removeEventListener('assistant-session-expired', expired);\n element.removeEventListener('assistant-event', assistantEvent);\n element.removeEventListener('assistant-appearance-warning', appearanceWarning);\n };\n }, [\n props.context,\n props.appearance,\n props.modelContext,\n props.onError,\n props.onAppearanceWarning,\n props.onEvent,\n props.onReady,\n props.onSessionExpired,\n props.open,\n props.pageContext,\n props.sessionEndpoint,\n props.embedId,\n props.serviceUrl,\n ]);\n return createElement('noodle-assistant', {\n ref,\n class: props.className,\n ...(props.sessionEndpoint ? { 'session-endpoint': props.sessionEndpoint } : {}),\n ...(props.embedId ? { 'embed-id': props.embedId } : {}),\n ...(props.serviceUrl ? { 'service-url': props.serviceUrl } : {}),\n ...(props.theme ? { theme: props.theme } : {}),\n });\n },\n);\n\nexport const NoodleAssistant = NoodleAssistantWithRef as <\n TPageContext extends AssistantPageContext = AssistantContext,\n>(\n props: NoodleAssistantProps<TPageContext> & RefAttributes<NoodleAssistantElement>,\n) => ReactElement;\n","import { createElement, type ReactElement, useEffect, useRef } from 'react';\nimport { mountAssistantApp, unmountAssistantApp, updateAssistantAppTheme } from './app-host.js';\nimport type { AssistantClient, AssistantViewAvailableDetail } from './client.js';\n\nexport interface NoodleAppViewProps {\n readonly client: AssistantClient;\n readonly view: AssistantViewAvailableDetail;\n readonly theme?: 'light' | 'dark';\n readonly className?: string;\n readonly onError?: (failure: {\n readonly code: 'view_render_timeout';\n readonly retryable: false;\n }) => void;\n}\n\n/**\n * Securely hosts one service-resolved MCP App inside a customer-owned React renderer.\n *\n * The bridge lifetime follows semantic view identity, so ordinary parent rerenders cannot reset an\n * in-progress App interaction.\n */\nexport function NoodleAppView({\n client,\n view,\n theme = 'light',\n className,\n onError,\n}: NoodleAppViewProps): ReactElement {\n const container = useRef<HTMLDivElement>(null);\n const mounted = useRef<HTMLElement>(null);\n const current = useRef({ view, theme, onError });\n const viewId = view.id;\n const resourceUri = view.resourceUri;\n\n useEffect(() => {\n current.current = { view, theme, onError };\n });\n\n useEffect(() => {\n const host = container.current;\n if (!host) return;\n const initialView = { ...current.current.view, id: viewId, resourceUri };\n const sandboxUrl = client.appSandboxUrl?.();\n const card = mountAssistantApp(\n initialView,\n {\n client,\n sendMessage: (message) => client.sendMessage(message),\n updateModelContext: (update) => client.updateModelContext(update),\n theme: current.current.theme,\n },\n {\n ...(sandboxUrl ? { sandboxUrl } : {}),\n getDetail: () => current.current.view,\n onRenderFailure: (failure) => current.current.onError?.(failure),\n },\n );\n if (!card) return;\n mounted.current = card;\n host.replaceChildren(card);\n return () => {\n if (mounted.current === card) mounted.current = null;\n void unmountAssistantApp(card);\n };\n }, [client, resourceUri, viewId]);\n\n useEffect(() => {\n if (mounted.current) updateAssistantAppTheme(mounted.current, theme);\n }, [theme]);\n\n return createElement('div', { ref: container, className });\n}\n"],"mappings":"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","names":["createElement","useEffect","useRef","useRef","useEffect","createElement","NoodleAssistant"]}
1
+ {"version":3,"sources":["../src/react.ts","../src/react-app-view.ts"],"sourcesContent":["import {\n createElement,\n forwardRef,\n type ReactElement,\n type RefAttributes,\n useEffect,\n useImperativeHandle,\n useRef,\n} from 'react';\nimport type { AssistantThemeMode } from './appearance.js';\nimport type { AssistantAppearance, AssistantAppearanceWarning } from './host-appearance.js';\n\nexport type { AssistantAppearance, AssistantAppearanceWarning } from './host-appearance.js';\n\nimport type {\n AssistantClientEvent,\n AssistantContext,\n AssistantModelContextUpdate,\n AssistantPageContext,\n} from './client.js';\nimport { type NoodleAssistantElement, registerNoodleAssistant } from './element.js';\nimport type { AssistantErrorDetail } from './transport.js';\n\nexport { NoodleAppView, type NoodleAppViewProps } from './react-app-view.js';\n\nexport interface NoodleAssistantProps<\n TPageContext extends AssistantPageContext = AssistantContext,\n> {\n /** In-app mount: the customer backend route that exchanges an embed secret for a session. */\n readonly sessionEndpoint?: string;\n /** Public mount: the non-secret embed id `noodle deploy` printed. Exclusive with `sessionEndpoint`. */\n readonly embedId?: string;\n /** Only for a dev or self-hosted service; a published page needs no origin. */\n readonly serviceUrl?: string;\n readonly theme?: AssistantThemeMode;\n readonly appearance?: AssistantAppearance;\n readonly open?: boolean;\n readonly className?: string;\n readonly context?: AssistantContext;\n readonly pageContext?: TPageContext;\n readonly modelContext?: AssistantModelContextUpdate;\n readonly onEvent?: (event: AssistantClientEvent) => void;\n /**\n * Fires at most once per component instance, when the element's shadow DOM is rendered and its\n * imperative API (`sendMessage`, `confirmTool`, …) is callable — NOT when a session exists (listen\n * for the `session_started` client event via `onEvent` for that). It fires whether the element\n * upgraded before or after this component mounted, and the first callback identity wins: a later\n * re-render with a different `onReady` is never invoked.\n */\n readonly onReady?: () => void;\n readonly onError?: (error: AssistantErrorDetail) => void;\n readonly onAppearanceWarning?: (warning: AssistantAppearanceWarning) => void;\n readonly onSessionExpired?: () => void;\n}\n\nconst NoodleAssistantWithRef = forwardRef<NoodleAssistantElement, NoodleAssistantProps>(\n function NoodleAssistant(props, forwardedRef): ReactElement {\n const ref = useRef<NoodleAssistantElement>(null);\n const readyNotified = useRef(false);\n useImperativeHandle(forwardedRef, () => ref.current as NoodleAssistantElement, []);\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n const ready = () => {\n if (readyNotified.current) return;\n readyNotified.current = true;\n // The one observable breadcrumb for the readiness path: integrators could previously\n // neither convict nor exonerate this callback for a field failure.\n console.debug('[noodle-assistant] ready');\n props.onReady?.();\n };\n const error = (event: Event) =>\n props.onError?.((event as CustomEvent<AssistantErrorDetail>).detail);\n const expired = () => props.onSessionExpired?.();\n const assistantEvent = (event: Event) =>\n props.onEvent?.((event as CustomEvent<AssistantClientEvent>).detail);\n const appearanceWarning = (event: Event) =>\n props.onAppearanceWarning?.((event as CustomEvent<AssistantAppearanceWarning>).detail);\n element.addEventListener('assistant-ready', ready);\n element.addEventListener('assistant-error', error);\n element.addEventListener('assistant-session-expired', expired);\n element.addEventListener('assistant-event', assistantEvent);\n element.addEventListener('assistant-appearance-warning', appearanceWarning);\n registerNoodleAssistant();\n element.sessionEndpoint = props.sessionEndpoint ?? '';\n element.embedId = props.embedId ?? '';\n element.serviceUrl = props.serviceUrl ?? '';\n element.appearance = props.appearance;\n element.toggleAttribute('open', props.open === true);\n if (props.context) element.updateContext(props.context);\n if (props.pageContext) element.updatePageContext(props.pageContext);\n if (props.modelContext) element.updateModelContext(props.modelContext);\n // The canonical entry may have registered and upgraded the element before this effect ran.\n // Readiness is sticky once the shadow root exists, so late React listeners still fire once.\n if (element.shadowRoot) ready();\n return () => {\n element.removeEventListener('assistant-ready', ready);\n element.removeEventListener('assistant-error', error);\n element.removeEventListener('assistant-session-expired', expired);\n element.removeEventListener('assistant-event', assistantEvent);\n element.removeEventListener('assistant-appearance-warning', appearanceWarning);\n };\n }, [\n props.context,\n props.appearance,\n props.modelContext,\n props.onError,\n props.onAppearanceWarning,\n props.onEvent,\n props.onReady,\n props.onSessionExpired,\n props.open,\n props.pageContext,\n props.sessionEndpoint,\n props.embedId,\n props.serviceUrl,\n ]);\n return createElement('noodle-assistant', {\n ref,\n class: props.className,\n ...(props.sessionEndpoint ? { 'session-endpoint': props.sessionEndpoint } : {}),\n ...(props.embedId ? { 'embed-id': props.embedId } : {}),\n ...(props.serviceUrl ? { 'service-url': props.serviceUrl } : {}),\n ...(props.theme ? { theme: props.theme } : {}),\n });\n },\n);\n\nexport const NoodleAssistant = NoodleAssistantWithRef as <\n TPageContext extends AssistantPageContext = AssistantContext,\n>(\n props: NoodleAssistantProps<TPageContext> & RefAttributes<NoodleAssistantElement>,\n) => ReactElement;\n","import { createElement, type ReactElement, useEffect, useRef } from 'react';\nimport {\n APP_VIEW_TAG_NAME,\n type AssistantAppViewErrorDetail,\n type NoodleAppViewElement,\n registerNoodleAppView,\n} from './app-view.js';\nimport type { AssistantClient, AssistantViewAvailableDetail } from './client.js';\n\nexport interface NoodleAppViewProps {\n readonly client: AssistantClient;\n readonly view: AssistantViewAvailableDetail;\n readonly theme?: 'light' | 'dark';\n /** Permit App-requested fullscreen presentation. Defaults to inline-only. */\n readonly allowFullscreen?: boolean;\n readonly className?: string;\n readonly onError?: (failure: AssistantAppViewErrorDetail) => void;\n}\n\n/**\n * Securely hosts one service-resolved MCP App inside a customer-owned React renderer.\n *\n * Compatibility adapter for the framework-neutral `<noodle-app-view>` host.\n */\nexport function NoodleAppView({\n client,\n view,\n theme = 'light',\n allowFullscreen = false,\n className,\n onError,\n}: NoodleAppViewProps): ReactElement {\n const elementRef = useRef<NoodleAppViewElement>(null);\n const onErrorRef = useRef(onError);\n onErrorRef.current = onError;\n\n useEffect(() => {\n const element = elementRef.current;\n if (!element) return;\n const handleError = (event: Event) => {\n onErrorRef.current?.((event as CustomEvent<AssistantAppViewErrorDetail>).detail);\n };\n element.addEventListener('assistant-error', handleError);\n registerNoodleAppView();\n return () => {\n element.removeEventListener('assistant-error', handleError);\n };\n }, []);\n\n useEffect(() => {\n const element = elementRef.current;\n if (!element) return;\n if (element.client !== client) element.view = undefined;\n element.allowFullscreen = allowFullscreen;\n element.client = client;\n element.theme = theme;\n element.view = view;\n }, [allowFullscreen, client, theme, view]);\n\n return createElement(APP_VIEW_TAG_NAME, { ref: elementRef, class: className });\n}\n"],"mappings":"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","names":["createElement","useEffect","useRef","useRef","useEffect","createElement","NoodleAssistant"]}
package/dist/server.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as AssistantConfiguration } from './appearance-Cc-eqSbp.cjs';
1
+ import { A as AssistantConfiguration } from './appearance-0nS2LFjb.cjs';
2
2
 
3
3
  interface AssistantSessionExchangeBase {
4
4
  readonly serviceUrl: string;
package/dist/server.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as AssistantConfiguration } from './appearance-Cc-eqSbp.js';
1
+ import { A as AssistantConfiguration } from './appearance-0nS2LFjb.js';
2
2
 
3
3
  interface AssistantSessionExchangeBase {
4
4
  readonly serviceUrl: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@noodleseed/assistant",
3
- "version": "1.22.0",
4
- "description": "Embed the Noodle Seed customer-branded assistant in your web app with a Web Component, managed or custom React UI, DOM-free client, and backend session helper. Authoring and deploying the server is @noodleseed/one.",
3
+ "version": "1.24.0",
4
+ "description": "Embed the Noodle Seed customer-branded assistant in your web app with managed or framework-owned UI, a framework-neutral MCP App host, a DOM-free client, and a backend session helper. Authoring and deploying the server is @noodleseed/one.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
@@ -26,6 +26,17 @@
26
26
  },
27
27
  "default": "./dist/index.js"
28
28
  },
29
+ "./app-view": {
30
+ "import": {
31
+ "types": "./dist/app-view.d.ts",
32
+ "default": "./dist/app-view.js"
33
+ },
34
+ "require": {
35
+ "types": "./dist/app-view.d.cts",
36
+ "default": "./dist/app-view.cjs"
37
+ },
38
+ "default": "./dist/app-view.js"
39
+ },
29
40
  "./client": {
30
41
  "import": {
31
42
  "types": "./dist/client.d.ts",
@@ -103,6 +114,9 @@
103
114
  "module": "./dist/index.js",
104
115
  "typesVersions": {
105
116
  "*": {
117
+ "app-view": [
118
+ "./dist/app-view.d.ts"
119
+ ],
106
120
  "react": [
107
121
  "./dist/react.d.ts"
108
122
  ],