@agent-native/dispatch 0.26.0 → 0.27.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.
@@ -47,9 +47,9 @@ declare const _default: import("node_modules/@agent-native/core/dist").ActionDef
47
47
  notes?: string | undefined;
48
48
  scope?: "org" | "user" | undefined;
49
49
  }, {
50
- deleted?: undefined;
51
50
  id?: undefined;
52
- provider?: undefined;
51
+ message?: undefined;
52
+ deleted?: undefined;
53
53
  providers: {
54
54
  id: string;
55
55
  label: string;
@@ -60,45 +60,45 @@ declare const _default: import("node_modules/@agent-native/core/dist").ActionDef
60
60
  updatedAt: number;
61
61
  }[];
62
62
  count: number;
63
+ provider?: undefined;
63
64
  found?: undefined;
64
65
  registered?: undefined;
65
66
  label?: undefined;
66
- message?: undefined;
67
67
  } | {
68
- deleted?: undefined;
69
68
  id?: undefined;
70
- providers?: undefined;
69
+ message?: undefined;
71
70
  count?: undefined;
71
+ deleted?: undefined;
72
+ providers?: undefined;
72
73
  found: boolean;
73
74
  provider: import("node_modules/@agent-native/core/dist/provider-api").CustomProviderConfig;
74
75
  registered?: undefined;
75
76
  label?: undefined;
76
- message?: undefined;
77
77
  } | {
78
+ message?: undefined;
79
+ count?: undefined;
78
80
  deleted?: undefined;
79
- provider?: undefined;
80
81
  providers?: undefined;
81
- count?: undefined;
82
+ provider?: undefined;
82
83
  found: boolean;
83
84
  id: string;
84
85
  registered?: undefined;
85
86
  label?: undefined;
86
- message?: undefined;
87
87
  } | {
88
- provider?: undefined;
89
- providers?: undefined;
88
+ message?: undefined;
90
89
  count?: undefined;
90
+ providers?: undefined;
91
+ provider?: undefined;
91
92
  found?: undefined;
92
93
  deleted: boolean;
93
94
  id: string;
94
95
  registered?: undefined;
95
96
  label?: undefined;
96
- message?: undefined;
97
97
  } | {
98
+ count?: undefined;
98
99
  deleted?: undefined;
99
- provider?: undefined;
100
100
  providers?: undefined;
101
- count?: undefined;
101
+ provider?: undefined;
102
102
  found?: undefined;
103
103
  registered: boolean;
104
104
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-app-host.d.ts","sourceRoot":"","sources":["../../src/components/workspace-app-host.tsx"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,sCAAsC,CAAC;AA6B9C,UAAU,iBAAiB;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,CAAC;CACnB;AAED,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,iBAAiB,CAEnB;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,UAAU,sBAAsB;IAC9B,GAAG,EAAE,oBAAoB,CAAC;IAC1B,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,aAAa,CAAC;CACtB;AAED,wBAAgB,iBAAiB,CAAC,EAChC,GAAG,EACH,SAAS,EACT,WAAmB,EACnB,IAA2B,GAC5B,EAAE,sBAAsB,mDAoJxB;AAED,wBAAgB,gBAAgB,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,mDAwH7D;AAID,wBAAgB,qBAAqB,CAAC,EACpC,WAAW,GACZ,EAAE;IACD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,mDAwCA"}
1
+ {"version":3,"file":"workspace-app-host.d.ts","sourceRoot":"","sources":["../../src/components/workspace-app-host.tsx"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,sCAAsC,CAAC;AAmC9C,UAAU,iBAAiB;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,CAAC;CACnB;AAoCD,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,iBAAiB,CAEnB;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,UAAU,sBAAsB;IAC9B,GAAG,EAAE,oBAAoB,CAAC;IAC1B,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,aAAa,CAAC;CACtB;AAED,wBAAgB,iBAAiB,CAAC,EAChC,GAAG,EACH,SAAS,EACT,WAAmB,EACnB,IAA2B,GAC5B,EAAE,sBAAsB,mDAuNxB;AAED,wBAAgB,gBAAgB,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,mDAwH7D;AAID,wBAAgB,qBAAqB,CAAC,EACpC,WAAW,GACZ,EAAE;IACD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,mDAwCA"}
@@ -5,8 +5,9 @@ import { useFeatureFlag } from "@agent-native/core/client/feature-flags";
5
5
  import { useActionMutation, useActionQuery, } from "@agent-native/core/client/hooks";
6
6
  import { useT } from "@agent-native/core/client/i18n";
7
7
  import { withBuilderUtmTrackingParams } from "@agent-native/core/shared/builder-link-tracking";
8
- import { IconArrowLeft, IconClockHour4 } from "@tabler/icons-react";
9
- import { useEffect, useMemo, useRef, useState } from "react";
8
+ import { IconArrowLeft, IconArrowUpRight, IconClockHour4, IconLock, } from "@tabler/icons-react";
9
+ import { useTheme } from "next-themes";
10
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
10
11
  import { Link } from "react-router";
11
12
  import { isEmbedSessionExpiredMessage } from "../lib/embed-session-recovery.js";
12
13
  import { workspaceAppDirectHref, workspaceAppEmbedTarget, workspaceAppHref, } from "../lib/workspace-apps.js";
@@ -15,14 +16,67 @@ import { ActionQueryError } from "./action-query-error.js";
15
16
  import { Badge } from "./ui/badge.js";
16
17
  import { Button } from "./ui/button.js";
17
18
  import { Skeleton } from "./ui/skeleton.js";
19
+ function resolveWorkspaceAppAuthState(rawUrl) {
20
+ if (!rawUrl)
21
+ return "unknown";
22
+ try {
23
+ const lastSegment = new URL(rawUrl, window.location.origin).pathname
24
+ .split("/")
25
+ .filter(Boolean)
26
+ .at(-1)
27
+ ?.toLowerCase();
28
+ if (lastSegment === "sign-in" ||
29
+ lastSegment === "login" ||
30
+ lastSegment === "signup") {
31
+ return "unauthenticated";
32
+ }
33
+ return "authenticated";
34
+ }
35
+ catch {
36
+ return "unknown";
37
+ }
38
+ }
39
+ function buildWorkspaceAppThemeUpdate(theme) {
40
+ return {
41
+ type: "agent-native-theme-update",
42
+ theme,
43
+ isDark: theme === "dark",
44
+ };
45
+ }
18
46
  export function buildChatFirstEmbedSessionInput(appId, path) {
19
47
  return { app: appId, path, chrome: "minimal" };
20
48
  }
21
49
  export function WorkspaceAppFrame({ app, embedPath, chatSidebar = false, copy = defaultChatFirstCopy, }) {
50
+ const { resolvedTheme } = useTheme();
51
+ const theme = resolvedTheme === "dark" || resolvedTheme === "light"
52
+ ? resolvedTheme
53
+ : typeof document !== "undefined" &&
54
+ document.documentElement.classList.contains("dark")
55
+ ? "dark"
56
+ : "light";
22
57
  const [embedUrl, setEmbedUrl] = useState(null);
23
58
  const [embedError, setEmbedError] = useState(null);
24
59
  const [embedAttempt, setEmbedAttempt] = useState(0);
60
+ const [authState, setAuthState] = useState("unknown");
25
61
  const embedFrameRef = useRef(null);
62
+ const postThemeToFrame = useCallback(() => {
63
+ embedFrameRef.current?.contentWindow?.postMessage(buildWorkspaceAppThemeUpdate(theme), "*");
64
+ }, [theme]);
65
+ const handleFrameLoad = useCallback(() => {
66
+ postThemeToFrame();
67
+ const frame = embedFrameRef.current;
68
+ let frameUrl = embedUrl;
69
+ try {
70
+ frameUrl = frame?.contentWindow?.location.href ?? frameUrl;
71
+ // coercion-ok: Cross-origin frames cannot expose location; their auth state arrives by message.
72
+ }
73
+ catch {
74
+ // Cross-origin app frames report their auth state through postMessage.
75
+ }
76
+ const nextAuthState = resolveWorkspaceAppAuthState(frameUrl);
77
+ if (nextAuthState !== "unknown")
78
+ setAuthState(nextAuthState);
79
+ }, [embedUrl, postThemeToFrame]);
26
80
  const workspaceSsoEnabled = useFeatureFlag(DISPATCH_WORKSPACE_SSO_FLAG.key);
27
81
  const createEmbedSession = useActionMutation("create_embed_session", {
28
82
  skipActionQueryInvalidation: true,
@@ -54,6 +108,7 @@ export function WorkspaceAppFrame({ app, embedPath, chatSidebar = false, copy =
54
108
  let cancelled = false;
55
109
  setEmbedUrl(null);
56
110
  setEmbedError(null);
111
+ setAuthState("unknown");
57
112
  const createSession = workspaceSsoEnabled
58
113
  ? createWorkspaceSsoEmbedSession
59
114
  : createEmbedSession;
@@ -93,13 +148,31 @@ export function WorkspaceAppFrame({ app, embedPath, chatSidebar = false, copy =
93
148
  window.addEventListener("message", handleEmbedSessionExpired);
94
149
  return () => window.removeEventListener("message", handleEmbedSessionExpired);
95
150
  }, [embedUrl]);
151
+ useEffect(() => {
152
+ const handleAuthState = (event) => {
153
+ const frame = embedFrameRef.current;
154
+ if (!frame || event.source !== frame.contentWindow)
155
+ return;
156
+ if (event.data?.type !== "agentNative.authState")
157
+ return;
158
+ const status = event.data.data?.status;
159
+ if (status === "authenticated" || status === "unauthenticated") {
160
+ setAuthState(status);
161
+ }
162
+ };
163
+ window.addEventListener("message", handleAuthState);
164
+ return () => window.removeEventListener("message", handleAuthState);
165
+ }, []);
166
+ useEffect(() => {
167
+ postThemeToFrame();
168
+ }, [embedUrl, postThemeToFrame]);
96
169
  const appPane = (_jsx(ChatFirstAppPane, { app: app, status: embedUrl
97
170
  ? "ready"
98
171
  : embedError
99
172
  ? "error"
100
173
  : embedInput
101
174
  ? "loading"
102
- : "unresolved", embedUrl: embedUrl, errorMessage: embedError?.message, onRetry: embedInput ? () => setEmbedAttempt((attempt) => attempt + 1) : undefined, renderEmbed: ({ url, title }) => (_jsx("iframe", { "data-dispatch-workspace-app-frame": true, src: url, title: title ?? app.name, ref: embedFrameRef, referrerPolicy: "no-referrer", allow: "clipboard-read; clipboard-write", className: "h-full w-full border-0 bg-background" }, url + ":" + embedAttempt)), copy: copy }));
175
+ : "unresolved", embedUrl: embedUrl, errorMessage: embedError?.message, onRetry: embedInput ? () => setEmbedAttempt((attempt) => attempt + 1) : undefined, renderEmbed: ({ url, title }) => (_jsx("iframe", { "data-dispatch-workspace-app-frame": true, src: url, title: title ?? app.name, ref: embedFrameRef, onLoad: handleFrameLoad, referrerPolicy: "no-referrer", allow: "clipboard-read; clipboard-write", className: "h-full w-full border-0 bg-background" }, url + ":" + embedAttempt)), copy: copy }));
103
176
  if (!chatSidebar)
104
177
  return appPane;
105
178
  return (_jsx(AgentSidebar, { position: "left", defaultOpen: true, openStorageKey: "dispatch-app-chat", storageKey: `dispatch-app-chat:${app.id}`, scope: {
@@ -107,7 +180,7 @@ export function WorkspaceAppFrame({ app, embedPath, chatSidebar = false, copy =
107
180
  id: app.id,
108
181
  label: app.name,
109
182
  contextKey: `workspace-app:${app.id}`,
110
- }, agentChatSurface: "app", showTabBar: true, suppressInlineOpenApp: true, dynamicSuggestions: false, suggestions: [], emptyStateText: `Ask about ${app.name}`, children: appPane }));
183
+ }, agentChatSurface: "app", showTabBar: true, suppressInlineOpenApp: true, dynamicSuggestions: false, suggestions: [], emptyStateText: `Ask about ${app.name}`, composerSlot: authState === "unauthenticated" ? (_jsx("div", { className: "flex shrink-0 items-center px-3 pb-1", children: _jsxs("button", { type: "button", "data-dispatch-app-sign-in": true, "aria-label": `Sign in to ${app.name} on the right`, title: `Sign in to ${app.name} on the right`, onClick: () => embedFrameRef.current?.focus(), className: "inline-flex h-6 shrink-0 items-center gap-1 rounded-full border border-border/70 bg-background/60 px-2 text-[11px] font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground", children: [_jsx(IconLock, { size: 12, stroke: 1.8 }), _jsx("span", { children: "Sign in on the right" }), _jsx(IconArrowUpRight, { size: 12, stroke: 1.8 })] }) })) : null, children: appPane }));
111
184
  }
112
185
  export function WorkspaceAppHost({ appId }) {
113
186
  const t = useT();
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-app-host.js","sourceRoot":"","sources":["../../src/components/workspace-app-host.tsx"],"names":[],"mappings":"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","sourcesContent":["import { AgentSidebar } from \"@agent-native/core/client/agent-chat\";\nimport {\n ChatFirstAppPane,\n defaultChatFirstCopy,\n type ChatFirstCopy,\n} from \"@agent-native/core/client/chat-first\";\nimport { useFeatureFlag } from \"@agent-native/core/client/feature-flags\";\nimport {\n useActionMutation,\n useActionQuery,\n} from \"@agent-native/core/client/hooks\";\nimport { useT } from \"@agent-native/core/client/i18n\";\nimport { withBuilderUtmTrackingParams } from \"@agent-native/core/shared/builder-link-tracking\";\nimport { IconArrowLeft, IconClockHour4 } from \"@tabler/icons-react\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { Link } from \"react-router\";\n\nimport { isEmbedSessionExpiredMessage } from \"../lib/embed-session-recovery\";\nimport {\n workspaceAppDirectHref,\n workspaceAppEmbedTarget,\n workspaceAppHref,\n type WorkspaceAppSummary,\n} from \"../lib/workspace-apps\";\nimport { DISPATCH_WORKSPACE_SSO_FLAG } from \"../shared/feature-flags\";\nimport { ActionQueryError } from \"./action-query-error\";\nimport { Badge } from \"./ui/badge\";\nimport { Button } from \"./ui/button\";\nimport { Skeleton } from \"./ui/skeleton\";\n\ninterface EmbedSessionResult {\n startUrl: string;\n}\n\ninterface EmbedSessionInput {\n app?: string;\n path?: string;\n url?: string;\n chrome: \"minimal\";\n}\n\nexport function buildChatFirstEmbedSessionInput(\n appId: string,\n path: string,\n): EmbedSessionInput {\n return { app: appId, path, chrome: \"minimal\" };\n}\n\nexport interface WorkspaceAppFrameApp {\n id: string;\n name: string;\n path?: string | null;\n url?: string | null;\n}\n\ninterface WorkspaceAppFrameProps {\n app: WorkspaceAppFrameApp;\n /** Chat-first app tabs use their own route while standalone hosts use app metadata. */\n embedPath?: string;\n /** Chat-first app surfaces own the parent chat rail around the iframe. */\n chatSidebar?: boolean;\n copy?: ChatFirstCopy;\n}\n\nexport function WorkspaceAppFrame({\n app,\n embedPath,\n chatSidebar = false,\n copy = defaultChatFirstCopy,\n}: WorkspaceAppFrameProps) {\n const [embedUrl, setEmbedUrl] = useState<string | null>(null);\n const [embedError, setEmbedError] = useState<Error | null>(null);\n const [embedAttempt, setEmbedAttempt] = useState(0);\n const embedFrameRef = useRef<HTMLIFrameElement>(null);\n const workspaceSsoEnabled = useFeatureFlag(DISPATCH_WORKSPACE_SSO_FLAG.key);\n const createEmbedSession = useActionMutation<\n EmbedSessionResult,\n EmbedSessionInput\n >(\"create_embed_session\", {\n skipActionQueryInvalidation: true,\n });\n const createWorkspaceSsoEmbedSession = useActionMutation<\n EmbedSessionResult,\n EmbedSessionInput\n >(\"create-workspace-app-embed-session\", {\n skipActionQueryInvalidation: true,\n });\n const appHref = workspaceAppHref({\n id: app.id,\n name: app.name,\n path: app.path ?? \"\",\n url: app.url,\n });\n const embedInput = useMemo<EmbedSessionInput | null>(() => {\n if (embedPath !== undefined) {\n return buildChatFirstEmbedSessionInput(app.id, embedPath);\n }\n if (!appHref) return null;\n return {\n app: app.id,\n ...workspaceAppEmbedTarget({ path: app.path ?? \"\", url: app.url }),\n chrome: \"minimal\",\n };\n }, [app.id, app.path, app.url, appHref, embedPath]);\n\n useEffect(() => {\n if (!embedInput) return;\n let cancelled = false;\n setEmbedUrl(null);\n setEmbedError(null);\n const createSession = workspaceSsoEnabled\n ? createWorkspaceSsoEmbedSession\n : createEmbedSession;\n void createSession\n .mutateAsync(embedInput)\n .then((result) => {\n if (!cancelled) setEmbedUrl(result.startUrl);\n })\n .catch((cause: unknown) => {\n if (cancelled) return;\n setEmbedUrl(\n workspaceAppDirectHref(\n { path: app.path ?? \"\", url: app.url },\n embedPath ?? \"/\",\n ),\n );\n setEmbedError(\n cause instanceof Error ? cause : new Error(String(cause)),\n );\n });\n return () => {\n cancelled = true;\n };\n }, [\n app.id,\n app.path,\n app.url,\n createEmbedSession.mutateAsync,\n createWorkspaceSsoEmbedSession.mutateAsync,\n embedInput,\n embedPath,\n embedAttempt,\n workspaceSsoEnabled,\n ]);\n\n useEffect(() => {\n const handleEmbedSessionExpired = (event: MessageEvent) => {\n if (\n !isEmbedSessionExpiredMessage(event, embedFrameRef.current, embedUrl)\n ) {\n return;\n }\n setEmbedAttempt((attempt) => attempt + 1);\n };\n\n window.addEventListener(\"message\", handleEmbedSessionExpired);\n return () =>\n window.removeEventListener(\"message\", handleEmbedSessionExpired);\n }, [embedUrl]);\n\n const appPane = (\n <ChatFirstAppPane\n app={app}\n status={\n embedUrl\n ? \"ready\"\n : embedError\n ? \"error\"\n : embedInput\n ? \"loading\"\n : \"unresolved\"\n }\n embedUrl={embedUrl}\n errorMessage={embedError?.message}\n onRetry={\n embedInput ? () => setEmbedAttempt((attempt) => attempt + 1) : undefined\n }\n renderEmbed={({ url, title }) => (\n <iframe\n key={url + \":\" + embedAttempt}\n data-dispatch-workspace-app-frame\n src={url}\n title={title ?? app.name}\n ref={embedFrameRef}\n referrerPolicy=\"no-referrer\"\n allow=\"clipboard-read; clipboard-write\"\n className=\"h-full w-full border-0 bg-background\"\n />\n )}\n copy={copy}\n />\n );\n\n if (!chatSidebar) return appPane;\n\n return (\n <AgentSidebar\n position=\"left\"\n defaultOpen\n openStorageKey=\"dispatch-app-chat\"\n storageKey={`dispatch-app-chat:${app.id}`}\n scope={{\n type: \"workspace-app\",\n id: app.id,\n label: app.name,\n contextKey: `workspace-app:${app.id}`,\n }}\n agentChatSurface=\"app\"\n showTabBar\n suppressInlineOpenApp\n dynamicSuggestions={false}\n suggestions={[]}\n emptyStateText={`Ask about ${app.name}`}\n >\n {appPane}\n </AgentSidebar>\n );\n}\n\nexport function WorkspaceAppHost({ appId }: { appId?: string }) {\n const t = useT();\n const appsQuery = useActionQuery(\"list-workspace-apps\", {\n includeAgentCards: false,\n });\n const { data: apps = [], isLoading } = appsQuery;\n const app = useMemo(\n () =>\n (apps as WorkspaceAppSummary[]).find((item) => item.id === appId) ?? null,\n [appId, apps],\n );\n\n if (appsQuery.isError) {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl\">\n <ActionQueryError\n error={appsQuery.error}\n onRetry={() => void appsQuery.refetch()}\n />\n </div>\n </div>\n );\n }\n\n if (isLoading && !app) {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl space-y-3 rounded-xl border bg-card p-6\">\n <Skeleton className=\"h-5 w-48\" />\n <Skeleton className=\"h-4 w-full\" />\n <Skeleton className=\"h-4 w-2/3\" />\n </div>\n </div>\n );\n }\n\n if (!app) {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl rounded-xl border bg-card p-6\">\n <Button asChild size=\"sm\" variant=\"ghost\" className=\"-ml-2 mb-4\">\n <Link to=\"/apps\">\n <IconArrowLeft size={15} className=\"mr-1.5\" />\n {t(\"dispatch.nav.apps\")}\n </Link>\n </Button>\n <div className=\"space-y-3\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {t(\"dispatch.pages.appNotFound\")}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"dispatch.pages.pageNotFoundDescription\")}\n </p>\n </div>\n </div>\n </div>\n );\n }\n\n if (app.status === \"pending\") {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl rounded-xl border bg-card p-6\">\n <Button asChild size=\"sm\" variant=\"ghost\" className=\"-ml-2 mb-4\">\n <Link to=\"/apps\">\n <IconArrowLeft size={15} className=\"mr-1.5\" />\n {t(\"dispatch.nav.apps\")}\n </Link>\n </Button>\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {app.name}\n </h2>\n <Badge\n variant=\"outline\"\n className=\"gap-1 border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-300\"\n >\n <IconClockHour4 size={12} />\n {t(\"dispatch.pages.building\")}\n </Badge>\n </div>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"dispatch.pages.appBuildingPrefix\")}{\" \"}\n <span className=\"font-mono text-foreground\">{app.path}</span>{\" \"}\n {t(\"dispatch.pages.appBuildingSuffix\")}\n </p>\n {app.builderUrl ? (\n <Button asChild>\n <a\n href={withBuilderUtmTrackingParams(app.builderUrl, {\n campaign: \"product\",\n content: \"dispatch_branch\",\n })}\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n {t(\"dispatch.pages.openBuilderBranch\", {\n defaultValue: \"Open in Builder\",\n })}\n </a>\n </Button>\n ) : null}\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div\n data-dispatch-workspace-app-host\n className=\"flex h-full min-h-0 flex-col bg-background\"\n >\n <div className=\"min-h-0 flex-1 bg-muted/20\">\n <WorkspaceAppFrame app={app} />\n </div>\n </div>\n );\n}\n\nconst MAX_KEEP_ALIVE_APPS = 3;\n\nexport function WorkspaceAppKeepAlive({\n activeAppId,\n}: {\n activeAppId: string | null;\n}) {\n const [visitedAppIds, setVisitedAppIds] = useState<string[]>(() =>\n activeAppId ? [activeAppId] : [],\n );\n\n useEffect(() => {\n if (!activeAppId) return;\n setVisitedAppIds((current) =>\n [activeAppId, ...current.filter((appId) => appId !== activeAppId)].slice(\n 0,\n MAX_KEEP_ALIVE_APPS,\n ),\n );\n }, [activeAppId]);\n\n const renderedAppIds =\n activeAppId && !visitedAppIds.includes(activeAppId)\n ? [activeAppId, ...visitedAppIds]\n : visitedAppIds;\n\n return (\n <div\n data-dispatch-workspace-app-cache\n className={activeAppId ? \"absolute inset-0 overflow-hidden\" : \"hidden\"}\n >\n {renderedAppIds.map((appId) => {\n const active = appId === activeAppId;\n return (\n <div\n key={appId}\n data-dispatch-workspace-app-cache-entry={appId}\n aria-hidden={!active}\n className={active ? \"h-full min-h-0\" : \"hidden\"}\n >\n <WorkspaceAppHost appId={appId} />\n </div>\n );\n })}\n </div>\n );\n}\n"]}
1
+ {"version":3,"file":"workspace-app-host.js","sourceRoot":"","sources":["../../src/components/workspace-app-host.tsx"],"names":[],"mappings":"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","sourcesContent":["import { AgentSidebar } from \"@agent-native/core/client/agent-chat\";\nimport {\n ChatFirstAppPane,\n defaultChatFirstCopy,\n type ChatFirstCopy,\n} from \"@agent-native/core/client/chat-first\";\nimport { useFeatureFlag } from \"@agent-native/core/client/feature-flags\";\nimport {\n useActionMutation,\n useActionQuery,\n} from \"@agent-native/core/client/hooks\";\nimport { useT } from \"@agent-native/core/client/i18n\";\nimport { withBuilderUtmTrackingParams } from \"@agent-native/core/shared/builder-link-tracking\";\nimport {\n IconArrowLeft,\n IconArrowUpRight,\n IconClockHour4,\n IconLock,\n} from \"@tabler/icons-react\";\nimport { useTheme } from \"next-themes\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { Link } from \"react-router\";\n\nimport { isEmbedSessionExpiredMessage } from \"../lib/embed-session-recovery\";\nimport {\n workspaceAppDirectHref,\n workspaceAppEmbedTarget,\n workspaceAppHref,\n type WorkspaceAppSummary,\n} from \"../lib/workspace-apps\";\nimport { DISPATCH_WORKSPACE_SSO_FLAG } from \"../shared/feature-flags\";\nimport { ActionQueryError } from \"./action-query-error\";\nimport { Badge } from \"./ui/badge\";\nimport { Button } from \"./ui/button\";\nimport { Skeleton } from \"./ui/skeleton\";\n\ninterface EmbedSessionResult {\n startUrl: string;\n}\n\ninterface EmbedSessionInput {\n app?: string;\n path?: string;\n url?: string;\n chrome: \"minimal\";\n}\n\ntype WorkspaceAppTheme = \"light\" | \"dark\";\ntype WorkspaceAppAuthState = \"unknown\" | \"authenticated\" | \"unauthenticated\";\n\nfunction resolveWorkspaceAppAuthState(\n rawUrl: string | null,\n): WorkspaceAppAuthState {\n if (!rawUrl) return \"unknown\";\n try {\n const lastSegment = new URL(rawUrl, window.location.origin).pathname\n .split(\"/\")\n .filter(Boolean)\n .at(-1)\n ?.toLowerCase();\n if (\n lastSegment === \"sign-in\" ||\n lastSegment === \"login\" ||\n lastSegment === \"signup\"\n ) {\n return \"unauthenticated\";\n }\n return \"authenticated\";\n } catch {\n return \"unknown\";\n }\n}\n\nfunction buildWorkspaceAppThemeUpdate(theme: WorkspaceAppTheme) {\n return {\n type: \"agent-native-theme-update\" as const,\n theme,\n isDark: theme === \"dark\",\n };\n}\n\nexport function buildChatFirstEmbedSessionInput(\n appId: string,\n path: string,\n): EmbedSessionInput {\n return { app: appId, path, chrome: \"minimal\" };\n}\n\nexport interface WorkspaceAppFrameApp {\n id: string;\n name: string;\n path?: string | null;\n url?: string | null;\n}\n\ninterface WorkspaceAppFrameProps {\n app: WorkspaceAppFrameApp;\n /** Chat-first app tabs use their own route while standalone hosts use app metadata. */\n embedPath?: string;\n /** Chat-first app surfaces own the parent chat rail around the iframe. */\n chatSidebar?: boolean;\n copy?: ChatFirstCopy;\n}\n\nexport function WorkspaceAppFrame({\n app,\n embedPath,\n chatSidebar = false,\n copy = defaultChatFirstCopy,\n}: WorkspaceAppFrameProps) {\n const { resolvedTheme } = useTheme();\n const theme: WorkspaceAppTheme =\n resolvedTheme === \"dark\" || resolvedTheme === \"light\"\n ? resolvedTheme\n : typeof document !== \"undefined\" &&\n document.documentElement.classList.contains(\"dark\")\n ? \"dark\"\n : \"light\";\n const [embedUrl, setEmbedUrl] = useState<string | null>(null);\n const [embedError, setEmbedError] = useState<Error | null>(null);\n const [embedAttempt, setEmbedAttempt] = useState(0);\n const [authState, setAuthState] = useState<WorkspaceAppAuthState>(\"unknown\");\n const embedFrameRef = useRef<HTMLIFrameElement>(null);\n const postThemeToFrame = useCallback(() => {\n embedFrameRef.current?.contentWindow?.postMessage(\n buildWorkspaceAppThemeUpdate(theme),\n \"*\",\n );\n }, [theme]);\n const handleFrameLoad = useCallback(() => {\n postThemeToFrame();\n const frame = embedFrameRef.current;\n let frameUrl = embedUrl;\n try {\n frameUrl = frame?.contentWindow?.location.href ?? frameUrl;\n // coercion-ok: Cross-origin frames cannot expose location; their auth state arrives by message.\n } catch {\n // Cross-origin app frames report their auth state through postMessage.\n }\n const nextAuthState = resolveWorkspaceAppAuthState(frameUrl);\n if (nextAuthState !== \"unknown\") setAuthState(nextAuthState);\n }, [embedUrl, postThemeToFrame]);\n const workspaceSsoEnabled = useFeatureFlag(DISPATCH_WORKSPACE_SSO_FLAG.key);\n const createEmbedSession = useActionMutation<\n EmbedSessionResult,\n EmbedSessionInput\n >(\"create_embed_session\", {\n skipActionQueryInvalidation: true,\n });\n const createWorkspaceSsoEmbedSession = useActionMutation<\n EmbedSessionResult,\n EmbedSessionInput\n >(\"create-workspace-app-embed-session\", {\n skipActionQueryInvalidation: true,\n });\n const appHref = workspaceAppHref({\n id: app.id,\n name: app.name,\n path: app.path ?? \"\",\n url: app.url,\n });\n const embedInput = useMemo<EmbedSessionInput | null>(() => {\n if (embedPath !== undefined) {\n return buildChatFirstEmbedSessionInput(app.id, embedPath);\n }\n if (!appHref) return null;\n return {\n app: app.id,\n ...workspaceAppEmbedTarget({ path: app.path ?? \"\", url: app.url }),\n chrome: \"minimal\",\n };\n }, [app.id, app.path, app.url, appHref, embedPath]);\n\n useEffect(() => {\n if (!embedInput) return;\n let cancelled = false;\n setEmbedUrl(null);\n setEmbedError(null);\n setAuthState(\"unknown\");\n const createSession = workspaceSsoEnabled\n ? createWorkspaceSsoEmbedSession\n : createEmbedSession;\n void createSession\n .mutateAsync(embedInput)\n .then((result) => {\n if (!cancelled) setEmbedUrl(result.startUrl);\n })\n .catch((cause: unknown) => {\n if (cancelled) return;\n setEmbedUrl(\n workspaceAppDirectHref(\n { path: app.path ?? \"\", url: app.url },\n embedPath ?? \"/\",\n ),\n );\n setEmbedError(\n cause instanceof Error ? cause : new Error(String(cause)),\n );\n });\n return () => {\n cancelled = true;\n };\n }, [\n app.id,\n app.path,\n app.url,\n createEmbedSession.mutateAsync,\n createWorkspaceSsoEmbedSession.mutateAsync,\n embedInput,\n embedPath,\n embedAttempt,\n workspaceSsoEnabled,\n ]);\n\n useEffect(() => {\n const handleEmbedSessionExpired = (event: MessageEvent) => {\n if (\n !isEmbedSessionExpiredMessage(event, embedFrameRef.current, embedUrl)\n ) {\n return;\n }\n setEmbedAttempt((attempt) => attempt + 1);\n };\n\n window.addEventListener(\"message\", handleEmbedSessionExpired);\n return () =>\n window.removeEventListener(\"message\", handleEmbedSessionExpired);\n }, [embedUrl]);\n\n useEffect(() => {\n const handleAuthState = (event: MessageEvent) => {\n const frame = embedFrameRef.current;\n if (!frame || event.source !== frame.contentWindow) return;\n if (event.data?.type !== \"agentNative.authState\") return;\n const status = event.data.data?.status;\n if (status === \"authenticated\" || status === \"unauthenticated\") {\n setAuthState(status);\n }\n };\n\n window.addEventListener(\"message\", handleAuthState);\n return () => window.removeEventListener(\"message\", handleAuthState);\n }, []);\n\n useEffect(() => {\n postThemeToFrame();\n }, [embedUrl, postThemeToFrame]);\n\n const appPane = (\n <ChatFirstAppPane\n app={app}\n status={\n embedUrl\n ? \"ready\"\n : embedError\n ? \"error\"\n : embedInput\n ? \"loading\"\n : \"unresolved\"\n }\n embedUrl={embedUrl}\n errorMessage={embedError?.message}\n onRetry={\n embedInput ? () => setEmbedAttempt((attempt) => attempt + 1) : undefined\n }\n renderEmbed={({ url, title }) => (\n <iframe\n key={url + \":\" + embedAttempt}\n data-dispatch-workspace-app-frame\n src={url}\n title={title ?? app.name}\n ref={embedFrameRef}\n onLoad={handleFrameLoad}\n referrerPolicy=\"no-referrer\"\n allow=\"clipboard-read; clipboard-write\"\n className=\"h-full w-full border-0 bg-background\"\n />\n )}\n copy={copy}\n />\n );\n\n if (!chatSidebar) return appPane;\n\n return (\n <AgentSidebar\n position=\"left\"\n defaultOpen\n openStorageKey=\"dispatch-app-chat\"\n storageKey={`dispatch-app-chat:${app.id}`}\n scope={{\n type: \"workspace-app\",\n id: app.id,\n label: app.name,\n contextKey: `workspace-app:${app.id}`,\n }}\n agentChatSurface=\"app\"\n showTabBar\n suppressInlineOpenApp\n dynamicSuggestions={false}\n suggestions={[]}\n emptyStateText={`Ask about ${app.name}`}\n composerSlot={\n authState === \"unauthenticated\" ? (\n <div className=\"flex shrink-0 items-center px-3 pb-1\">\n <button\n type=\"button\"\n data-dispatch-app-sign-in\n aria-label={`Sign in to ${app.name} on the right`}\n title={`Sign in to ${app.name} on the right`}\n onClick={() => embedFrameRef.current?.focus()}\n className=\"inline-flex h-6 shrink-0 items-center gap-1 rounded-full border border-border/70 bg-background/60 px-2 text-[11px] font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground\"\n >\n <IconLock size={12} stroke={1.8} />\n <span>Sign in on the right</span>\n <IconArrowUpRight size={12} stroke={1.8} />\n </button>\n </div>\n ) : null\n }\n >\n {appPane}\n </AgentSidebar>\n );\n}\n\nexport function WorkspaceAppHost({ appId }: { appId?: string }) {\n const t = useT();\n const appsQuery = useActionQuery(\"list-workspace-apps\", {\n includeAgentCards: false,\n });\n const { data: apps = [], isLoading } = appsQuery;\n const app = useMemo(\n () =>\n (apps as WorkspaceAppSummary[]).find((item) => item.id === appId) ?? null,\n [appId, apps],\n );\n\n if (appsQuery.isError) {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl\">\n <ActionQueryError\n error={appsQuery.error}\n onRetry={() => void appsQuery.refetch()}\n />\n </div>\n </div>\n );\n }\n\n if (isLoading && !app) {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl space-y-3 rounded-xl border bg-card p-6\">\n <Skeleton className=\"h-5 w-48\" />\n <Skeleton className=\"h-4 w-full\" />\n <Skeleton className=\"h-4 w-2/3\" />\n </div>\n </div>\n );\n }\n\n if (!app) {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl rounded-xl border bg-card p-6\">\n <Button asChild size=\"sm\" variant=\"ghost\" className=\"-ml-2 mb-4\">\n <Link to=\"/apps\">\n <IconArrowLeft size={15} className=\"mr-1.5\" />\n {t(\"dispatch.nav.apps\")}\n </Link>\n </Button>\n <div className=\"space-y-3\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {t(\"dispatch.pages.appNotFound\")}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"dispatch.pages.pageNotFoundDescription\")}\n </p>\n </div>\n </div>\n </div>\n );\n }\n\n if (app.status === \"pending\") {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl rounded-xl border bg-card p-6\">\n <Button asChild size=\"sm\" variant=\"ghost\" className=\"-ml-2 mb-4\">\n <Link to=\"/apps\">\n <IconArrowLeft size={15} className=\"mr-1.5\" />\n {t(\"dispatch.nav.apps\")}\n </Link>\n </Button>\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {app.name}\n </h2>\n <Badge\n variant=\"outline\"\n className=\"gap-1 border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-300\"\n >\n <IconClockHour4 size={12} />\n {t(\"dispatch.pages.building\")}\n </Badge>\n </div>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"dispatch.pages.appBuildingPrefix\")}{\" \"}\n <span className=\"font-mono text-foreground\">{app.path}</span>{\" \"}\n {t(\"dispatch.pages.appBuildingSuffix\")}\n </p>\n {app.builderUrl ? (\n <Button asChild>\n <a\n href={withBuilderUtmTrackingParams(app.builderUrl, {\n campaign: \"product\",\n content: \"dispatch_branch\",\n })}\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n {t(\"dispatch.pages.openBuilderBranch\", {\n defaultValue: \"Open in Builder\",\n })}\n </a>\n </Button>\n ) : null}\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div\n data-dispatch-workspace-app-host\n className=\"flex h-full min-h-0 flex-col bg-background\"\n >\n <div className=\"min-h-0 flex-1 bg-muted/20\">\n <WorkspaceAppFrame app={app} />\n </div>\n </div>\n );\n}\n\nconst MAX_KEEP_ALIVE_APPS = 3;\n\nexport function WorkspaceAppKeepAlive({\n activeAppId,\n}: {\n activeAppId: string | null;\n}) {\n const [visitedAppIds, setVisitedAppIds] = useState<string[]>(() =>\n activeAppId ? [activeAppId] : [],\n );\n\n useEffect(() => {\n if (!activeAppId) return;\n setVisitedAppIds((current) =>\n [activeAppId, ...current.filter((appId) => appId !== activeAppId)].slice(\n 0,\n MAX_KEEP_ALIVE_APPS,\n ),\n );\n }, [activeAppId]);\n\n const renderedAppIds =\n activeAppId && !visitedAppIds.includes(activeAppId)\n ? [activeAppId, ...visitedAppIds]\n : visitedAppIds;\n\n return (\n <div\n data-dispatch-workspace-app-cache\n className={activeAppId ? \"absolute inset-0 overflow-hidden\" : \"hidden\"}\n >\n {renderedAppIds.map((appId) => {\n const active = appId === activeAppId;\n return (\n <div\n key={appId}\n data-dispatch-workspace-app-cache-entry={appId}\n aria-hidden={!active}\n className={active ? \"h-full min-h-0\" : \"hidden\"}\n >\n <WorkspaceAppHost appId={appId} />\n </div>\n );\n })}\n </div>\n );\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/dispatch",
3
- "version": "0.26.0",
3
+ "version": "0.27.0",
4
4
  "description": "Dispatch — workspace control plane for agent-native apps. Vault, integrations, destinations, scheduled jobs, and cross-app delegation, shipped as a single drop-in package.",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -87,7 +87,7 @@
87
87
  "tailwind-merge": "^3.5.0",
88
88
  "vaul": "^1.1.2",
89
89
  "zod": "^4.3.6",
90
- "@agent-native/toolkit": "0.15.1"
90
+ "@agent-native/toolkit": "0.16.0"
91
91
  },
92
92
  "devDependencies": {
93
93
  "@react-router/dev": "^8.1.0",
@@ -101,7 +101,7 @@
101
101
  "typescript-7": "npm:typescript@^7.0.2",
102
102
  "vite": "8.1.0",
103
103
  "vitest": "^4.1.5",
104
- "@agent-native/core": "0.157.1"
104
+ "@agent-native/core": "0.157.4"
105
105
  },
106
106
  "peerDependencies": {
107
107
  "@agent-native/core": ">=0.8.0",
@@ -15,6 +15,7 @@ const clientState = vi.hoisted(() => {
15
15
  return {
16
16
  actionNames,
17
17
  legacyMutateAsync,
18
+ theme: "dark" as "dark" | "light",
18
19
  workspaceSsoEnabled: false,
19
20
  workspaceSsoMutateAsync,
20
21
  };
@@ -90,6 +91,10 @@ vi.mock("@agent-native/core/client/i18n", () => ({
90
91
  useT: () => (key: string) => key,
91
92
  }));
92
93
 
94
+ vi.mock("next-themes", () => ({
95
+ useTheme: () => ({ resolvedTheme: clientState.theme }),
96
+ }));
97
+
93
98
  import { WorkspaceAppFrame, WorkspaceAppKeepAlive } from "./workspace-app-host";
94
99
 
95
100
  describe("WorkspaceAppKeepAlive", () => {
@@ -104,6 +109,7 @@ describe("WorkspaceAppKeepAlive", () => {
104
109
  clientState.actionNames.length = 0;
105
110
  clientState.legacyMutateAsync.mockClear();
106
111
  clientState.workspaceSsoMutateAsync.mockClear();
112
+ clientState.theme = "dark";
107
113
  clientState.workspaceSsoEnabled = false;
108
114
  });
109
115
 
@@ -163,6 +169,57 @@ describe("WorkspaceAppKeepAlive", () => {
163
169
  expect(clientState.legacyMutateAsync).not.toHaveBeenCalled();
164
170
  });
165
171
 
172
+ it("sends the parent theme on iframe load and when the parent changes", async () => {
173
+ await act(async () => {
174
+ root.render(
175
+ <WorkspaceAppFrame app={{ id: "mail", name: "Mail", path: "/mail" }} />,
176
+ );
177
+ await Promise.resolve();
178
+ await Promise.resolve();
179
+ });
180
+
181
+ const iframe = container.querySelector<HTMLIFrameElement>("iframe");
182
+ expect(iframe).not.toBeNull();
183
+ if (!iframe) throw new Error("Workspace app iframe was not rendered");
184
+
185
+ const postMessage = vi.fn();
186
+ Object.defineProperty(iframe, "contentWindow", {
187
+ configurable: true,
188
+ value: { postMessage },
189
+ });
190
+
191
+ await act(async () => {
192
+ iframe?.dispatchEvent(new Event("load"));
193
+ await Promise.resolve();
194
+ });
195
+
196
+ expect(postMessage).toHaveBeenCalledWith(
197
+ {
198
+ type: "agent-native-theme-update",
199
+ theme: "dark",
200
+ isDark: true,
201
+ },
202
+ "*",
203
+ );
204
+
205
+ clientState.theme = "light";
206
+ await act(async () => {
207
+ root.render(
208
+ <WorkspaceAppFrame app={{ id: "mail", name: "Mail", path: "/mail" }} />,
209
+ );
210
+ await Promise.resolve();
211
+ });
212
+
213
+ expect(postMessage).toHaveBeenLastCalledWith(
214
+ {
215
+ type: "agent-native-theme-update",
216
+ theme: "light",
217
+ isDark: false,
218
+ },
219
+ "*",
220
+ );
221
+ });
222
+
166
223
  it("evicts the oldest inactive app after reaching the keep-alive limit", async () => {
167
224
  await act(async () => {
168
225
  root.render(<WorkspaceAppKeepAlive activeAppId="mail" />);
@@ -11,8 +11,14 @@ import {
11
11
  } from "@agent-native/core/client/hooks";
12
12
  import { useT } from "@agent-native/core/client/i18n";
13
13
  import { withBuilderUtmTrackingParams } from "@agent-native/core/shared/builder-link-tracking";
14
- import { IconArrowLeft, IconClockHour4 } from "@tabler/icons-react";
15
- import { useEffect, useMemo, useRef, useState } from "react";
14
+ import {
15
+ IconArrowLeft,
16
+ IconArrowUpRight,
17
+ IconClockHour4,
18
+ IconLock,
19
+ } from "@tabler/icons-react";
20
+ import { useTheme } from "next-themes";
21
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
16
22
  import { Link } from "react-router";
17
23
 
18
24
  import { isEmbedSessionExpiredMessage } from "../lib/embed-session-recovery";
@@ -39,6 +45,40 @@ interface EmbedSessionInput {
39
45
  chrome: "minimal";
40
46
  }
41
47
 
48
+ type WorkspaceAppTheme = "light" | "dark";
49
+ type WorkspaceAppAuthState = "unknown" | "authenticated" | "unauthenticated";
50
+
51
+ function resolveWorkspaceAppAuthState(
52
+ rawUrl: string | null,
53
+ ): WorkspaceAppAuthState {
54
+ if (!rawUrl) return "unknown";
55
+ try {
56
+ const lastSegment = new URL(rawUrl, window.location.origin).pathname
57
+ .split("/")
58
+ .filter(Boolean)
59
+ .at(-1)
60
+ ?.toLowerCase();
61
+ if (
62
+ lastSegment === "sign-in" ||
63
+ lastSegment === "login" ||
64
+ lastSegment === "signup"
65
+ ) {
66
+ return "unauthenticated";
67
+ }
68
+ return "authenticated";
69
+ } catch {
70
+ return "unknown";
71
+ }
72
+ }
73
+
74
+ function buildWorkspaceAppThemeUpdate(theme: WorkspaceAppTheme) {
75
+ return {
76
+ type: "agent-native-theme-update" as const,
77
+ theme,
78
+ isDark: theme === "dark",
79
+ };
80
+ }
81
+
42
82
  export function buildChatFirstEmbedSessionInput(
43
83
  appId: string,
44
84
  path: string,
@@ -68,10 +108,38 @@ export function WorkspaceAppFrame({
68
108
  chatSidebar = false,
69
109
  copy = defaultChatFirstCopy,
70
110
  }: WorkspaceAppFrameProps) {
111
+ const { resolvedTheme } = useTheme();
112
+ const theme: WorkspaceAppTheme =
113
+ resolvedTheme === "dark" || resolvedTheme === "light"
114
+ ? resolvedTheme
115
+ : typeof document !== "undefined" &&
116
+ document.documentElement.classList.contains("dark")
117
+ ? "dark"
118
+ : "light";
71
119
  const [embedUrl, setEmbedUrl] = useState<string | null>(null);
72
120
  const [embedError, setEmbedError] = useState<Error | null>(null);
73
121
  const [embedAttempt, setEmbedAttempt] = useState(0);
122
+ const [authState, setAuthState] = useState<WorkspaceAppAuthState>("unknown");
74
123
  const embedFrameRef = useRef<HTMLIFrameElement>(null);
124
+ const postThemeToFrame = useCallback(() => {
125
+ embedFrameRef.current?.contentWindow?.postMessage(
126
+ buildWorkspaceAppThemeUpdate(theme),
127
+ "*",
128
+ );
129
+ }, [theme]);
130
+ const handleFrameLoad = useCallback(() => {
131
+ postThemeToFrame();
132
+ const frame = embedFrameRef.current;
133
+ let frameUrl = embedUrl;
134
+ try {
135
+ frameUrl = frame?.contentWindow?.location.href ?? frameUrl;
136
+ // coercion-ok: Cross-origin frames cannot expose location; their auth state arrives by message.
137
+ } catch {
138
+ // Cross-origin app frames report their auth state through postMessage.
139
+ }
140
+ const nextAuthState = resolveWorkspaceAppAuthState(frameUrl);
141
+ if (nextAuthState !== "unknown") setAuthState(nextAuthState);
142
+ }, [embedUrl, postThemeToFrame]);
75
143
  const workspaceSsoEnabled = useFeatureFlag(DISPATCH_WORKSPACE_SSO_FLAG.key);
76
144
  const createEmbedSession = useActionMutation<
77
145
  EmbedSessionResult,
@@ -108,6 +176,7 @@ export function WorkspaceAppFrame({
108
176
  let cancelled = false;
109
177
  setEmbedUrl(null);
110
178
  setEmbedError(null);
179
+ setAuthState("unknown");
111
180
  const createSession = workspaceSsoEnabled
112
181
  ? createWorkspaceSsoEmbedSession
113
182
  : createEmbedSession;
@@ -158,6 +227,25 @@ export function WorkspaceAppFrame({
158
227
  window.removeEventListener("message", handleEmbedSessionExpired);
159
228
  }, [embedUrl]);
160
229
 
230
+ useEffect(() => {
231
+ const handleAuthState = (event: MessageEvent) => {
232
+ const frame = embedFrameRef.current;
233
+ if (!frame || event.source !== frame.contentWindow) return;
234
+ if (event.data?.type !== "agentNative.authState") return;
235
+ const status = event.data.data?.status;
236
+ if (status === "authenticated" || status === "unauthenticated") {
237
+ setAuthState(status);
238
+ }
239
+ };
240
+
241
+ window.addEventListener("message", handleAuthState);
242
+ return () => window.removeEventListener("message", handleAuthState);
243
+ }, []);
244
+
245
+ useEffect(() => {
246
+ postThemeToFrame();
247
+ }, [embedUrl, postThemeToFrame]);
248
+
161
249
  const appPane = (
162
250
  <ChatFirstAppPane
163
251
  app={app}
@@ -182,6 +270,7 @@ export function WorkspaceAppFrame({
182
270
  src={url}
183
271
  title={title ?? app.name}
184
272
  ref={embedFrameRef}
273
+ onLoad={handleFrameLoad}
185
274
  referrerPolicy="no-referrer"
186
275
  allow="clipboard-read; clipboard-write"
187
276
  className="h-full w-full border-0 bg-background"
@@ -211,6 +300,24 @@ export function WorkspaceAppFrame({
211
300
  dynamicSuggestions={false}
212
301
  suggestions={[]}
213
302
  emptyStateText={`Ask about ${app.name}`}
303
+ composerSlot={
304
+ authState === "unauthenticated" ? (
305
+ <div className="flex shrink-0 items-center px-3 pb-1">
306
+ <button
307
+ type="button"
308
+ data-dispatch-app-sign-in
309
+ aria-label={`Sign in to ${app.name} on the right`}
310
+ title={`Sign in to ${app.name} on the right`}
311
+ onClick={() => embedFrameRef.current?.focus()}
312
+ className="inline-flex h-6 shrink-0 items-center gap-1 rounded-full border border-border/70 bg-background/60 px-2 text-[11px] font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
313
+ >
314
+ <IconLock size={12} stroke={1.8} />
315
+ <span>Sign in on the right</span>
316
+ <IconArrowUpRight size={12} stroke={1.8} />
317
+ </button>
318
+ </div>
319
+ ) : null
320
+ }
214
321
  >
215
322
  {appPane}
216
323
  </AgentSidebar>