@agent-native/dispatch 0.8.6 → 0.8.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/list_apps.js +1 -1
- package/dist/actions/list_apps.js.map +1 -1
- package/dist/actions/open_app.d.ts.map +1 -1
- package/dist/actions/open_app.js +7 -4
- package/dist/actions/open_app.js.map +1 -1
- package/dist/components/workspace-app-card.d.ts.map +1 -1
- package/dist/components/workspace-app-card.js +2 -1
- package/dist/components/workspace-app-card.js.map +1 -1
- package/dist/routes/pages/metrics.d.ts.map +1 -1
- package/dist/routes/pages/metrics.js +3 -1
- package/dist/routes/pages/metrics.js.map +1 -1
- package/dist/server/lib/app-creation-store.d.ts.map +1 -1
- package/dist/server/lib/app-creation-store.js +104 -10
- package/dist/server/lib/app-creation-store.js.map +1 -1
- package/dist/server/lib/mcp-gateway.d.ts.map +1 -1
- package/dist/server/lib/mcp-gateway.js +160 -4
- package/dist/server/lib/mcp-gateway.js.map +1 -1
- package/dist/server/lib/usage-metrics-store.d.ts +1 -0
- package/dist/server/lib/usage-metrics-store.d.ts.map +1 -1
- package/dist/server/lib/usage-metrics-store.js +1 -0
- package/dist/server/lib/usage-metrics-store.js.map +1 -1
- package/package.json +1 -1
- package/src/actions/list_apps.ts +1 -1
- package/src/actions/open_app.ts +11 -4
- package/src/components/workspace-app-card.tsx +3 -2
- package/src/routes/pages/metrics.tsx +4 -1
- package/src/server/lib/app-creation-store.spec.ts +240 -0
- package/src/server/lib/app-creation-store.ts +130 -11
- package/src/server/lib/mcp-gateway.spec.ts +295 -0
- package/src/server/lib/mcp-gateway.ts +187 -4
- package/src/server/lib/usage-metrics-store.ts +2 -0
|
@@ -1,13 +1,80 @@
|
|
|
1
1
|
import { callAgent, signA2AToken } from "@agent-native/core/a2a";
|
|
2
2
|
import { buildMcpToolName, McpClientManager, } from "@agent-native/core/mcp-client";
|
|
3
|
-
import { buildDeepLink } from "@agent-native/core/server";
|
|
3
|
+
import { buildDeepLink, buildEmbedStartPath, createEmbedSessionTicket, getRequestContext, } from "@agent-native/core/server";
|
|
4
4
|
import { discoverAgents, } from "@agent-native/core/server/agent-discovery";
|
|
5
5
|
import { getRequestOrgId, getRequestUserEmail, } from "@agent-native/core/server";
|
|
6
6
|
import { getOrgA2ASecret, getOrgDomain } from "@agent-native/core/org";
|
|
7
7
|
import { getDispatchMcpAppAccessSettings, isAppAllowedByMcpAccess, } from "./mcp-access-store.js";
|
|
8
|
+
const DISPATCH_APP_ID = "dispatch";
|
|
9
|
+
const DISPATCH_NAME = "Agent-Native Dispatch";
|
|
10
|
+
const DISPATCH_DESCRIPTION = "Workspace control plane for extensions, agents, vault, integrations, approvals, and app routing.";
|
|
11
|
+
const DISPATCH_COLOR = "#14B8A6";
|
|
8
12
|
function normalizeAppId(value) {
|
|
9
13
|
return value.trim().toLowerCase();
|
|
10
14
|
}
|
|
15
|
+
function normalizeBaseUrl(raw) {
|
|
16
|
+
const value = raw?.trim();
|
|
17
|
+
if (!value)
|
|
18
|
+
return null;
|
|
19
|
+
try {
|
|
20
|
+
const url = new URL(value);
|
|
21
|
+
if (url.protocol !== "http:" && url.protocol !== "https:")
|
|
22
|
+
return null;
|
|
23
|
+
return url.toString().replace(/\/+$/, "");
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function normalizeBasePath(value) {
|
|
30
|
+
const trimmed = value?.trim();
|
|
31
|
+
if (!trimmed || trimmed === "/")
|
|
32
|
+
return "";
|
|
33
|
+
const normalized = trimmed.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
34
|
+
return normalized ? `/${normalized}` : "";
|
|
35
|
+
}
|
|
36
|
+
function withConfiguredBasePath(baseUrl) {
|
|
37
|
+
const basePath = normalizeBasePath(process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH);
|
|
38
|
+
if (!basePath)
|
|
39
|
+
return baseUrl;
|
|
40
|
+
try {
|
|
41
|
+
const url = new URL(baseUrl);
|
|
42
|
+
const path = normalizeBasePath(url.pathname);
|
|
43
|
+
if (path === basePath || path.startsWith(`${basePath}/`)) {
|
|
44
|
+
return baseUrl;
|
|
45
|
+
}
|
|
46
|
+
url.pathname = path && path !== "/" ? `${basePath}${path}` : `${basePath}/`;
|
|
47
|
+
return url.toString().replace(/\/+$/, "");
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return baseUrl;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function dispatchSelfBaseUrl() {
|
|
54
|
+
const requestOrigin = normalizeBaseUrl(getRequestContext()?.requestOrigin);
|
|
55
|
+
if (requestOrigin)
|
|
56
|
+
return withConfiguredBasePath(requestOrigin);
|
|
57
|
+
const configured = normalizeBaseUrl(process.env.WORKSPACE_GATEWAY_URL) ??
|
|
58
|
+
normalizeBaseUrl(process.env.APP_URL) ??
|
|
59
|
+
normalizeBaseUrl(process.env.URL) ??
|
|
60
|
+
normalizeBaseUrl(process.env.DEPLOY_URL) ??
|
|
61
|
+
normalizeBaseUrl(process.env.BETTER_AUTH_URL);
|
|
62
|
+
if (configured)
|
|
63
|
+
return withConfiguredBasePath(configured);
|
|
64
|
+
return process.env.NODE_ENV === "production"
|
|
65
|
+
? "https://dispatch.agent-native.com"
|
|
66
|
+
: "http://localhost:8092";
|
|
67
|
+
}
|
|
68
|
+
function dispatchSelfApp(settings) {
|
|
69
|
+
return {
|
|
70
|
+
id: DISPATCH_APP_ID,
|
|
71
|
+
name: DISPATCH_NAME,
|
|
72
|
+
description: DISPATCH_DESCRIPTION,
|
|
73
|
+
url: dispatchSelfBaseUrl(),
|
|
74
|
+
color: DISPATCH_COLOR,
|
|
75
|
+
granted: isAppAllowedByMcpAccess(DISPATCH_APP_ID, settings),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
11
78
|
const CONTROL_CHARS = new RegExp("[\\u0000-\\u001f\\u007f]");
|
|
12
79
|
function safeAppPath(raw) {
|
|
13
80
|
if (typeof raw !== "string" || !raw.trim())
|
|
@@ -21,6 +88,18 @@ function safeAppPath(raw) {
|
|
|
21
88
|
return null;
|
|
22
89
|
if (/^\/[a-z][a-z0-9+.-]*:/i.test(value))
|
|
23
90
|
return null;
|
|
91
|
+
if (/%(?:2f|5c)/i.test(value))
|
|
92
|
+
return null;
|
|
93
|
+
const rawPath = value.split(/[?#]/, 1)[0] ?? value;
|
|
94
|
+
let parsed;
|
|
95
|
+
try {
|
|
96
|
+
parsed = new URL(value, "http://agent-native.invalid");
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
if (parsed.pathname !== rawPath)
|
|
102
|
+
return null;
|
|
24
103
|
return value;
|
|
25
104
|
}
|
|
26
105
|
function appendParamsToPath(path, params) {
|
|
@@ -38,6 +117,44 @@ function appOrigin(app) {
|
|
|
38
117
|
function appBaseUrl(app) {
|
|
39
118
|
return app.url.replace(/\/+$/, "");
|
|
40
119
|
}
|
|
120
|
+
function appBasePath(app) {
|
|
121
|
+
const pathname = new URL(appBaseUrl(app)).pathname.replace(/\/+$/, "");
|
|
122
|
+
return pathname === "/" ? "" : pathname;
|
|
123
|
+
}
|
|
124
|
+
function appMatchesUrlPath(app, url) {
|
|
125
|
+
if (url.origin !== appOrigin(app))
|
|
126
|
+
return false;
|
|
127
|
+
const basePath = appBasePath(app);
|
|
128
|
+
if (!basePath)
|
|
129
|
+
return true;
|
|
130
|
+
return url.pathname === basePath || url.pathname.startsWith(`${basePath}/`);
|
|
131
|
+
}
|
|
132
|
+
function appPathSpecificity(app) {
|
|
133
|
+
return appBasePath(app).length;
|
|
134
|
+
}
|
|
135
|
+
function appRelativePath(app, url) {
|
|
136
|
+
const basePath = appBasePath(app);
|
|
137
|
+
const path = basePath
|
|
138
|
+
? url.pathname === basePath
|
|
139
|
+
? "/"
|
|
140
|
+
: url.pathname.slice(basePath.length)
|
|
141
|
+
: url.pathname;
|
|
142
|
+
return `${path || "/"}${url.search}${url.hash}`;
|
|
143
|
+
}
|
|
144
|
+
function isDispatchControlPath(path) {
|
|
145
|
+
if (!path)
|
|
146
|
+
return false;
|
|
147
|
+
const route = path.split(/[?#]/, 1)[0] ?? path;
|
|
148
|
+
return (route === "/extensions" ||
|
|
149
|
+
route.startsWith("/extensions/") ||
|
|
150
|
+
route === "/tools" ||
|
|
151
|
+
route.startsWith("/tools/"));
|
|
152
|
+
}
|
|
153
|
+
function assertAppCanOpenPath(app, path) {
|
|
154
|
+
if (app.id !== DISPATCH_APP_ID && isDispatchControlPath(path)) {
|
|
155
|
+
throw new Error(`Path "${path}" belongs to Dispatch. Use app: "dispatch" for Dispatch extension and tool routes.`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
41
158
|
function toAccessibleApp(agent, settings) {
|
|
42
159
|
return {
|
|
43
160
|
id: agent.id,
|
|
@@ -55,7 +172,12 @@ export async function listDispatchMcpApps() {
|
|
|
55
172
|
]);
|
|
56
173
|
return {
|
|
57
174
|
settings,
|
|
58
|
-
apps:
|
|
175
|
+
apps: [
|
|
176
|
+
dispatchSelfApp(settings),
|
|
177
|
+
...agents
|
|
178
|
+
.filter((agent) => normalizeAppId(agent.id) !== DISPATCH_APP_ID)
|
|
179
|
+
.map((agent) => toAccessibleApp(agent, settings)),
|
|
180
|
+
],
|
|
59
181
|
};
|
|
60
182
|
}
|
|
61
183
|
export async function listGrantedDispatchMcpApps() {
|
|
@@ -101,10 +223,16 @@ export async function askGrantedDispatchMcpApp(app, message) {
|
|
|
101
223
|
}
|
|
102
224
|
export async function openGrantedDispatchMcpApp(input) {
|
|
103
225
|
const view = input.view?.trim() ?? "";
|
|
226
|
+
const hasPathInput = input.path != null;
|
|
104
227
|
const path = safeAppPath(input.path);
|
|
228
|
+
if (hasPathInput && !path) {
|
|
229
|
+
throw new Error("path must be a safe app-relative route");
|
|
230
|
+
}
|
|
105
231
|
if (!view && !path)
|
|
106
232
|
throw new Error("open_app requires view or path");
|
|
107
233
|
const target = await resolveGrantedDispatchMcpApp(input.app);
|
|
234
|
+
if (path)
|
|
235
|
+
assertAppCanOpenPath(target, path);
|
|
108
236
|
const relUrl = path
|
|
109
237
|
? appendParamsToPath(path, input.params)
|
|
110
238
|
: buildDeepLink({
|
|
@@ -146,6 +274,7 @@ async function resolveDispatchEmbedTarget(input) {
|
|
|
146
274
|
const path = safeAppPath(input.path);
|
|
147
275
|
if (!path)
|
|
148
276
|
throw new Error("path must be a safe app-relative route");
|
|
277
|
+
assertAppCanOpenPath(explicitApp, path);
|
|
149
278
|
return {
|
|
150
279
|
app: explicitApp,
|
|
151
280
|
path,
|
|
@@ -173,21 +302,48 @@ async function resolveDispatchEmbedTarget(input) {
|
|
|
173
302
|
};
|
|
174
303
|
}
|
|
175
304
|
const apps = explicitApp ? [explicitApp] : await listGrantedDispatchMcpApps();
|
|
176
|
-
const target = apps
|
|
305
|
+
const target = apps
|
|
306
|
+
.filter((app) => appMatchesUrlPath(app, parsed))
|
|
307
|
+
.sort((a, b) => appPathSpecificity(b) - appPathSpecificity(a))[0];
|
|
177
308
|
if (!target) {
|
|
178
309
|
throw new Error("Embed URL must belong to an app granted through Dispatch.");
|
|
179
310
|
}
|
|
180
|
-
const path = safeAppPath(
|
|
311
|
+
const path = safeAppPath(appRelativePath(target, parsed));
|
|
181
312
|
if (!path)
|
|
182
313
|
throw new Error("Embed URL path is not safe.");
|
|
314
|
+
assertAppCanOpenPath(target, path);
|
|
183
315
|
return { app: target, path, url: `${appBaseUrl(target)}${path}` };
|
|
184
316
|
}
|
|
317
|
+
async function createDispatchSelfEmbedSession(input) {
|
|
318
|
+
const ticket = await createEmbedSessionTicket({
|
|
319
|
+
ownerEmail: input.ownerEmail,
|
|
320
|
+
orgId: input.orgId,
|
|
321
|
+
targetPath: input.path,
|
|
322
|
+
scope: input.chrome ?? null,
|
|
323
|
+
});
|
|
324
|
+
const startPath = buildEmbedStartPath(ticket.ticket);
|
|
325
|
+
return {
|
|
326
|
+
startUrl: new URL(startPath, input.baseUrl).toString(),
|
|
327
|
+
targetPath: input.path,
|
|
328
|
+
expiresAt: ticket.expiresAt,
|
|
329
|
+
app: DISPATCH_APP_ID,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
185
332
|
export async function createGrantedDispatchMcpEmbedSession(input) {
|
|
186
333
|
const userEmail = getRequestUserEmail();
|
|
187
334
|
if (!userEmail)
|
|
188
335
|
throw new Error("no authenticated user");
|
|
189
336
|
const target = await resolveDispatchEmbedTarget(input);
|
|
190
337
|
const orgId = getRequestOrgId();
|
|
338
|
+
if (target.app.id === DISPATCH_APP_ID) {
|
|
339
|
+
return createDispatchSelfEmbedSession({
|
|
340
|
+
ownerEmail: userEmail,
|
|
341
|
+
orgId,
|
|
342
|
+
path: target.path,
|
|
343
|
+
baseUrl: appBaseUrl(target.app),
|
|
344
|
+
chrome: input.chrome,
|
|
345
|
+
});
|
|
346
|
+
}
|
|
191
347
|
const [orgDomain, orgSecret] = orgId
|
|
192
348
|
? await Promise.all([
|
|
193
349
|
getOrgDomain(orgId).catch(() => null),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-gateway.js","sourceRoot":"","sources":["../../../src/server/lib/mcp-gateway.ts"],"names":[],"mappings":"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","sourcesContent":["import { callAgent, signA2AToken } from \"@agent-native/core/a2a\";\nimport {\n buildMcpToolName,\n McpClientManager,\n} from \"@agent-native/core/mcp-client\";\nimport { buildDeepLink } from \"@agent-native/core/server\";\nimport {\n discoverAgents,\n type DiscoveredAgent,\n} from \"@agent-native/core/server/agent-discovery\";\nimport {\n getRequestOrgId,\n getRequestUserEmail,\n} from \"@agent-native/core/server\";\nimport { getOrgA2ASecret, getOrgDomain } from \"@agent-native/core/org\";\nimport {\n getDispatchMcpAppAccessSettings,\n isAppAllowedByMcpAccess,\n type DispatchMcpAppAccessSettings,\n} from \"./mcp-access-store.js\";\n\nexport interface DispatchMcpAccessibleApp {\n id: string;\n name: string;\n description: string;\n url: string;\n color: string;\n granted: boolean;\n}\n\nfunction normalizeAppId(value: string): string {\n return value.trim().toLowerCase();\n}\n\nconst CONTROL_CHARS = new RegExp(\"[\\\\u0000-\\\\u001f\\\\u007f]\");\n\nfunction safeAppPath(raw: unknown): string | null {\n if (typeof raw !== \"string\" || !raw.trim()) return null;\n const value = raw.trim();\n if (CONTROL_CHARS.test(value)) return null;\n if (!value.startsWith(\"/\")) return null;\n if (value.startsWith(\"//\") || value.startsWith(\"/\\\\\")) return null;\n if (/^\\/[a-z][a-z0-9+.-]*:/i.test(value)) return null;\n return value;\n}\n\nfunction appendParamsToPath(\n path: string,\n params: Record<string, string | number | boolean> | undefined,\n): string {\n if (!params || Object.keys(params).length === 0) return path;\n const url = new URL(path, \"http://agent-native.invalid\");\n for (const [key, value] of Object.entries(params)) {\n url.searchParams.set(key, String(value));\n }\n return `${url.pathname}${url.search}${url.hash}`;\n}\n\nfunction appOrigin(app: DispatchMcpAccessibleApp): string {\n return new URL(app.url).origin;\n}\n\nfunction appBaseUrl(app: DispatchMcpAccessibleApp): string {\n return app.url.replace(/\\/+$/, \"\");\n}\n\nfunction toAccessibleApp(\n agent: DiscoveredAgent,\n settings: DispatchMcpAppAccessSettings,\n): DispatchMcpAccessibleApp {\n return {\n id: agent.id,\n name: agent.name,\n description: agent.description,\n url: agent.url,\n color: agent.color,\n granted: isAppAllowedByMcpAccess(agent.id, settings),\n };\n}\n\nexport async function listDispatchMcpApps(): Promise<{\n settings: DispatchMcpAppAccessSettings;\n apps: DispatchMcpAccessibleApp[];\n}> {\n const [settings, agents] = await Promise.all([\n getDispatchMcpAppAccessSettings(),\n discoverAgents(\"dispatch\"),\n ]);\n return {\n settings,\n apps: agents.map((agent) => toAccessibleApp(agent, settings)),\n };\n}\n\nexport async function listGrantedDispatchMcpApps(): Promise<\n DispatchMcpAccessibleApp[]\n> {\n const { apps } = await listDispatchMcpApps();\n return apps.filter((app) => app.granted);\n}\n\nexport async function resolveGrantedDispatchMcpApp(\n app: string,\n): Promise<DispatchMcpAccessibleApp> {\n const target = normalizeAppId(app);\n if (!target) throw new Error(\"app is required\");\n const { apps } = await listDispatchMcpApps();\n const match = apps.find(\n (candidate) =>\n candidate.id === target || candidate.name.toLowerCase() === target,\n );\n if (!match) {\n throw new Error(\n `Unknown app \"${app}\". Call list_apps to see apps available through Dispatch MCP.`,\n );\n }\n if (!match.granted) {\n throw new Error(\n `Dispatch MCP access to \"${match.id}\" is not granted. Open Dispatch > Agents to change MCP app access.`,\n );\n }\n return match;\n}\n\nexport async function askGrantedDispatchMcpApp(\n app: string,\n message: string,\n): Promise<{ app: string; routedVia: \"a2a\"; response: string }> {\n const trimmedMessage = message.trim();\n if (!trimmedMessage) throw new Error(\"message is required\");\n const target = await resolveGrantedDispatchMcpApp(app);\n const userEmail = getRequestUserEmail();\n if (!userEmail) throw new Error(\"no authenticated user\");\n\n const orgId = getRequestOrgId();\n const [orgDomain, orgSecret] = orgId\n ? await Promise.all([\n getOrgDomain(orgId).catch(() => null),\n getOrgA2ASecret(orgId).catch(() => null),\n ])\n : [null, null];\n\n const response = await callAgent(target.url, trimmedMessage, {\n userEmail,\n orgDomain: orgDomain ?? undefined,\n orgSecret: orgSecret ?? undefined,\n timeoutMs: 5 * 60_000,\n });\n return { app: target.id, routedVia: \"a2a\", response };\n}\n\nexport async function openGrantedDispatchMcpApp(input: {\n app: string;\n view?: string;\n path?: string;\n params?: Record<string, string | number | boolean>;\n embed?: boolean;\n chrome?: \"full\" | \"minimal\";\n}): Promise<{\n app: string;\n view?: string;\n path?: string;\n url: string;\n embed?: boolean;\n chrome?: \"full\" | \"minimal\";\n}> {\n const view = input.view?.trim() ?? \"\";\n const path = safeAppPath(input.path);\n if (!view && !path) throw new Error(\"open_app requires view or path\");\n const target = await resolveGrantedDispatchMcpApp(input.app);\n const relUrl = path\n ? appendParamsToPath(path, input.params)\n : buildDeepLink({\n app: target.id,\n view,\n params: input.params,\n });\n return {\n app: target.id,\n ...(view ? { view } : {}),\n ...(path ? { path } : {}),\n url: `${appBaseUrl(target)}${relUrl}`,\n ...(input.embed === true ? { embed: true } : {}),\n ...(input.chrome ? { chrome: input.chrome } : {}),\n };\n}\n\nfunction parseMcpToolTextResult(result: unknown): Record<string, unknown> {\n if (result && typeof result === \"object\") {\n const structured = (result as any).structuredContent;\n if (structured && typeof structured === \"object\") return structured;\n const parts = Array.isArray((result as any).content)\n ? ((result as any).content as Array<Record<string, unknown>>)\n : [];\n const text = parts.find(\n (part) => part?.type === \"text\" && typeof part.text === \"string\",\n )?.text;\n if (typeof text === \"string\" && text.trim()) {\n const parsed = JSON.parse(text);\n if (parsed && typeof parsed === \"object\") return parsed;\n }\n }\n throw new Error(\"Target app did not return an embed session.\");\n}\n\nasync function resolveDispatchEmbedTarget(input: {\n app?: string;\n url?: string;\n path?: string;\n}): Promise<{ app: DispatchMcpAccessibleApp; path: string; url: string }> {\n const explicitApp = input.app?.trim()\n ? await resolveGrantedDispatchMcpApp(input.app)\n : null;\n if (explicitApp && input.path) {\n const path = safeAppPath(input.path);\n if (!path) throw new Error(\"path must be a safe app-relative route\");\n return {\n app: explicitApp,\n path,\n url: `${appBaseUrl(explicitApp)}${path}`,\n };\n }\n\n if (!input.url) {\n throw new Error(\"create_embed_session requires a url or app + path.\");\n }\n\n let parsed: URL;\n try {\n parsed = new URL(input.url);\n } catch {\n if (!explicitApp) {\n throw new Error(\"Relative embed paths require an app id.\");\n }\n const path = safeAppPath(input.url);\n if (!path) throw new Error(\"url must be a safe app route.\");\n return {\n app: explicitApp,\n path,\n url: `${appBaseUrl(explicitApp)}${path}`,\n };\n }\n\n const apps = explicitApp ? [explicitApp] : await listGrantedDispatchMcpApps();\n const target = apps.find((app) => parsed.origin === appOrigin(app));\n if (!target) {\n throw new Error(\n \"Embed URL must belong to an app granted through Dispatch.\",\n );\n }\n const path = safeAppPath(`${parsed.pathname}${parsed.search}${parsed.hash}`);\n if (!path) throw new Error(\"Embed URL path is not safe.\");\n return { app: target, path, url: `${appBaseUrl(target)}${path}` };\n}\n\nexport async function createGrantedDispatchMcpEmbedSession(input: {\n app?: string;\n url?: string;\n path?: string;\n chrome?: \"full\" | \"minimal\";\n}): Promise<{\n startUrl: string;\n targetPath?: string;\n expiresAt?: number;\n app: string;\n}> {\n const userEmail = getRequestUserEmail();\n if (!userEmail) throw new Error(\"no authenticated user\");\n const target = await resolveDispatchEmbedTarget(input);\n\n const orgId = getRequestOrgId();\n const [orgDomain, orgSecret] = orgId\n ? await Promise.all([\n getOrgDomain(orgId).catch(() => null),\n getOrgA2ASecret(orgId).catch(() => null),\n ])\n : [null, null];\n const token = await signA2AToken(\n userEmail,\n orgDomain ?? undefined,\n orgSecret ?? undefined,\n {\n expiresIn: \"5m\",\n preferGlobalSecret: !orgSecret,\n },\n );\n\n const serverId = \"target\";\n const manager = new McpClientManager({\n servers: {\n [serverId]: {\n type: \"http\",\n url: `${appBaseUrl(target.app)}/_agent-native/mcp`,\n headers: {\n Authorization: `Bearer ${token}`,\n },\n },\n },\n });\n await manager.start();\n try {\n const result = await manager.callTool(\n buildMcpToolName(serverId, \"create_embed_session\"),\n {\n url: target.url,\n chrome: input.chrome ?? \"full\",\n },\n );\n const parsed = parseMcpToolTextResult(result) as {\n startUrl?: string;\n targetPath?: string;\n expiresAt?: number;\n };\n if (!parsed.startUrl) {\n throw new Error(\"Target app did not return an embed start URL.\");\n }\n const output: {\n startUrl: string;\n targetPath?: string;\n expiresAt?: number;\n app: string;\n } = {\n startUrl: parsed.startUrl,\n app: target.app.id,\n };\n if (parsed.targetPath) output.targetPath = parsed.targetPath;\n if (typeof parsed.expiresAt === \"number\")\n output.expiresAt = parsed.expiresAt;\n return output;\n } finally {\n await manager.stop();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"mcp-gateway.js","sourceRoot":"","sources":["../../../src/server/lib/mcp-gateway.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EACL,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,wBAAwB,EACxB,iBAAiB,GAClB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,cAAc,GAEf,MAAM,2CAA2C,CAAC;AACnD,OAAO,EACL,eAAe,EACf,mBAAmB,GACpB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,EACL,+BAA+B,EAC/B,uBAAuB,GAExB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,eAAe,GAAG,UAAU,CAAC;AACnC,MAAM,aAAa,GAAG,uBAAuB,CAAC;AAC9C,MAAM,oBAAoB,GACxB,kGAAkG,CAAC;AACrG,MAAM,cAAc,GAAG,SAAS,CAAC;AAWjC,SAAS,cAAc,CAAC,KAAa;IACnC,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AACpC,CAAC;AAED,SAAS,gBAAgB,CAAC,GAA8B;IACtD,MAAM,KAAK,GAAG,GAAG,EAAE,IAAI,EAAE,CAAC;IAC1B,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3B,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QACvE,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAyB;IAClD,MAAM,OAAO,GAAG,KAAK,EAAE,IAAI,EAAE,CAAC;IAC9B,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,GAAG;QAAE,OAAO,EAAE,CAAC;IAC3C,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACnE,OAAO,UAAU,CAAC,CAAC,CAAC,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAC5C,CAAC;AAED,SAAS,sBAAsB,CAAC,OAAe;IAC7C,MAAM,QAAQ,GAAG,iBAAiB,CAChC,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAC5D,CAAC;IACF,IAAI,CAAC,QAAQ;QAAE,OAAO,OAAO,CAAC;IAC9B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;QAC7B,MAAM,IAAI,GAAG,iBAAiB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7C,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,QAAQ,GAAG,CAAC,EAAE,CAAC;YACzD,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,GAAG,CAAC,QAAQ,GAAG,IAAI,IAAI,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,QAAQ,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,QAAQ,GAAG,CAAC;QAC5E,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB;IAC1B,MAAM,aAAa,GAAG,gBAAgB,CAAC,iBAAiB,EAAE,EAAE,aAAa,CAAC,CAAC;IAC3E,IAAI,aAAa;QAAE,OAAO,sBAAsB,CAAC,aAAa,CAAC,CAAC;IAEhE,MAAM,UAAU,GACd,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;QACnD,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;QACrC,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;QACjC,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;QACxC,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAChD,IAAI,UAAU;QAAE,OAAO,sBAAsB,CAAC,UAAU,CAAC,CAAC;IAE1D,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;QAC1C,CAAC,CAAC,mCAAmC;QACrC,CAAC,CAAC,uBAAuB,CAAC;AAC9B,CAAC;AAED,SAAS,eAAe,CACtB,QAAsC;IAEtC,OAAO;QACL,EAAE,EAAE,eAAe;QACnB,IAAI,EAAE,aAAa;QACnB,WAAW,EAAE,oBAAoB;QACjC,GAAG,EAAE,mBAAmB,EAAE;QAC1B,KAAK,EAAE,cAAc;QACrB,OAAO,EAAE,uBAAuB,CAAC,eAAe,EAAE,QAAQ,CAAC;KAC5D,CAAC;AACJ,CAAC;AAED,MAAM,aAAa,GAAG,IAAI,MAAM,CAAC,0BAA0B,CAAC,CAAC;AAE7D,SAAS,WAAW,CAAC,GAAY;IAC/B,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE;QAAE,OAAO,IAAI,CAAC;IACxD,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACzB,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3C,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACnE,IAAI,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACtD,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3C,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC;IACnD,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,EAAE,6BAA6B,CAAC,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO;QAAE,OAAO,IAAI,CAAC;IAC7C,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,kBAAkB,CACzB,IAAY,EACZ,MAA6D;IAE7D,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,6BAA6B,CAAC,CAAC;IACzD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,GAAG,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;AACnD,CAAC;AAED,SAAS,SAAS,CAAC,GAA6B;IAC9C,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;AACjC,CAAC;AAED,SAAS,UAAU,CAAC,GAA6B;IAC/C,OAAO,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,WAAW,CAAC,GAA6B;IAChD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACvE,OAAO,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC1C,CAAC;AAED,SAAS,iBAAiB,CAAC,GAA6B,EAAE,GAAQ;IAChE,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAChD,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3B,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,QAAQ,GAAG,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,kBAAkB,CAAC,GAA6B;IACvD,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;AACjC,CAAC;AAED,SAAS,eAAe,CAAC,GAA6B,EAAE,GAAQ;IAC9D,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,IAAI,GAAG,QAAQ;QACnB,CAAC,CAAC,GAAG,CAAC,QAAQ,KAAK,QAAQ;YACzB,CAAC,CAAC,GAAG;YACL,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;QACvC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC;IACjB,OAAO,GAAG,IAAI,IAAI,GAAG,GAAG,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;AAClD,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAmB;IAChD,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACxB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IAC/C,OAAO,CACL,KAAK,KAAK,aAAa;QACvB,KAAK,CAAC,UAAU,CAAC,cAAc,CAAC;QAChC,KAAK,KAAK,QAAQ;QAClB,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,CAC5B,CAAC;AACJ,CAAC;AAED,SAAS,oBAAoB,CAAC,GAA6B,EAAE,IAAY;IACvE,IAAI,GAAG,CAAC,EAAE,KAAK,eAAe,IAAI,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,KAAK,CACb,SAAS,IAAI,oFAAoF,CAClG,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CACtB,KAAsB,EACtB,QAAsC;IAEtC,OAAO;QACL,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,OAAO,EAAE,uBAAuB,CAAC,KAAK,CAAC,EAAE,EAAE,QAAQ,CAAC;KACrD,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB;IAIvC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC3C,+BAA+B,EAAE;QACjC,cAAc,CAAC,UAAU,CAAC;KAC3B,CAAC,CAAC;IACH,OAAO;QACL,QAAQ;QACR,IAAI,EAAE;YACJ,eAAe,CAAC,QAAQ,CAAC;YACzB,GAAG,MAAM;iBACN,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,eAAe,CAAC;iBAC/D,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;SACpD;KACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAG9C,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,mBAAmB,EAAE,CAAC;IAC7C,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,GAAW;IAEX,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IAChD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,mBAAmB,EAAE,CAAC;IAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CACrB,CAAC,SAAS,EAAE,EAAE,CACZ,SAAS,CAAC,EAAE,KAAK,MAAM,IAAI,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,MAAM,CACrE,CAAC;IACF,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,gBAAgB,GAAG,+DAA+D,CACnF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CACb,2BAA2B,KAAK,CAAC,EAAE,oEAAoE,CACxG,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,GAAW,EACX,OAAe;IAEf,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IACtC,IAAI,CAAC,cAAc;QAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAG,MAAM,4BAA4B,CAAC,GAAG,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,mBAAmB,EAAE,CAAC;IACxC,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAEzD,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;IAChC,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC,GAAG,KAAK;QAClC,CAAC,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC;YAChB,YAAY,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;YACrC,eAAe,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;SACzC,CAAC;QACJ,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAEjB,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,GAAG,EAAE,cAAc,EAAE;QAC3D,SAAS;QACT,SAAS,EAAE,SAAS,IAAI,SAAS;QACjC,SAAS,EAAE,SAAS,IAAI,SAAS;QACjC,SAAS,EAAE,CAAC,GAAG,MAAM;KACtB,CAAC,CAAC;IACH,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AACxD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,KAO/C;IAQC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACtC,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC;IACxC,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,YAAY,IAAI,CAAC,IAAI,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC5D,CAAC;IACD,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACtE,MAAM,MAAM,GAAG,MAAM,4BAA4B,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7D,IAAI,IAAI;QAAE,oBAAoB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,IAAI;QACjB,CAAC,CAAC,kBAAkB,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC;QACxC,CAAC,CAAC,aAAa,CAAC;YACZ,GAAG,EAAE,MAAM,CAAC,EAAE;YACd,IAAI;YACJ,MAAM,EAAE,KAAK,CAAC,MAAM;SACrB,CAAC,CAAC;IACP,OAAO;QACL,GAAG,EAAE,MAAM,CAAC,EAAE;QACd,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzB,GAAG,EAAE,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE;QACrC,GAAG,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChD,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAClD,CAAC;AACJ,CAAC;AAED,SAAS,sBAAsB,CAAC,MAAe;IAC7C,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QACzC,MAAM,UAAU,GAAI,MAAc,CAAC,iBAAiB,CAAC;QACrD,IAAI,UAAU,IAAI,OAAO,UAAU,KAAK,QAAQ;YAAE,OAAO,UAAU,CAAC;QACpE,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAE,MAAc,CAAC,OAAO,CAAC;YAClD,CAAC,CAAG,MAAc,CAAC,OAA0C;YAC7D,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CACrB,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CACjE,EAAE,IAAI,CAAC;QACR,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;YAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;gBAAE,OAAO,MAAM,CAAC;QAC1D,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;AACjE,CAAC;AAED,KAAK,UAAU,0BAA0B,CAAC,KAIzC;IACC,MAAM,WAAW,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE;QACnC,CAAC,CAAC,MAAM,4BAA4B,CAAC,KAAK,CAAC,GAAG,CAAC;QAC/C,CAAC,CAAC,IAAI,CAAC;IACT,IAAI,WAAW,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QACrE,oBAAoB,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QACxC,OAAO;YACL,GAAG,EAAE,WAAW;YAChB,IAAI;YACJ,GAAG,EAAE,GAAG,UAAU,CAAC,WAAW,CAAC,GAAG,IAAI,EAAE;SACzC,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IAED,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAC7D,CAAC;QACD,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;QAC5D,OAAO;YACL,GAAG,EAAE,WAAW;YAChB,IAAI;YACJ,GAAG,EAAE,GAAG,UAAU,CAAC,WAAW,CAAC,GAAG,IAAI,EAAE;SACzC,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,0BAA0B,EAAE,CAAC;IAC9E,MAAM,MAAM,GAAG,IAAI;SAChB,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,iBAAiB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;SAC/C,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACpE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,2DAA2D,CAC5D,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,WAAW,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1D,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IAC1D,oBAAoB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACnC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC;AACpE,CAAC;AAED,KAAK,UAAU,8BAA8B,CAAC,KAM7C;IAMC,MAAM,MAAM,GAAG,MAAM,wBAAwB,CAAC;QAC5C,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,UAAU,EAAE,KAAK,CAAC,IAAI;QACtB,KAAK,EAAE,KAAK,CAAC,MAAM,IAAI,IAAI;KAC5B,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,mBAAmB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACrD,OAAO;QACL,QAAQ,EAAE,IAAI,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE;QACtD,UAAU,EAAE,KAAK,CAAC,IAAI;QACtB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,GAAG,EAAE,eAAe;KACrB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oCAAoC,CAAC,KAK1D;IAMC,MAAM,SAAS,GAAG,mBAAmB,EAAE,CAAC;IACxC,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IACzD,MAAM,MAAM,GAAG,MAAM,0BAA0B,CAAC,KAAK,CAAC,CAAC;IAEvD,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;IAChC,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,eAAe,EAAE,CAAC;QACtC,OAAO,8BAA8B,CAAC;YACpC,UAAU,EAAE,SAAS;YACrB,KAAK;YACL,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,OAAO,EAAE,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC;YAC/B,MAAM,EAAE,KAAK,CAAC,MAAM;SACrB,CAAC,CAAC;IACL,CAAC;IAED,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC,GAAG,KAAK;QAClC,CAAC,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC;YAChB,YAAY,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;YACrC,eAAe,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;SACzC,CAAC;QACJ,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACjB,MAAM,KAAK,GAAG,MAAM,YAAY,CAC9B,SAAS,EACT,SAAS,IAAI,SAAS,EACtB,SAAS,IAAI,SAAS,EACtB;QACE,SAAS,EAAE,IAAI;QACf,kBAAkB,EAAE,CAAC,SAAS;KAC/B,CACF,CAAC;IAEF,MAAM,QAAQ,GAAG,QAAQ,CAAC;IAC1B,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAAC;QACnC,OAAO,EAAE;YACP,CAAC,QAAQ,CAAC,EAAE;gBACV,IAAI,EAAE,MAAM;gBACZ,GAAG,EAAE,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,oBAAoB;gBAClD,OAAO,EAAE;oBACP,aAAa,EAAE,UAAU,KAAK,EAAE;iBACjC;aACF;SACF;KACF,CAAC,CAAC;IACH,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACtB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,CACnC,gBAAgB,CAAC,QAAQ,EAAE,sBAAsB,CAAC,EAClD;YACE,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,MAAM;SAC/B,CACF,CAAC;QACF,MAAM,MAAM,GAAG,sBAAsB,CAAC,MAAM,CAI3C,CAAC;QACF,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACnE,CAAC;QACD,MAAM,MAAM,GAKR;YACF,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE;SACnB,CAAC;QACF,IAAI,MAAM,CAAC,UAAU;YAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;QAC7D,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ;YACtC,MAAM,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QACtC,OAAO,MAAM,CAAC;IAChB,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;IACvB,CAAC;AACH,CAAC","sourcesContent":["import { callAgent, signA2AToken } from \"@agent-native/core/a2a\";\nimport {\n buildMcpToolName,\n McpClientManager,\n} from \"@agent-native/core/mcp-client\";\nimport {\n buildDeepLink,\n buildEmbedStartPath,\n createEmbedSessionTicket,\n getRequestContext,\n} from \"@agent-native/core/server\";\nimport {\n discoverAgents,\n type DiscoveredAgent,\n} from \"@agent-native/core/server/agent-discovery\";\nimport {\n getRequestOrgId,\n getRequestUserEmail,\n} from \"@agent-native/core/server\";\nimport { getOrgA2ASecret, getOrgDomain } from \"@agent-native/core/org\";\nimport {\n getDispatchMcpAppAccessSettings,\n isAppAllowedByMcpAccess,\n type DispatchMcpAppAccessSettings,\n} from \"./mcp-access-store.js\";\n\nconst DISPATCH_APP_ID = \"dispatch\";\nconst DISPATCH_NAME = \"Agent-Native Dispatch\";\nconst DISPATCH_DESCRIPTION =\n \"Workspace control plane for extensions, agents, vault, integrations, approvals, and app routing.\";\nconst DISPATCH_COLOR = \"#14B8A6\";\n\nexport interface DispatchMcpAccessibleApp {\n id: string;\n name: string;\n description: string;\n url: string;\n color: string;\n granted: boolean;\n}\n\nfunction normalizeAppId(value: string): string {\n return value.trim().toLowerCase();\n}\n\nfunction normalizeBaseUrl(raw: string | undefined | null): string | null {\n const value = raw?.trim();\n if (!value) return null;\n try {\n const url = new URL(value);\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") return null;\n return url.toString().replace(/\\/+$/, \"\");\n } catch {\n return null;\n }\n}\n\nfunction normalizeBasePath(value: string | undefined): string {\n const trimmed = value?.trim();\n if (!trimmed || trimmed === \"/\") return \"\";\n const normalized = trimmed.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n return normalized ? `/${normalized}` : \"\";\n}\n\nfunction withConfiguredBasePath(baseUrl: string): string {\n const basePath = normalizeBasePath(\n process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH,\n );\n if (!basePath) return baseUrl;\n try {\n const url = new URL(baseUrl);\n const path = normalizeBasePath(url.pathname);\n if (path === basePath || path.startsWith(`${basePath}/`)) {\n return baseUrl;\n }\n url.pathname = path && path !== \"/\" ? `${basePath}${path}` : `${basePath}/`;\n return url.toString().replace(/\\/+$/, \"\");\n } catch {\n return baseUrl;\n }\n}\n\nfunction dispatchSelfBaseUrl(): string {\n const requestOrigin = normalizeBaseUrl(getRequestContext()?.requestOrigin);\n if (requestOrigin) return withConfiguredBasePath(requestOrigin);\n\n const configured =\n normalizeBaseUrl(process.env.WORKSPACE_GATEWAY_URL) ??\n normalizeBaseUrl(process.env.APP_URL) ??\n normalizeBaseUrl(process.env.URL) ??\n normalizeBaseUrl(process.env.DEPLOY_URL) ??\n normalizeBaseUrl(process.env.BETTER_AUTH_URL);\n if (configured) return withConfiguredBasePath(configured);\n\n return process.env.NODE_ENV === \"production\"\n ? \"https://dispatch.agent-native.com\"\n : \"http://localhost:8092\";\n}\n\nfunction dispatchSelfApp(\n settings: DispatchMcpAppAccessSettings,\n): DispatchMcpAccessibleApp {\n return {\n id: DISPATCH_APP_ID,\n name: DISPATCH_NAME,\n description: DISPATCH_DESCRIPTION,\n url: dispatchSelfBaseUrl(),\n color: DISPATCH_COLOR,\n granted: isAppAllowedByMcpAccess(DISPATCH_APP_ID, settings),\n };\n}\n\nconst CONTROL_CHARS = new RegExp(\"[\\\\u0000-\\\\u001f\\\\u007f]\");\n\nfunction safeAppPath(raw: unknown): string | null {\n if (typeof raw !== \"string\" || !raw.trim()) return null;\n const value = raw.trim();\n if (CONTROL_CHARS.test(value)) return null;\n if (!value.startsWith(\"/\")) return null;\n if (value.startsWith(\"//\") || value.startsWith(\"/\\\\\")) return null;\n if (/^\\/[a-z][a-z0-9+.-]*:/i.test(value)) return null;\n if (/%(?:2f|5c)/i.test(value)) return null;\n const rawPath = value.split(/[?#]/, 1)[0] ?? value;\n let parsed: URL;\n try {\n parsed = new URL(value, \"http://agent-native.invalid\");\n } catch {\n return null;\n }\n if (parsed.pathname !== rawPath) return null;\n return value;\n}\n\nfunction appendParamsToPath(\n path: string,\n params: Record<string, string | number | boolean> | undefined,\n): string {\n if (!params || Object.keys(params).length === 0) return path;\n const url = new URL(path, \"http://agent-native.invalid\");\n for (const [key, value] of Object.entries(params)) {\n url.searchParams.set(key, String(value));\n }\n return `${url.pathname}${url.search}${url.hash}`;\n}\n\nfunction appOrigin(app: DispatchMcpAccessibleApp): string {\n return new URL(app.url).origin;\n}\n\nfunction appBaseUrl(app: DispatchMcpAccessibleApp): string {\n return app.url.replace(/\\/+$/, \"\");\n}\n\nfunction appBasePath(app: DispatchMcpAccessibleApp): string {\n const pathname = new URL(appBaseUrl(app)).pathname.replace(/\\/+$/, \"\");\n return pathname === \"/\" ? \"\" : pathname;\n}\n\nfunction appMatchesUrlPath(app: DispatchMcpAccessibleApp, url: URL): boolean {\n if (url.origin !== appOrigin(app)) return false;\n const basePath = appBasePath(app);\n if (!basePath) return true;\n return url.pathname === basePath || url.pathname.startsWith(`${basePath}/`);\n}\n\nfunction appPathSpecificity(app: DispatchMcpAccessibleApp): number {\n return appBasePath(app).length;\n}\n\nfunction appRelativePath(app: DispatchMcpAccessibleApp, url: URL): string {\n const basePath = appBasePath(app);\n const path = basePath\n ? url.pathname === basePath\n ? \"/\"\n : url.pathname.slice(basePath.length)\n : url.pathname;\n return `${path || \"/\"}${url.search}${url.hash}`;\n}\n\nfunction isDispatchControlPath(path: string | null): boolean {\n if (!path) return false;\n const route = path.split(/[?#]/, 1)[0] ?? path;\n return (\n route === \"/extensions\" ||\n route.startsWith(\"/extensions/\") ||\n route === \"/tools\" ||\n route.startsWith(\"/tools/\")\n );\n}\n\nfunction assertAppCanOpenPath(app: DispatchMcpAccessibleApp, path: string) {\n if (app.id !== DISPATCH_APP_ID && isDispatchControlPath(path)) {\n throw new Error(\n `Path \"${path}\" belongs to Dispatch. Use app: \"dispatch\" for Dispatch extension and tool routes.`,\n );\n }\n}\n\nfunction toAccessibleApp(\n agent: DiscoveredAgent,\n settings: DispatchMcpAppAccessSettings,\n): DispatchMcpAccessibleApp {\n return {\n id: agent.id,\n name: agent.name,\n description: agent.description,\n url: agent.url,\n color: agent.color,\n granted: isAppAllowedByMcpAccess(agent.id, settings),\n };\n}\n\nexport async function listDispatchMcpApps(): Promise<{\n settings: DispatchMcpAppAccessSettings;\n apps: DispatchMcpAccessibleApp[];\n}> {\n const [settings, agents] = await Promise.all([\n getDispatchMcpAppAccessSettings(),\n discoverAgents(\"dispatch\"),\n ]);\n return {\n settings,\n apps: [\n dispatchSelfApp(settings),\n ...agents\n .filter((agent) => normalizeAppId(agent.id) !== DISPATCH_APP_ID)\n .map((agent) => toAccessibleApp(agent, settings)),\n ],\n };\n}\n\nexport async function listGrantedDispatchMcpApps(): Promise<\n DispatchMcpAccessibleApp[]\n> {\n const { apps } = await listDispatchMcpApps();\n return apps.filter((app) => app.granted);\n}\n\nexport async function resolveGrantedDispatchMcpApp(\n app: string,\n): Promise<DispatchMcpAccessibleApp> {\n const target = normalizeAppId(app);\n if (!target) throw new Error(\"app is required\");\n const { apps } = await listDispatchMcpApps();\n const match = apps.find(\n (candidate) =>\n candidate.id === target || candidate.name.toLowerCase() === target,\n );\n if (!match) {\n throw new Error(\n `Unknown app \"${app}\". Call list_apps to see apps available through Dispatch MCP.`,\n );\n }\n if (!match.granted) {\n throw new Error(\n `Dispatch MCP access to \"${match.id}\" is not granted. Open Dispatch > Agents to change MCP app access.`,\n );\n }\n return match;\n}\n\nexport async function askGrantedDispatchMcpApp(\n app: string,\n message: string,\n): Promise<{ app: string; routedVia: \"a2a\"; response: string }> {\n const trimmedMessage = message.trim();\n if (!trimmedMessage) throw new Error(\"message is required\");\n const target = await resolveGrantedDispatchMcpApp(app);\n const userEmail = getRequestUserEmail();\n if (!userEmail) throw new Error(\"no authenticated user\");\n\n const orgId = getRequestOrgId();\n const [orgDomain, orgSecret] = orgId\n ? await Promise.all([\n getOrgDomain(orgId).catch(() => null),\n getOrgA2ASecret(orgId).catch(() => null),\n ])\n : [null, null];\n\n const response = await callAgent(target.url, trimmedMessage, {\n userEmail,\n orgDomain: orgDomain ?? undefined,\n orgSecret: orgSecret ?? undefined,\n timeoutMs: 5 * 60_000,\n });\n return { app: target.id, routedVia: \"a2a\", response };\n}\n\nexport async function openGrantedDispatchMcpApp(input: {\n app: string;\n view?: string;\n path?: string;\n params?: Record<string, string | number | boolean>;\n embed?: boolean;\n chrome?: \"full\" | \"minimal\";\n}): Promise<{\n app: string;\n view?: string;\n path?: string;\n url: string;\n embed?: boolean;\n chrome?: \"full\" | \"minimal\";\n}> {\n const view = input.view?.trim() ?? \"\";\n const hasPathInput = input.path != null;\n const path = safeAppPath(input.path);\n if (hasPathInput && !path) {\n throw new Error(\"path must be a safe app-relative route\");\n }\n if (!view && !path) throw new Error(\"open_app requires view or path\");\n const target = await resolveGrantedDispatchMcpApp(input.app);\n if (path) assertAppCanOpenPath(target, path);\n const relUrl = path\n ? appendParamsToPath(path, input.params)\n : buildDeepLink({\n app: target.id,\n view,\n params: input.params,\n });\n return {\n app: target.id,\n ...(view ? { view } : {}),\n ...(path ? { path } : {}),\n url: `${appBaseUrl(target)}${relUrl}`,\n ...(input.embed === true ? { embed: true } : {}),\n ...(input.chrome ? { chrome: input.chrome } : {}),\n };\n}\n\nfunction parseMcpToolTextResult(result: unknown): Record<string, unknown> {\n if (result && typeof result === \"object\") {\n const structured = (result as any).structuredContent;\n if (structured && typeof structured === \"object\") return structured;\n const parts = Array.isArray((result as any).content)\n ? ((result as any).content as Array<Record<string, unknown>>)\n : [];\n const text = parts.find(\n (part) => part?.type === \"text\" && typeof part.text === \"string\",\n )?.text;\n if (typeof text === \"string\" && text.trim()) {\n const parsed = JSON.parse(text);\n if (parsed && typeof parsed === \"object\") return parsed;\n }\n }\n throw new Error(\"Target app did not return an embed session.\");\n}\n\nasync function resolveDispatchEmbedTarget(input: {\n app?: string;\n url?: string;\n path?: string;\n}): Promise<{ app: DispatchMcpAccessibleApp; path: string; url: string }> {\n const explicitApp = input.app?.trim()\n ? await resolveGrantedDispatchMcpApp(input.app)\n : null;\n if (explicitApp && input.path) {\n const path = safeAppPath(input.path);\n if (!path) throw new Error(\"path must be a safe app-relative route\");\n assertAppCanOpenPath(explicitApp, path);\n return {\n app: explicitApp,\n path,\n url: `${appBaseUrl(explicitApp)}${path}`,\n };\n }\n\n if (!input.url) {\n throw new Error(\"create_embed_session requires a url or app + path.\");\n }\n\n let parsed: URL;\n try {\n parsed = new URL(input.url);\n } catch {\n if (!explicitApp) {\n throw new Error(\"Relative embed paths require an app id.\");\n }\n const path = safeAppPath(input.url);\n if (!path) throw new Error(\"url must be a safe app route.\");\n return {\n app: explicitApp,\n path,\n url: `${appBaseUrl(explicitApp)}${path}`,\n };\n }\n\n const apps = explicitApp ? [explicitApp] : await listGrantedDispatchMcpApps();\n const target = apps\n .filter((app) => appMatchesUrlPath(app, parsed))\n .sort((a, b) => appPathSpecificity(b) - appPathSpecificity(a))[0];\n if (!target) {\n throw new Error(\n \"Embed URL must belong to an app granted through Dispatch.\",\n );\n }\n const path = safeAppPath(appRelativePath(target, parsed));\n if (!path) throw new Error(\"Embed URL path is not safe.\");\n assertAppCanOpenPath(target, path);\n return { app: target, path, url: `${appBaseUrl(target)}${path}` };\n}\n\nasync function createDispatchSelfEmbedSession(input: {\n ownerEmail: string;\n orgId?: string;\n path: string;\n baseUrl: string;\n chrome?: \"full\" | \"minimal\";\n}): Promise<{\n startUrl: string;\n targetPath?: string;\n expiresAt?: number;\n app: string;\n}> {\n const ticket = await createEmbedSessionTicket({\n ownerEmail: input.ownerEmail,\n orgId: input.orgId,\n targetPath: input.path,\n scope: input.chrome ?? null,\n });\n const startPath = buildEmbedStartPath(ticket.ticket);\n return {\n startUrl: new URL(startPath, input.baseUrl).toString(),\n targetPath: input.path,\n expiresAt: ticket.expiresAt,\n app: DISPATCH_APP_ID,\n };\n}\n\nexport async function createGrantedDispatchMcpEmbedSession(input: {\n app?: string;\n url?: string;\n path?: string;\n chrome?: \"full\" | \"minimal\";\n}): Promise<{\n startUrl: string;\n targetPath?: string;\n expiresAt?: number;\n app: string;\n}> {\n const userEmail = getRequestUserEmail();\n if (!userEmail) throw new Error(\"no authenticated user\");\n const target = await resolveDispatchEmbedTarget(input);\n\n const orgId = getRequestOrgId();\n if (target.app.id === DISPATCH_APP_ID) {\n return createDispatchSelfEmbedSession({\n ownerEmail: userEmail,\n orgId,\n path: target.path,\n baseUrl: appBaseUrl(target.app),\n chrome: input.chrome,\n });\n }\n\n const [orgDomain, orgSecret] = orgId\n ? await Promise.all([\n getOrgDomain(orgId).catch(() => null),\n getOrgA2ASecret(orgId).catch(() => null),\n ])\n : [null, null];\n const token = await signA2AToken(\n userEmail,\n orgDomain ?? undefined,\n orgSecret ?? undefined,\n {\n expiresIn: \"5m\",\n preferGlobalSecret: !orgSecret,\n },\n );\n\n const serverId = \"target\";\n const manager = new McpClientManager({\n servers: {\n [serverId]: {\n type: \"http\",\n url: `${appBaseUrl(target.app)}/_agent-native/mcp`,\n headers: {\n Authorization: `Bearer ${token}`,\n },\n },\n },\n });\n await manager.start();\n try {\n const result = await manager.callTool(\n buildMcpToolName(serverId, \"create_embed_session\"),\n {\n url: target.url,\n chrome: input.chrome ?? \"full\",\n },\n );\n const parsed = parseMcpToolTextResult(result) as {\n startUrl?: string;\n targetPath?: string;\n expiresAt?: number;\n };\n if (!parsed.startUrl) {\n throw new Error(\"Target app did not return an embed start URL.\");\n }\n const output: {\n startUrl: string;\n targetPath?: string;\n expiresAt?: number;\n app: string;\n } = {\n startUrl: parsed.startUrl,\n app: target.app.id,\n };\n if (parsed.targetPath) output.targetPath = parsed.targetPath;\n if (typeof parsed.expiresAt === \"number\")\n output.expiresAt = parsed.expiresAt;\n return output;\n } finally {\n await manager.stop();\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage-metrics-store.d.ts","sourceRoot":"","sources":["../../../src/server/lib/usage-metrics-store.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"usage-metrics-store.d.ts","sourceRoot":"","sources":["../../../src/server/lib/usage-metrics-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage-metrics-store.js","sourceRoot":"","sources":["../../../src/server/lib/usage-metrics-store.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getUsageSummary,\n usageBillingForEngine,\n type UsageBillingMode,\n} from \"@agent-native/core/usage\";\nimport { getDbExec } from \"@agent-native/core/db\";\nimport {\n detectEngineFromEnv,\n detectEngineFromUserSecrets,\n getAgentEngineEntry,\n isAgentEngineSettingConfigured,\n isStoredEngineUsable,\n registerBuiltinEngines,\n} from \"@agent-native/core/agent/engine\";\nimport { getSetting } from \"@agent-native/core/settings\";\nimport { currentOrgId, currentOwnerEmail } from \"./dispatch-store.js\";\nimport {\n listWorkspaceApps,\n type WorkspaceAppSummary,\n} from \"./app-creation-store.js\";\n\nconst DAY_MS = 86_400_000;\n\nregisterBuiltinEngines();\n\nexport interface UsageMetricBucket {\n key: string;\n label: string;\n costCents: number;\n calls: number;\n chatCalls: number;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheWriteTokens: number;\n activeUsers: number;\n lastActiveAt: number | null;\n}\n\nexport interface UserUsageMetric extends UsageMetricBucket {\n ownerEmail: string;\n chatThreads: number;\n chatMessages: number;\n lastChatAt: number | null;\n topApp: string | null;\n role: string | null;\n}\n\nexport interface AppAccessMetric {\n id: string;\n name: string;\n path: string;\n status: WorkspaceAppSummary[\"status\"];\n isDispatch: boolean;\n accessModel: \"workspace\" | \"solo\";\n accessLabel: string;\n accessUsers: number;\n usersWithUsage: number;\n usageCalls: number;\n chatCalls: number;\n costCents: number;\n lastActiveAt: number | null;\n}\n\nexport interface DailyUsageMetric {\n date: string;\n costCents: number;\n calls: number;\n chatCalls: number;\n activeUsers: number;\n}\n\nexport interface RecentUsageMetric {\n id: number;\n createdAt: number;\n ownerEmail: string;\n app: string;\n label: string;\n model: string;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheWriteTokens: number;\n costCents: number;\n}\n\nexport interface DispatchUsageMetrics {\n billing: UsageBillingMode;\n sinceMs: number;\n sinceDays: number;\n generatedAt: number;\n access: {\n viewerEmail: string;\n orgId: string | null;\n role: string | null;\n scope: \"organization\" | \"solo\";\n totalUsers: number;\n };\n totals: {\n costCents: number;\n calls: number;\n chatCalls: number;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheWriteTokens: number;\n activeUsers: number;\n chatThreads: number;\n chatMessages: number;\n workspaceApps: number;\n };\n byApp: UsageMetricBucket[];\n byUser: UserUsageMetric[];\n byLabel: UsageMetricBucket[];\n byModel: UsageMetricBucket[];\n daily: DailyUsageMetric[];\n appAccess: AppAccessMetric[];\n recent: RecentUsageMetric[];\n}\n\ninterface MemberRecord {\n email: string;\n role: string | null;\n joinedAt: number | null;\n}\n\ninterface ChatStats {\n threads: number;\n messages: number;\n lastChatAt: number | null;\n}\n\nfunction numberField(row: Record<string, unknown>, key: string): number {\n return Number(row[key] ?? 0) || 0;\n}\n\nfunction stringField(row: Record<string, unknown>, key: string): string {\n return String(row[key] ?? \"\");\n}\n\nfunction nullableNumberField(\n row: Record<string, unknown>,\n key: string,\n): number | null {\n const value = row[key];\n if (value == null) return null;\n const numberValue = Number(value);\n return Number.isFinite(numberValue) ? numberValue : null;\n}\n\nfunction labelForKey(value: string): string {\n const trimmed = value.trim();\n return trimmed || \"Unattributed\";\n}\n\nfunction normalizeAppKey(value: string | null | undefined): string {\n const raw = (value ?? \"\").trim().toLowerCase();\n if (!raw) return \"unattributed\";\n return raw.replace(/^agent-native-/, \"\");\n}\n\nfunction envEmails(name: string): string[] {\n return (process.env[name] ?? \"\")\n .split(\",\")\n .map((value) => value.trim().toLowerCase())\n .filter(Boolean);\n}\n\nfunction isEnvAdmin(email: string): boolean {\n const normalized = email.trim().toLowerCase();\n return [\n ...envEmails(\"DISPATCH_ADMIN_EMAILS\"),\n ...envEmails(\"WORKSPACE_OWNER_EMAIL\"),\n ...envEmails(\"DISPATCH_DEFAULT_OWNER_EMAIL\"),\n ].includes(normalized);\n}\n\nasync function detectUsageEngineName(): Promise<string | null> {\n try {\n const stored = (await getSetting(\"agent-engine\")) as {\n engine?: string;\n } | null;\n if (isAgentEngineSettingConfigured(stored)) {\n return (stored as { engine: string }).engine;\n }\n if (stored && typeof stored.engine === \"string\") {\n const entry = getAgentEngineEntry(stored.engine);\n if (entry && isStoredEngineUsable(stored, entry)) {\n return stored.engine;\n }\n }\n\n const detectedFromUser = await detectEngineFromUserSecrets();\n if (detectedFromUser) return detectedFromUser.name;\n\n return detectEngineFromEnv()?.name ?? null;\n } catch {\n return null;\n }\n}\n\nasync function queryRows<T extends Record<string, unknown>>(\n sql: string,\n args: unknown[] = [],\n): Promise<T[]> {\n try {\n const result = await getDbExec().execute({ sql, args });\n return result.rows as T[];\n } catch {\n return [];\n }\n}\n\nasync function getViewerOrgRole(\n orgId: string | null,\n email: string,\n): Promise<string | null> {\n if (!orgId) return null;\n const rows = await queryRows<{ role?: string }>(\n `SELECT role FROM org_members WHERE org_id = ? AND LOWER(email) = ? LIMIT 1`,\n [orgId, email.toLowerCase()],\n );\n const role = rows[0]?.role;\n return typeof role === \"string\" ? role : null;\n}\n\nasync function listOrgMembers(orgId: string | null): Promise<MemberRecord[]> {\n if (!orgId) return [];\n const rows = await queryRows<Record<string, unknown>>(\n `SELECT email, role, joined_at AS joined_at FROM org_members WHERE org_id = ? ORDER BY joined_at ASC`,\n [orgId],\n );\n return rows\n .map((row) => ({\n email: stringField(row, \"email\").trim(),\n role: stringField(row, \"role\") || null,\n joinedAt: nullableNumberField(row, \"joined_at\"),\n }))\n .filter((member) => member.email);\n}\n\nasync function listSignedInUsers(): Promise<MemberRecord[]> {\n const authRows = await queryRows<Record<string, unknown>>(\n `SELECT email, created_at AS joined_at FROM \"user\" ORDER BY created_at ASC`,\n );\n if (authRows.length > 0) {\n return authRows\n .map((row) => ({\n email: stringField(row, \"email\").trim(),\n role: null,\n joinedAt: nullableNumberField(row, \"joined_at\"),\n }))\n .filter((member) => member.email);\n }\n\n const usageRows = await queryRows<{ email?: string }>(\n `SELECT DISTINCT owner_email AS email FROM token_usage`,\n );\n const threadRows = await queryRows<{ email?: string }>(\n `SELECT DISTINCT owner_email AS email FROM chat_threads`,\n );\n const emails = new Set<string>();\n for (const row of [...usageRows, ...threadRows]) {\n if (row.email) emails.add(row.email);\n }\n return [...emails].sort().map((email) => ({\n email,\n role: null,\n joinedAt: null,\n }));\n}\n\nfunction usageScope(\n sinceMs: number,\n memberEmails: string[],\n): { where: string; args: unknown[] } {\n if (memberEmails.length === 0) {\n return { where: \"created_at >= ?\", args: [sinceMs] };\n }\n const placeholders = memberEmails.map(() => \"?\").join(\", \");\n return {\n where: `created_at >= ? AND owner_email IN (${placeholders})`,\n args: [sinceMs, ...memberEmails],\n };\n}\n\nfunction threadScope(\n sinceMs: number,\n memberEmails: string[],\n): { where: string; args: unknown[] } {\n if (memberEmails.length === 0) {\n return { where: \"updated_at >= ?\", args: [sinceMs] };\n }\n const placeholders = memberEmails.map(() => \"?\").join(\", \");\n return {\n where: `updated_at >= ? AND owner_email IN (${placeholders})`,\n args: [sinceMs, ...memberEmails],\n };\n}\n\nfunction bucketFromRow(row: Record<string, unknown>): UsageMetricBucket {\n const key = stringField(row, \"k\");\n return {\n key,\n label: labelForKey(key),\n costCents: numberField(row, \"cost_x100\") / 100,\n calls: numberField(row, \"calls\"),\n chatCalls: numberField(row, \"chat_calls\"),\n inputTokens: numberField(row, \"input_tokens\"),\n outputTokens: numberField(row, \"output_tokens\"),\n cacheReadTokens: numberField(row, \"cache_read_tokens\"),\n cacheWriteTokens: numberField(row, \"cache_write_tokens\"),\n activeUsers: numberField(row, \"active_users\"),\n lastActiveAt: nullableNumberField(row, \"last_active_at\"),\n };\n}\n\nasync function usageBuckets(\n columnExpression: string,\n where: string,\n args: unknown[],\n limit: number,\n): Promise<UsageMetricBucket[]> {\n const rows = await queryRows<Record<string, unknown>>(\n `SELECT ${columnExpression} AS k,\n COALESCE(SUM(cost_cents_x100), 0) AS cost_x100,\n COUNT(*) AS calls,\n SUM(CASE WHEN label = 'chat' THEN 1 ELSE 0 END) AS chat_calls,\n COALESCE(SUM(input_tokens), 0) AS input_tokens,\n COALESCE(SUM(output_tokens), 0) AS output_tokens,\n COALESCE(SUM(cache_read_tokens), 0) AS cache_read_tokens,\n COALESCE(SUM(cache_write_tokens), 0) AS cache_write_tokens,\n COUNT(DISTINCT owner_email) AS active_users,\n MAX(created_at) AS last_active_at\n FROM token_usage\n WHERE ${where}\n GROUP BY ${columnExpression}\n ORDER BY cost_x100 DESC\n LIMIT ?`,\n [...args, limit],\n );\n return rows.map(bucketFromRow);\n}\n\nasync function loadChatStats(\n where: string,\n args: unknown[],\n): Promise<Map<string, ChatStats>> {\n const rows = await queryRows<Record<string, unknown>>(\n `SELECT owner_email AS owner_email,\n COUNT(*) AS threads,\n COALESCE(SUM(message_count), 0) AS messages,\n MAX(updated_at) AS last_chat_at\n FROM chat_threads\n WHERE ${where}\n GROUP BY owner_email`,\n args,\n );\n return new Map(\n rows.map((row) => [\n stringField(row, \"owner_email\"),\n {\n threads: numberField(row, \"threads\"),\n messages: numberField(row, \"messages\"),\n lastChatAt: nullableNumberField(row, \"last_chat_at\"),\n },\n ]),\n );\n}\n\nasync function assertCanViewMetrics(): Promise<{\n viewerEmail: string;\n orgId: string | null;\n role: string | null;\n}> {\n const viewerEmail = currentOwnerEmail();\n const orgId = currentOrgId();\n const role = await getViewerOrgRole(orgId, viewerEmail);\n if (isEnvAdmin(viewerEmail) || role === \"owner\" || role === \"admin\") {\n return { viewerEmail, orgId, role };\n }\n if (!orgId) {\n return { viewerEmail, orgId, role };\n }\n throw new Error(\n \"Only organization owners and admins can view workspace usage metrics.\",\n );\n}\n\nexport async function listDispatchUsageMetrics(input: {\n sinceDays?: number;\n}): Promise<DispatchUsageMetrics> {\n const { viewerEmail, orgId, role } = await assertCanViewMetrics();\n const sinceDays = Math.max(1, Math.min(365, input.sinceDays ?? 30));\n const sinceMs = Date.now() - sinceDays * DAY_MS;\n const billing = usageBillingForEngine(await detectUsageEngineName());\n\n // Initializes token_usage on fresh deployments before the read-only\n // aggregate queries below. The fake owner avoids changing visible data.\n await getUsageSummary({ ownerEmail: \"__dispatch_metrics_init__\", sinceMs });\n\n const rawMembers = orgId\n ? await listOrgMembers(orgId)\n : await listSignedInUsers();\n const members =\n orgId && rawMembers.length === 0\n ? [{ email: viewerEmail, role, joinedAt: null }]\n : rawMembers;\n const memberEmails = orgId ? members.map((member) => member.email) : [];\n const memberByEmail = new Map(\n members.map((member) => [member.email.toLowerCase(), member]),\n );\n const usage = usageScope(sinceMs, memberEmails);\n const threads = threadScope(sinceMs, memberEmails);\n\n const [apps, totalsRows, byApp, byUserBase, byLabel, byModel, chatStats] =\n await Promise.all([\n listWorkspaceApps({ includeAgentCards: false }),\n queryRows<Record<string, unknown>>(\n `SELECT\n COALESCE(SUM(cost_cents_x100), 0) AS cost_x100,\n COUNT(*) AS calls,\n SUM(CASE WHEN label = 'chat' THEN 1 ELSE 0 END) AS chat_calls,\n COALESCE(SUM(input_tokens), 0) AS input_tokens,\n COALESCE(SUM(output_tokens), 0) AS output_tokens,\n COALESCE(SUM(cache_read_tokens), 0) AS cache_read_tokens,\n COALESCE(SUM(cache_write_tokens), 0) AS cache_write_tokens,\n COUNT(DISTINCT owner_email) AS active_users\n FROM token_usage\n WHERE ${usage.where}`,\n usage.args,\n ),\n usageBuckets(\n `COALESCE(NULLIF(app, ''), 'unattributed')`,\n usage.where,\n usage.args,\n 20,\n ),\n usageBuckets(\"owner_email\", usage.where, usage.args, 50),\n usageBuckets(\n `COALESCE(NULLIF(label, ''), 'chat')`,\n usage.where,\n usage.args,\n 20,\n ),\n usageBuckets(\n `COALESCE(NULLIF(model, ''), 'unknown')`,\n usage.where,\n usage.args,\n 20,\n ),\n loadChatStats(threads.where, threads.args),\n ]);\n\n const topAppRows = await queryRows<Record<string, unknown>>(\n `SELECT owner_email AS owner_email,\n COALESCE(NULLIF(app, ''), 'unattributed') AS app,\n COALESCE(SUM(cost_cents_x100), 0) AS cost_x100\n FROM token_usage\n WHERE ${usage.where}\n GROUP BY owner_email, COALESCE(NULLIF(app, ''), 'unattributed')\n ORDER BY owner_email ASC, cost_x100 DESC`,\n usage.args,\n );\n const topAppByUser = new Map<string, string>();\n for (const row of topAppRows) {\n const email = stringField(row, \"owner_email\");\n if (!topAppByUser.has(email)) {\n topAppByUser.set(email, stringField(row, \"app\"));\n }\n }\n\n const byUserMap = new Map<string, UserUsageMetric>();\n for (const bucket of byUserBase) {\n const ownerEmail = bucket.key;\n const stats = chatStats.get(ownerEmail) ?? {\n threads: 0,\n messages: 0,\n lastChatAt: null,\n };\n const member = memberByEmail.get(ownerEmail.toLowerCase());\n byUserMap.set(ownerEmail, {\n ...bucket,\n ownerEmail,\n chatThreads: stats.threads,\n chatMessages: stats.messages,\n lastChatAt: stats.lastChatAt,\n topApp: topAppByUser.get(ownerEmail) ?? null,\n role: member?.role ?? null,\n });\n }\n for (const [ownerEmail, stats] of chatStats) {\n if (byUserMap.has(ownerEmail)) continue;\n const member = memberByEmail.get(ownerEmail.toLowerCase());\n byUserMap.set(ownerEmail, {\n key: ownerEmail,\n label: ownerEmail,\n ownerEmail,\n costCents: 0,\n calls: 0,\n chatCalls: 0,\n inputTokens: 0,\n outputTokens: 0,\n cacheReadTokens: 0,\n cacheWriteTokens: 0,\n activeUsers: 1,\n lastActiveAt: stats.lastChatAt,\n chatThreads: stats.threads,\n chatMessages: stats.messages,\n lastChatAt: stats.lastChatAt,\n topApp: null,\n role: member?.role ?? null,\n });\n }\n\n const dayRows = await queryRows<Record<string, unknown>>(\n `SELECT created_at, owner_email, label, cost_cents_x100\n FROM token_usage\n WHERE ${usage.where}\n ORDER BY created_at ASC`,\n usage.args,\n );\n const dailyMap = new Map<\n string,\n { costX100: number; calls: number; chatCalls: number; users: Set<string> }\n >();\n for (const row of dayRows) {\n const date = new Date(numberField(row, \"created_at\"))\n .toISOString()\n .slice(0, 10);\n const current = dailyMap.get(date) ?? {\n costX100: 0,\n calls: 0,\n chatCalls: 0,\n users: new Set<string>(),\n };\n current.costX100 += numberField(row, \"cost_cents_x100\");\n current.calls += 1;\n if (stringField(row, \"label\") === \"chat\") current.chatCalls += 1;\n current.users.add(stringField(row, \"owner_email\"));\n dailyMap.set(date, current);\n }\n const daily = [...dailyMap.entries()]\n .map(([date, value]) => ({\n date,\n costCents: value.costX100 / 100,\n calls: value.calls,\n chatCalls: value.chatCalls,\n activeUsers: value.users.size,\n }))\n .sort((a, b) => a.date.localeCompare(b.date));\n\n const recentRows = await queryRows<Record<string, unknown>>(\n `SELECT id, created_at, owner_email, app, label, model,\n input_tokens, output_tokens, cache_read_tokens, cache_write_tokens,\n cost_cents_x100\n FROM token_usage\n WHERE ${usage.where}\n ORDER BY created_at DESC\n LIMIT 50`,\n usage.args,\n );\n const recent = recentRows.map((row) => ({\n id: numberField(row, \"id\"),\n createdAt: numberField(row, \"created_at\"),\n ownerEmail: stringField(row, \"owner_email\"),\n app: stringField(row, \"app\") || \"unattributed\",\n label: stringField(row, \"label\") || \"chat\",\n model: stringField(row, \"model\") || \"unknown\",\n inputTokens: numberField(row, \"input_tokens\"),\n outputTokens: numberField(row, \"output_tokens\"),\n cacheReadTokens: numberField(row, \"cache_read_tokens\"),\n cacheWriteTokens: numberField(row, \"cache_write_tokens\"),\n costCents: numberField(row, \"cost_cents_x100\") / 100,\n }));\n\n const appUsageByKey = new Map(\n byApp.map((bucket) => [normalizeAppKey(bucket.key), bucket]),\n );\n const accessUsers = members.length || byUserMap.size;\n const accessModel = orgId ? \"workspace\" : \"solo\";\n const accessLabel = orgId ? \"Workspace members\" : \"Signed-in users\";\n const appAccess = apps.map((app) => {\n const usageBucket = appUsageByKey.get(normalizeAppKey(app.id));\n return {\n id: app.id,\n name: app.name,\n path: app.path,\n status: app.status,\n isDispatch: app.isDispatch,\n accessModel,\n accessLabel,\n accessUsers,\n usersWithUsage: usageBucket?.activeUsers ?? 0,\n usageCalls: usageBucket?.calls ?? 0,\n chatCalls: usageBucket?.chatCalls ?? 0,\n costCents: usageBucket?.costCents ?? 0,\n lastActiveAt: usageBucket?.lastActiveAt ?? null,\n } satisfies AppAccessMetric;\n });\n\n const totals = totalsRows[0] ?? {};\n const chatThreadTotals = [...chatStats.values()].reduce(\n (acc, value) => ({\n threads: acc.threads + value.threads,\n messages: acc.messages + value.messages,\n }),\n { threads: 0, messages: 0 },\n );\n\n return {\n billing,\n sinceMs,\n sinceDays,\n generatedAt: Date.now(),\n access: {\n viewerEmail,\n orgId,\n role,\n scope: orgId ? \"organization\" : \"solo\",\n totalUsers: accessUsers,\n },\n totals: {\n costCents: numberField(totals, \"cost_x100\") / 100,\n calls: numberField(totals, \"calls\"),\n chatCalls: numberField(totals, \"chat_calls\"),\n inputTokens: numberField(totals, \"input_tokens\"),\n outputTokens: numberField(totals, \"output_tokens\"),\n cacheReadTokens: numberField(totals, \"cache_read_tokens\"),\n cacheWriteTokens: numberField(totals, \"cache_write_tokens\"),\n activeUsers: numberField(totals, \"active_users\"),\n chatThreads: chatThreadTotals.threads,\n chatMessages: chatThreadTotals.messages,\n workspaceApps: apps.filter((app) => !app.isDispatch).length,\n },\n byApp,\n byUser: [...byUserMap.values()].sort((a, b) => {\n if (b.costCents !== a.costCents) return b.costCents - a.costCents;\n return (b.lastActiveAt ?? 0) - (a.lastActiveAt ?? 0);\n }),\n byLabel,\n byModel,\n daily,\n appAccess,\n recent,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"usage-metrics-store.js","sourceRoot":"","sources":["../../../src/server/lib/usage-metrics-store.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getUsageSummary,\n usageBillingForEngine,\n type UsageBillingMode,\n} from \"@agent-native/core/usage\";\nimport { getDbExec } from \"@agent-native/core/db\";\nimport {\n detectEngineFromEnv,\n detectEngineFromUserSecrets,\n getAgentEngineEntry,\n isAgentEngineSettingConfigured,\n isStoredEngineUsable,\n registerBuiltinEngines,\n} from \"@agent-native/core/agent/engine\";\nimport { getSetting } from \"@agent-native/core/settings\";\nimport { currentOrgId, currentOwnerEmail } from \"./dispatch-store.js\";\nimport {\n listWorkspaceApps,\n type WorkspaceAppSummary,\n} from \"./app-creation-store.js\";\n\nconst DAY_MS = 86_400_000;\n\nregisterBuiltinEngines();\n\nexport interface UsageMetricBucket {\n key: string;\n label: string;\n costCents: number;\n calls: number;\n chatCalls: number;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheWriteTokens: number;\n activeUsers: number;\n lastActiveAt: number | null;\n}\n\nexport interface UserUsageMetric extends UsageMetricBucket {\n ownerEmail: string;\n chatThreads: number;\n chatMessages: number;\n lastChatAt: number | null;\n topApp: string | null;\n role: string | null;\n}\n\nexport interface AppAccessMetric {\n id: string;\n name: string;\n path: string;\n status: WorkspaceAppSummary[\"status\"];\n statusLabel?: string;\n isDispatch: boolean;\n accessModel: \"workspace\" | \"solo\";\n accessLabel: string;\n accessUsers: number;\n usersWithUsage: number;\n usageCalls: number;\n chatCalls: number;\n costCents: number;\n lastActiveAt: number | null;\n}\n\nexport interface DailyUsageMetric {\n date: string;\n costCents: number;\n calls: number;\n chatCalls: number;\n activeUsers: number;\n}\n\nexport interface RecentUsageMetric {\n id: number;\n createdAt: number;\n ownerEmail: string;\n app: string;\n label: string;\n model: string;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheWriteTokens: number;\n costCents: number;\n}\n\nexport interface DispatchUsageMetrics {\n billing: UsageBillingMode;\n sinceMs: number;\n sinceDays: number;\n generatedAt: number;\n access: {\n viewerEmail: string;\n orgId: string | null;\n role: string | null;\n scope: \"organization\" | \"solo\";\n totalUsers: number;\n };\n totals: {\n costCents: number;\n calls: number;\n chatCalls: number;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheWriteTokens: number;\n activeUsers: number;\n chatThreads: number;\n chatMessages: number;\n workspaceApps: number;\n };\n byApp: UsageMetricBucket[];\n byUser: UserUsageMetric[];\n byLabel: UsageMetricBucket[];\n byModel: UsageMetricBucket[];\n daily: DailyUsageMetric[];\n appAccess: AppAccessMetric[];\n recent: RecentUsageMetric[];\n}\n\ninterface MemberRecord {\n email: string;\n role: string | null;\n joinedAt: number | null;\n}\n\ninterface ChatStats {\n threads: number;\n messages: number;\n lastChatAt: number | null;\n}\n\nfunction numberField(row: Record<string, unknown>, key: string): number {\n return Number(row[key] ?? 0) || 0;\n}\n\nfunction stringField(row: Record<string, unknown>, key: string): string {\n return String(row[key] ?? \"\");\n}\n\nfunction nullableNumberField(\n row: Record<string, unknown>,\n key: string,\n): number | null {\n const value = row[key];\n if (value == null) return null;\n const numberValue = Number(value);\n return Number.isFinite(numberValue) ? numberValue : null;\n}\n\nfunction labelForKey(value: string): string {\n const trimmed = value.trim();\n return trimmed || \"Unattributed\";\n}\n\nfunction normalizeAppKey(value: string | null | undefined): string {\n const raw = (value ?? \"\").trim().toLowerCase();\n if (!raw) return \"unattributed\";\n return raw.replace(/^agent-native-/, \"\");\n}\n\nfunction envEmails(name: string): string[] {\n return (process.env[name] ?? \"\")\n .split(\",\")\n .map((value) => value.trim().toLowerCase())\n .filter(Boolean);\n}\n\nfunction isEnvAdmin(email: string): boolean {\n const normalized = email.trim().toLowerCase();\n return [\n ...envEmails(\"DISPATCH_ADMIN_EMAILS\"),\n ...envEmails(\"WORKSPACE_OWNER_EMAIL\"),\n ...envEmails(\"DISPATCH_DEFAULT_OWNER_EMAIL\"),\n ].includes(normalized);\n}\n\nasync function detectUsageEngineName(): Promise<string | null> {\n try {\n const stored = (await getSetting(\"agent-engine\")) as {\n engine?: string;\n } | null;\n if (isAgentEngineSettingConfigured(stored)) {\n return (stored as { engine: string }).engine;\n }\n if (stored && typeof stored.engine === \"string\") {\n const entry = getAgentEngineEntry(stored.engine);\n if (entry && isStoredEngineUsable(stored, entry)) {\n return stored.engine;\n }\n }\n\n const detectedFromUser = await detectEngineFromUserSecrets();\n if (detectedFromUser) return detectedFromUser.name;\n\n return detectEngineFromEnv()?.name ?? null;\n } catch {\n return null;\n }\n}\n\nasync function queryRows<T extends Record<string, unknown>>(\n sql: string,\n args: unknown[] = [],\n): Promise<T[]> {\n try {\n const result = await getDbExec().execute({ sql, args });\n return result.rows as T[];\n } catch {\n return [];\n }\n}\n\nasync function getViewerOrgRole(\n orgId: string | null,\n email: string,\n): Promise<string | null> {\n if (!orgId) return null;\n const rows = await queryRows<{ role?: string }>(\n `SELECT role FROM org_members WHERE org_id = ? AND LOWER(email) = ? LIMIT 1`,\n [orgId, email.toLowerCase()],\n );\n const role = rows[0]?.role;\n return typeof role === \"string\" ? role : null;\n}\n\nasync function listOrgMembers(orgId: string | null): Promise<MemberRecord[]> {\n if (!orgId) return [];\n const rows = await queryRows<Record<string, unknown>>(\n `SELECT email, role, joined_at AS joined_at FROM org_members WHERE org_id = ? ORDER BY joined_at ASC`,\n [orgId],\n );\n return rows\n .map((row) => ({\n email: stringField(row, \"email\").trim(),\n role: stringField(row, \"role\") || null,\n joinedAt: nullableNumberField(row, \"joined_at\"),\n }))\n .filter((member) => member.email);\n}\n\nasync function listSignedInUsers(): Promise<MemberRecord[]> {\n const authRows = await queryRows<Record<string, unknown>>(\n `SELECT email, created_at AS joined_at FROM \"user\" ORDER BY created_at ASC`,\n );\n if (authRows.length > 0) {\n return authRows\n .map((row) => ({\n email: stringField(row, \"email\").trim(),\n role: null,\n joinedAt: nullableNumberField(row, \"joined_at\"),\n }))\n .filter((member) => member.email);\n }\n\n const usageRows = await queryRows<{ email?: string }>(\n `SELECT DISTINCT owner_email AS email FROM token_usage`,\n );\n const threadRows = await queryRows<{ email?: string }>(\n `SELECT DISTINCT owner_email AS email FROM chat_threads`,\n );\n const emails = new Set<string>();\n for (const row of [...usageRows, ...threadRows]) {\n if (row.email) emails.add(row.email);\n }\n return [...emails].sort().map((email) => ({\n email,\n role: null,\n joinedAt: null,\n }));\n}\n\nfunction usageScope(\n sinceMs: number,\n memberEmails: string[],\n): { where: string; args: unknown[] } {\n if (memberEmails.length === 0) {\n return { where: \"created_at >= ?\", args: [sinceMs] };\n }\n const placeholders = memberEmails.map(() => \"?\").join(\", \");\n return {\n where: `created_at >= ? AND owner_email IN (${placeholders})`,\n args: [sinceMs, ...memberEmails],\n };\n}\n\nfunction threadScope(\n sinceMs: number,\n memberEmails: string[],\n): { where: string; args: unknown[] } {\n if (memberEmails.length === 0) {\n return { where: \"updated_at >= ?\", args: [sinceMs] };\n }\n const placeholders = memberEmails.map(() => \"?\").join(\", \");\n return {\n where: `updated_at >= ? AND owner_email IN (${placeholders})`,\n args: [sinceMs, ...memberEmails],\n };\n}\n\nfunction bucketFromRow(row: Record<string, unknown>): UsageMetricBucket {\n const key = stringField(row, \"k\");\n return {\n key,\n label: labelForKey(key),\n costCents: numberField(row, \"cost_x100\") / 100,\n calls: numberField(row, \"calls\"),\n chatCalls: numberField(row, \"chat_calls\"),\n inputTokens: numberField(row, \"input_tokens\"),\n outputTokens: numberField(row, \"output_tokens\"),\n cacheReadTokens: numberField(row, \"cache_read_tokens\"),\n cacheWriteTokens: numberField(row, \"cache_write_tokens\"),\n activeUsers: numberField(row, \"active_users\"),\n lastActiveAt: nullableNumberField(row, \"last_active_at\"),\n };\n}\n\nasync function usageBuckets(\n columnExpression: string,\n where: string,\n args: unknown[],\n limit: number,\n): Promise<UsageMetricBucket[]> {\n const rows = await queryRows<Record<string, unknown>>(\n `SELECT ${columnExpression} AS k,\n COALESCE(SUM(cost_cents_x100), 0) AS cost_x100,\n COUNT(*) AS calls,\n SUM(CASE WHEN label = 'chat' THEN 1 ELSE 0 END) AS chat_calls,\n COALESCE(SUM(input_tokens), 0) AS input_tokens,\n COALESCE(SUM(output_tokens), 0) AS output_tokens,\n COALESCE(SUM(cache_read_tokens), 0) AS cache_read_tokens,\n COALESCE(SUM(cache_write_tokens), 0) AS cache_write_tokens,\n COUNT(DISTINCT owner_email) AS active_users,\n MAX(created_at) AS last_active_at\n FROM token_usage\n WHERE ${where}\n GROUP BY ${columnExpression}\n ORDER BY cost_x100 DESC\n LIMIT ?`,\n [...args, limit],\n );\n return rows.map(bucketFromRow);\n}\n\nasync function loadChatStats(\n where: string,\n args: unknown[],\n): Promise<Map<string, ChatStats>> {\n const rows = await queryRows<Record<string, unknown>>(\n `SELECT owner_email AS owner_email,\n COUNT(*) AS threads,\n COALESCE(SUM(message_count), 0) AS messages,\n MAX(updated_at) AS last_chat_at\n FROM chat_threads\n WHERE ${where}\n GROUP BY owner_email`,\n args,\n );\n return new Map(\n rows.map((row) => [\n stringField(row, \"owner_email\"),\n {\n threads: numberField(row, \"threads\"),\n messages: numberField(row, \"messages\"),\n lastChatAt: nullableNumberField(row, \"last_chat_at\"),\n },\n ]),\n );\n}\n\nasync function assertCanViewMetrics(): Promise<{\n viewerEmail: string;\n orgId: string | null;\n role: string | null;\n}> {\n const viewerEmail = currentOwnerEmail();\n const orgId = currentOrgId();\n const role = await getViewerOrgRole(orgId, viewerEmail);\n if (isEnvAdmin(viewerEmail) || role === \"owner\" || role === \"admin\") {\n return { viewerEmail, orgId, role };\n }\n if (!orgId) {\n return { viewerEmail, orgId, role };\n }\n throw new Error(\n \"Only organization owners and admins can view workspace usage metrics.\",\n );\n}\n\nexport async function listDispatchUsageMetrics(input: {\n sinceDays?: number;\n}): Promise<DispatchUsageMetrics> {\n const { viewerEmail, orgId, role } = await assertCanViewMetrics();\n const sinceDays = Math.max(1, Math.min(365, input.sinceDays ?? 30));\n const sinceMs = Date.now() - sinceDays * DAY_MS;\n const billing = usageBillingForEngine(await detectUsageEngineName());\n\n // Initializes token_usage on fresh deployments before the read-only\n // aggregate queries below. The fake owner avoids changing visible data.\n await getUsageSummary({ ownerEmail: \"__dispatch_metrics_init__\", sinceMs });\n\n const rawMembers = orgId\n ? await listOrgMembers(orgId)\n : await listSignedInUsers();\n const members =\n orgId && rawMembers.length === 0\n ? [{ email: viewerEmail, role, joinedAt: null }]\n : rawMembers;\n const memberEmails = orgId ? members.map((member) => member.email) : [];\n const memberByEmail = new Map(\n members.map((member) => [member.email.toLowerCase(), member]),\n );\n const usage = usageScope(sinceMs, memberEmails);\n const threads = threadScope(sinceMs, memberEmails);\n\n const [apps, totalsRows, byApp, byUserBase, byLabel, byModel, chatStats] =\n await Promise.all([\n listWorkspaceApps({ includeAgentCards: false }),\n queryRows<Record<string, unknown>>(\n `SELECT\n COALESCE(SUM(cost_cents_x100), 0) AS cost_x100,\n COUNT(*) AS calls,\n SUM(CASE WHEN label = 'chat' THEN 1 ELSE 0 END) AS chat_calls,\n COALESCE(SUM(input_tokens), 0) AS input_tokens,\n COALESCE(SUM(output_tokens), 0) AS output_tokens,\n COALESCE(SUM(cache_read_tokens), 0) AS cache_read_tokens,\n COALESCE(SUM(cache_write_tokens), 0) AS cache_write_tokens,\n COUNT(DISTINCT owner_email) AS active_users\n FROM token_usage\n WHERE ${usage.where}`,\n usage.args,\n ),\n usageBuckets(\n `COALESCE(NULLIF(app, ''), 'unattributed')`,\n usage.where,\n usage.args,\n 20,\n ),\n usageBuckets(\"owner_email\", usage.where, usage.args, 50),\n usageBuckets(\n `COALESCE(NULLIF(label, ''), 'chat')`,\n usage.where,\n usage.args,\n 20,\n ),\n usageBuckets(\n `COALESCE(NULLIF(model, ''), 'unknown')`,\n usage.where,\n usage.args,\n 20,\n ),\n loadChatStats(threads.where, threads.args),\n ]);\n\n const topAppRows = await queryRows<Record<string, unknown>>(\n `SELECT owner_email AS owner_email,\n COALESCE(NULLIF(app, ''), 'unattributed') AS app,\n COALESCE(SUM(cost_cents_x100), 0) AS cost_x100\n FROM token_usage\n WHERE ${usage.where}\n GROUP BY owner_email, COALESCE(NULLIF(app, ''), 'unattributed')\n ORDER BY owner_email ASC, cost_x100 DESC`,\n usage.args,\n );\n const topAppByUser = new Map<string, string>();\n for (const row of topAppRows) {\n const email = stringField(row, \"owner_email\");\n if (!topAppByUser.has(email)) {\n topAppByUser.set(email, stringField(row, \"app\"));\n }\n }\n\n const byUserMap = new Map<string, UserUsageMetric>();\n for (const bucket of byUserBase) {\n const ownerEmail = bucket.key;\n const stats = chatStats.get(ownerEmail) ?? {\n threads: 0,\n messages: 0,\n lastChatAt: null,\n };\n const member = memberByEmail.get(ownerEmail.toLowerCase());\n byUserMap.set(ownerEmail, {\n ...bucket,\n ownerEmail,\n chatThreads: stats.threads,\n chatMessages: stats.messages,\n lastChatAt: stats.lastChatAt,\n topApp: topAppByUser.get(ownerEmail) ?? null,\n role: member?.role ?? null,\n });\n }\n for (const [ownerEmail, stats] of chatStats) {\n if (byUserMap.has(ownerEmail)) continue;\n const member = memberByEmail.get(ownerEmail.toLowerCase());\n byUserMap.set(ownerEmail, {\n key: ownerEmail,\n label: ownerEmail,\n ownerEmail,\n costCents: 0,\n calls: 0,\n chatCalls: 0,\n inputTokens: 0,\n outputTokens: 0,\n cacheReadTokens: 0,\n cacheWriteTokens: 0,\n activeUsers: 1,\n lastActiveAt: stats.lastChatAt,\n chatThreads: stats.threads,\n chatMessages: stats.messages,\n lastChatAt: stats.lastChatAt,\n topApp: null,\n role: member?.role ?? null,\n });\n }\n\n const dayRows = await queryRows<Record<string, unknown>>(\n `SELECT created_at, owner_email, label, cost_cents_x100\n FROM token_usage\n WHERE ${usage.where}\n ORDER BY created_at ASC`,\n usage.args,\n );\n const dailyMap = new Map<\n string,\n { costX100: number; calls: number; chatCalls: number; users: Set<string> }\n >();\n for (const row of dayRows) {\n const date = new Date(numberField(row, \"created_at\"))\n .toISOString()\n .slice(0, 10);\n const current = dailyMap.get(date) ?? {\n costX100: 0,\n calls: 0,\n chatCalls: 0,\n users: new Set<string>(),\n };\n current.costX100 += numberField(row, \"cost_cents_x100\");\n current.calls += 1;\n if (stringField(row, \"label\") === \"chat\") current.chatCalls += 1;\n current.users.add(stringField(row, \"owner_email\"));\n dailyMap.set(date, current);\n }\n const daily = [...dailyMap.entries()]\n .map(([date, value]) => ({\n date,\n costCents: value.costX100 / 100,\n calls: value.calls,\n chatCalls: value.chatCalls,\n activeUsers: value.users.size,\n }))\n .sort((a, b) => a.date.localeCompare(b.date));\n\n const recentRows = await queryRows<Record<string, unknown>>(\n `SELECT id, created_at, owner_email, app, label, model,\n input_tokens, output_tokens, cache_read_tokens, cache_write_tokens,\n cost_cents_x100\n FROM token_usage\n WHERE ${usage.where}\n ORDER BY created_at DESC\n LIMIT 50`,\n usage.args,\n );\n const recent = recentRows.map((row) => ({\n id: numberField(row, \"id\"),\n createdAt: numberField(row, \"created_at\"),\n ownerEmail: stringField(row, \"owner_email\"),\n app: stringField(row, \"app\") || \"unattributed\",\n label: stringField(row, \"label\") || \"chat\",\n model: stringField(row, \"model\") || \"unknown\",\n inputTokens: numberField(row, \"input_tokens\"),\n outputTokens: numberField(row, \"output_tokens\"),\n cacheReadTokens: numberField(row, \"cache_read_tokens\"),\n cacheWriteTokens: numberField(row, \"cache_write_tokens\"),\n costCents: numberField(row, \"cost_cents_x100\") / 100,\n }));\n\n const appUsageByKey = new Map(\n byApp.map((bucket) => [normalizeAppKey(bucket.key), bucket]),\n );\n const accessUsers = members.length || byUserMap.size;\n const accessModel = orgId ? \"workspace\" : \"solo\";\n const accessLabel = orgId ? \"Workspace members\" : \"Signed-in users\";\n const appAccess = apps.map((app) => {\n const usageBucket = appUsageByKey.get(normalizeAppKey(app.id));\n return {\n id: app.id,\n name: app.name,\n path: app.path,\n status: app.status,\n statusLabel: app.statusLabel,\n isDispatch: app.isDispatch,\n accessModel,\n accessLabel,\n accessUsers,\n usersWithUsage: usageBucket?.activeUsers ?? 0,\n usageCalls: usageBucket?.calls ?? 0,\n chatCalls: usageBucket?.chatCalls ?? 0,\n costCents: usageBucket?.costCents ?? 0,\n lastActiveAt: usageBucket?.lastActiveAt ?? null,\n } satisfies AppAccessMetric;\n });\n\n const totals = totalsRows[0] ?? {};\n const chatThreadTotals = [...chatStats.values()].reduce(\n (acc, value) => ({\n threads: acc.threads + value.threads,\n messages: acc.messages + value.messages,\n }),\n { threads: 0, messages: 0 },\n );\n\n return {\n billing,\n sinceMs,\n sinceDays,\n generatedAt: Date.now(),\n access: {\n viewerEmail,\n orgId,\n role,\n scope: orgId ? \"organization\" : \"solo\",\n totalUsers: accessUsers,\n },\n totals: {\n costCents: numberField(totals, \"cost_x100\") / 100,\n calls: numberField(totals, \"calls\"),\n chatCalls: numberField(totals, \"chat_calls\"),\n inputTokens: numberField(totals, \"input_tokens\"),\n outputTokens: numberField(totals, \"output_tokens\"),\n cacheReadTokens: numberField(totals, \"cache_read_tokens\"),\n cacheWriteTokens: numberField(totals, \"cache_write_tokens\"),\n activeUsers: numberField(totals, \"active_users\"),\n chatThreads: chatThreadTotals.threads,\n chatMessages: chatThreadTotals.messages,\n workspaceApps: apps.filter((app) => !app.isDispatch).length,\n },\n byApp,\n byUser: [...byUserMap.values()].sort((a, b) => {\n if (b.costCents !== a.costCents) return b.costCents - a.costCents;\n return (b.lastActiveAt ?? 0) - (a.lastActiveAt ?? 0);\n }),\n byLabel,\n byModel,\n daily,\n appAccess,\n recent,\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/dispatch",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"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.",
|
|
6
6
|
"license": "MIT",
|
package/src/actions/list_apps.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { listGrantedDispatchMcpApps } from "../server/lib/mcp-gateway.js";
|
|
|
4
4
|
|
|
5
5
|
export default defineAction({
|
|
6
6
|
description:
|
|
7
|
-
|
|
7
|
+
'List the apps this Dispatch MCP gateway can route to, including "dispatch" itself for Dispatch-owned pages such as extensions. The result is filtered by Dispatch\'s MCP app access policy.',
|
|
8
8
|
schema: z.object({}),
|
|
9
9
|
http: { method: "GET" },
|
|
10
10
|
readOnly: true,
|
package/src/actions/open_app.ts
CHANGED
|
@@ -5,13 +5,17 @@ import { openGrantedDispatchMcpApp } from "../server/lib/mcp-gateway.js";
|
|
|
5
5
|
const deepLinkParam = z.union([z.string(), z.number(), z.boolean()]);
|
|
6
6
|
const openAppSchema = z
|
|
7
7
|
.object({
|
|
8
|
-
app: z
|
|
8
|
+
app: z
|
|
9
|
+
.string()
|
|
10
|
+
.describe(
|
|
11
|
+
'Granted app id, e.g. mail or calendar. Use "dispatch" for Dispatch-owned pages such as /extensions.',
|
|
12
|
+
),
|
|
9
13
|
view: z.string().optional().describe("Target view in the app, e.g. inbox."),
|
|
10
14
|
path: z
|
|
11
15
|
.string()
|
|
12
16
|
.optional()
|
|
13
17
|
.describe(
|
|
14
|
-
|
|
18
|
+
'Optional route within the target app, e.g. /adhoc/q2 or /chart?panel=... . Dispatch extension routes such as /extensions/<id>/<slug> belong to app "dispatch".',
|
|
15
19
|
),
|
|
16
20
|
params: z
|
|
17
21
|
.record(z.string(), deepLinkParam)
|
|
@@ -20,7 +24,9 @@ const openAppSchema = z
|
|
|
20
24
|
embed: z
|
|
21
25
|
.boolean()
|
|
22
26
|
.optional()
|
|
23
|
-
.describe(
|
|
27
|
+
.describe(
|
|
28
|
+
"Render the app or focused route/component inline in MCP Apps when supported.",
|
|
29
|
+
),
|
|
24
30
|
chrome: z
|
|
25
31
|
.enum(["full", "minimal"])
|
|
26
32
|
.optional()
|
|
@@ -33,7 +39,7 @@ const openAppSchema = z
|
|
|
33
39
|
|
|
34
40
|
export default defineAction({
|
|
35
41
|
description:
|
|
36
|
-
|
|
42
|
+
'Build a deep link or embeddable app route/component route for an app available through Dispatch MCP. Use app "dispatch" for Dispatch extension/tool pages. No side effects; surface the returned Open link to the user.',
|
|
37
43
|
schema: openAppSchema,
|
|
38
44
|
http: { method: "GET" },
|
|
39
45
|
readOnly: true,
|
|
@@ -56,6 +62,7 @@ export default defineAction({
|
|
|
56
62
|
iframeTitle: "Dispatch MCP app",
|
|
57
63
|
openLabel: "Open app",
|
|
58
64
|
frameDomains: ["https:", "http://localhost:*", "http://127.0.0.1:*"],
|
|
65
|
+
height: 900,
|
|
59
66
|
}),
|
|
60
67
|
},
|
|
61
68
|
});
|