@agent-native/core 0.206.0-nightly-20261009153146 → 0.206.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/action.d.ts +7 -1
- package/dist/client/agent-chat/index.d.ts +1 -1
- package/dist/client/agent-chat/index.js +1 -1
- package/dist/client/embed-auth.d.ts +2 -0
- package/dist/client/embed-auth.js +160 -12
- package/dist/client/host/index.d.ts +1 -1
- package/dist/client/host/index.js +1 -1
- package/dist/client/mcp-app-host.d.ts +1 -0
- package/dist/client/mcp-app-host.js +4 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/mcp/build-server.d.ts +15 -0
- package/dist/mcp/build-server.js +307 -91
- package/dist/mcp/connect-route.js +1 -0
- package/dist/mcp/embed-app.js +291 -31
- package/dist/mcp/oauth-route.js +3 -0
- package/dist/mcp/oauth-store.d.ts +2 -1
- package/dist/mcp/oauth-store.js +5 -6
- package/dist/mcp/oauth-token.d.ts +5 -0
- package/dist/mcp/oauth-token.js +17 -0
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/mcp/server.d.ts +2 -2
- package/dist/mcp/server.js +2 -2
- package/dist/observability/routes.d.ts +5 -5
- package/dist/org/handlers.d.ts +1 -1
- package/dist/org/workspace-app-access-request.d.ts +8 -0
- package/dist/org/workspace-app-access-request.js +20 -0
- package/dist/provider-api/actions/custom-provider-registration.d.ts +4 -4
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +11 -11
- package/dist/server/action-routes.d.ts +2 -0
- package/dist/server/action-routes.js +187 -31
- package/dist/server/agent-chat/mcp-options.d.ts +3 -1
- package/dist/server/agent-chat-plugin.js +26 -1
- package/dist/server/agent-engine-ollama-models-route.d.ts +2 -2
- package/dist/server/auth.js +11 -20
- package/dist/server/embed-route.js +5 -3
- package/dist/server/embed-session.d.ts +30 -1
- package/dist/server/embed-session.js +376 -30
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/request-context.d.ts +2 -0
- package/dist/server/request-context.js +25 -1
- package/dist/shared/embed-auth.d.ts +74 -0
- package/dist/shared/embed-auth.js +379 -10
- package/dist/sharing/actions/list-resource-shares.d.ts +1 -1
- package/dist/triggers/actions/manage-automation.d.ts +3 -3
- package/package.json +4 -4
package/dist/action.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { type ActionChatUIConfig } from "./action-ui.js";
|
|
|
3
3
|
import type { ActionTool, AgentChatAttachment, AgentChatEvent } from "./agent/types.js";
|
|
4
4
|
import type { ActionAuditConfig } from "./audit/types.js";
|
|
5
5
|
import { type ActionAccessConfig } from "./authorization/action-access-runtime.js";
|
|
6
|
-
export type ActionCaller = "tool" | "http" | "frontend" | "mcp-widget" | "cli" | "mcp" | "webmcp" | "a2a" | "automation";
|
|
6
|
+
export type ActionCaller = "tool" | "http" | "frontend" | "mcp-widget" | "mcp-widget-write" | "cli" | "mcp" | "webmcp" | "a2a" | "automation";
|
|
7
7
|
export interface ActionAutomationContext {
|
|
8
8
|
triggerId: string;
|
|
9
9
|
triggerName: string;
|
|
@@ -38,6 +38,12 @@ export interface ActionRunContext {
|
|
|
38
38
|
actionName?: string;
|
|
39
39
|
/** Present only on frontend GETs authorized by a scoped directory-widget read capability. */
|
|
40
40
|
mcpDirectoryWidgetReadOnly?: true;
|
|
41
|
+
/** Present only on frontend mutations authorized by a scoped directory-widget write capability. */
|
|
42
|
+
mcpDirectoryWidgetWrite?: {
|
|
43
|
+
appId: string;
|
|
44
|
+
resourceIds: Record<string, string>;
|
|
45
|
+
actionNames: readonly string[];
|
|
46
|
+
};
|
|
41
47
|
threadId?: string;
|
|
42
48
|
runId?: string;
|
|
43
49
|
turnId?: string;
|
|
@@ -13,7 +13,7 @@ export { useSendToAgentChat } from "../use-send-to-agent-chat.js";
|
|
|
13
13
|
export { DEFAULT_MODEL, CHAT_MODEL_SELECTION_CHANGED_EVENT, chatModelSelectionStorageKey, loadChatModelCatalog, useChatModels, type UseChatModelsResult, type UseChatModelsOptions, type PersistedModelSelection, type EngineModelGroup, } from "../use-chat-models.js";
|
|
14
14
|
export { fetchAgentEngineConfiguredState, useAgentEngineConfigured, type AgentEngineConfiguredState, type FetchAgentEngineConfiguredStateOptions, type UseAgentEngineConfiguredResult, } from "../use-agent-engine-configured.js";
|
|
15
15
|
export { AGENT_CHAT_AI_SETUP_REQUIRED_CODE, AgentChatAiSetupRequiredError, ensureAgentEngineReadiness, getAgentEngineReadiness, invalidateAgentEngineReadiness, isAgentChatAiSetupRequiredError, isLocalRuntimeEngine, requireAgentEngineConfiguredForDispatch, subscribeAgentEngineReadiness, LOCAL_RUNTIME_ENGINE_IDS, agentEngineStatusUrlForChatApi, type AgentEngineReadinessSource, } from "../agent-engine-readiness.js";
|
|
16
|
-
export { AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES, getMcpAppHostContext, initializeMcpAppHost, isMcpAppWidgetEmbed, isOpenAiMcpAppHost, openMcpAppHostLink, requestMcpAppDisplayMode, sendMcpAppHostMessage, updateMcpAppModelContext, useIsMcpAppWidgetEmbed, useMcpAppHostContext, type AgentNativeMcpAppHostMessageType, type McpAppDisplayMode, type McpAppHostChatMessage, type McpAppHostCapabilities, type McpAppHostContext, type McpAppHostInfo, type McpAppHostContextSnapshot, type McpAppModelContextContentPart, type McpAppModelContextUpdate, } from "../mcp-app-host.js";
|
|
16
|
+
export { AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES, getMcpAppHostContext, initializeMcpAppHost, isMcpAppWidgetEmbed, isOpenAiMcpAppHost, openMcpAppHostLink, requestMcpAppDisplayMode, sendMcpAppHostMessage, updateMcpAppModelContext, useIsMcpAppWidgetEmbed, useIsMcpDirectoryWidgetReadOnlyEmbed, useIsMcpDirectoryWidgetWriteEmbed, useMcpAppHostContext, type AgentNativeMcpAppHostMessageType, type McpAppDisplayMode, type McpAppHostChatMessage, type McpAppHostCapabilities, type McpAppHostContext, type McpAppHostInfo, type McpAppHostContextSnapshot, type McpAppModelContextContentPart, type McpAppModelContextUpdate, } from "../mcp-app-host.js";
|
|
17
17
|
export { buildDynamicAgentSuggestions, dedupeSuggestions, mergeAgentSuggestions, normalizeAgentDynamicSuggestionsConfig, useAgentDynamicSuggestions, useAgentDynamicSuggestionsResult, type AgentDynamicSuggestionContext, type AgentDynamicSuggestionsConfig, type AgentDynamicSuggestionsOption, } from "../dynamic-suggestions.js";
|
|
18
18
|
export { clearChatStorage } from "../chat/storage.js";
|
|
19
19
|
export { isAssistantChatHistoryVersion, coerceAssistantChatHistoryDate, type AssistantChatHistoryDate, type AssistantChatHistoryVersion, } from "../chat/assistant-chat-history-version.js";
|
|
@@ -13,7 +13,7 @@ export { useSendToAgentChat } from "../use-send-to-agent-chat.js";
|
|
|
13
13
|
export { DEFAULT_MODEL, CHAT_MODEL_SELECTION_CHANGED_EVENT, chatModelSelectionStorageKey, loadChatModelCatalog, useChatModels, } from "../use-chat-models.js";
|
|
14
14
|
export { fetchAgentEngineConfiguredState, useAgentEngineConfigured, } from "../use-agent-engine-configured.js";
|
|
15
15
|
export { AGENT_CHAT_AI_SETUP_REQUIRED_CODE, AgentChatAiSetupRequiredError, ensureAgentEngineReadiness, getAgentEngineReadiness, invalidateAgentEngineReadiness, isAgentChatAiSetupRequiredError, isLocalRuntimeEngine, requireAgentEngineConfiguredForDispatch, subscribeAgentEngineReadiness, LOCAL_RUNTIME_ENGINE_IDS, agentEngineStatusUrlForChatApi, } from "../agent-engine-readiness.js";
|
|
16
|
-
export { AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES, getMcpAppHostContext, initializeMcpAppHost, isMcpAppWidgetEmbed, isOpenAiMcpAppHost, openMcpAppHostLink, requestMcpAppDisplayMode, sendMcpAppHostMessage, updateMcpAppModelContext, useIsMcpAppWidgetEmbed, useMcpAppHostContext, } from "../mcp-app-host.js";
|
|
16
|
+
export { AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES, getMcpAppHostContext, initializeMcpAppHost, isMcpAppWidgetEmbed, isOpenAiMcpAppHost, openMcpAppHostLink, requestMcpAppDisplayMode, sendMcpAppHostMessage, updateMcpAppModelContext, useIsMcpAppWidgetEmbed, useIsMcpDirectoryWidgetReadOnlyEmbed, useIsMcpDirectoryWidgetWriteEmbed, useMcpAppHostContext, } from "../mcp-app-host.js";
|
|
17
17
|
export { buildDynamicAgentSuggestions, dedupeSuggestions, mergeAgentSuggestions, normalizeAgentDynamicSuggestionsConfig, useAgentDynamicSuggestions, useAgentDynamicSuggestionsResult, } from "../dynamic-suggestions.js";
|
|
18
18
|
export { clearChatStorage } from "../chat/storage.js";
|
|
19
19
|
export { isAssistantChatHistoryVersion, coerceAssistantChatHistoryDate, } from "../chat/assistant-chat-history-version.js";
|
|
@@ -11,12 +11,14 @@ export declare function getEmbedAuthToken(): string | null;
|
|
|
11
11
|
* allowed.
|
|
12
12
|
*/
|
|
13
13
|
export declare function hasMcpDirectoryWidgetCapabilityToken(): boolean;
|
|
14
|
+
export declare function hasMcpDirectoryWidgetWriteCapabilityToken(): boolean;
|
|
14
15
|
/**
|
|
15
16
|
* True when this document is the app nested in an MCP App widget shell (the
|
|
16
17
|
* chat bridge is active) on a directory-widget read capability, which the
|
|
17
18
|
* server limits to the widget's own resource reads.
|
|
18
19
|
*/
|
|
19
20
|
export declare function isMcpDirectoryWidgetReadOnlyEmbed(): boolean;
|
|
21
|
+
export declare function isMcpDirectoryWidgetWriteEmbed(): boolean;
|
|
20
22
|
export declare function isEmbedAuthActive(): boolean;
|
|
21
23
|
export declare function _resetEmbedAuthForTests(): void;
|
|
22
24
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { EMBED_MODE_QUERY_PARAM, EMBED_START_PATH, EMBED_TARGET_HEADER, EMBED_TARGET_QUERY_PARAM, EMBED_TOKEN_QUERY_PARAM, MCP_APP_CHAT_BRIDGE_QUERY_PARAM, } from "../shared/embed-auth.js";
|
|
2
|
-
import { isMcpDirectoryWidgetReadCapabilityScope } from "../shared/embed-auth.js";
|
|
1
|
+
import { EMBED_MODE_QUERY_PARAM, EMBED_START_PATH, EMBED_TARGET_HEADER, EMBED_TARGET_QUERY_PARAM, EMBED_TOKEN_QUERY_PARAM, MCP_APP_CHAT_BRIDGE_QUERY_PARAM, MCP_DIRECTORY_WIDGET_SESSION_EXPIRED_HEADER, } from "../shared/embed-auth.js";
|
|
2
|
+
import { isMcpDirectoryWidgetReadCapabilityScope, isMcpDirectoryWidgetWriteCapabilityScope, } from "../shared/embed-auth.js";
|
|
3
3
|
import { FRAMEWORK_INTERNAL_ROUTE_PREFIX } from "../shared/framework-route-prefix.js";
|
|
4
4
|
import { MCP_APP_HOST_FILL_ATTRIBUTE } from "../shared/mcp-app-display.js";
|
|
5
5
|
import { EMBED_TOKEN_STORAGE_KEY, MCP_CHAT_BRIDGE_STORAGE_KEY, } from "../shared/mcp-app-widget-embed.js";
|
|
@@ -7,11 +7,16 @@ import { SIGN_IN_ENTRY_PATH, SIGN_IN_LEGACY_ENTRY_PATH, } from "../shared/sign-i
|
|
|
7
7
|
import { frameworkRoutePrefix } from "./api-path.js";
|
|
8
8
|
let installed = false;
|
|
9
9
|
let memoryToken = null;
|
|
10
|
+
let renewedFromUrlToken = null;
|
|
11
|
+
let pendingWidgetSessionRenewal = null;
|
|
12
|
+
let widgetSessionRenewalRequestId = 0;
|
|
10
13
|
let mcpChatBridgeActive = false;
|
|
11
14
|
let mcpChatBridgeScope = null;
|
|
12
15
|
const AUTH_FAILURE_COOLDOWN_MS = 60_000;
|
|
13
16
|
const GUARDED_METHODS = new Set(["GET", "HEAD"]);
|
|
14
17
|
const AUTH_FAILURE_HEADER = "x-agent-native-auth-circuit-breaker";
|
|
18
|
+
const EMBED_TOKEN_RENEWED_FROM_STORAGE_KEY = `${EMBED_TOKEN_STORAGE_KEY}:renewed-from`;
|
|
19
|
+
const EMBED_SESSION_RENEWAL_TIMEOUT_MS = 15_000;
|
|
15
20
|
const MCP_CHAT_BRIDGE_VIEWPORT_STYLE_ID = "agent-native-mcp-chat-bridge-viewport";
|
|
16
21
|
const MCP_CHAT_BRIDGE_VIEWPORT_HEIGHT = 560;
|
|
17
22
|
let pendingMcpChatBridgeViewportNotification = null;
|
|
@@ -43,7 +48,7 @@ export function readEmbedMcpChatBridgeFlagFromUrl() {
|
|
|
43
48
|
return value === "1" || value === "true";
|
|
44
49
|
}
|
|
45
50
|
function currentMcpChatBridgeScope(win) {
|
|
46
|
-
return
|
|
51
|
+
return getEmbedAuthToken() ?? memoryToken ?? storedToken(win);
|
|
47
52
|
}
|
|
48
53
|
function clearMcpChatBridge(win) {
|
|
49
54
|
mcpChatBridgeActive = false;
|
|
@@ -142,6 +147,31 @@ export function getEmbedAuthToken() {
|
|
|
142
147
|
return null;
|
|
143
148
|
const fromUrl = readTokenFromUrl(win);
|
|
144
149
|
if (fromUrl) {
|
|
150
|
+
let renewedFrom = renewedFromUrlToken;
|
|
151
|
+
if (!renewedFrom) {
|
|
152
|
+
try {
|
|
153
|
+
renewedFrom =
|
|
154
|
+
win.sessionStorage?.getItem(EMBED_TOKEN_RENEWED_FROM_STORAGE_KEY) ??
|
|
155
|
+
null;
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
renewedFrom = null;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (renewedFrom === fromUrl) {
|
|
162
|
+
const refreshed = memoryToken ?? storedToken(win);
|
|
163
|
+
if (refreshed && refreshed !== fromUrl)
|
|
164
|
+
return refreshed;
|
|
165
|
+
}
|
|
166
|
+
if (renewedFrom && renewedFrom !== fromUrl) {
|
|
167
|
+
renewedFromUrlToken = null;
|
|
168
|
+
try {
|
|
169
|
+
win.sessionStorage?.removeItem(EMBED_TOKEN_RENEWED_FROM_STORAGE_KEY);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
// coercion-ok: cleanup is best-effort; the refreshed URL token still supersedes this marker.
|
|
173
|
+
}
|
|
174
|
+
}
|
|
145
175
|
storeToken(fromUrl, win);
|
|
146
176
|
return fromUrl;
|
|
147
177
|
}
|
|
@@ -160,7 +190,7 @@ function readEmbedTokenScope(token) {
|
|
|
160
190
|
return undefined;
|
|
161
191
|
}
|
|
162
192
|
}
|
|
163
|
-
let
|
|
193
|
+
let widgetScopeCache = null;
|
|
164
194
|
/**
|
|
165
195
|
* True when the embed credential is a directory-widget read capability, which
|
|
166
196
|
* only the MCP App widget flows mint. It stays readable after a client
|
|
@@ -173,13 +203,29 @@ export function hasMcpDirectoryWidgetCapabilityToken() {
|
|
|
173
203
|
const token = getEmbedAuthToken();
|
|
174
204
|
if (!token)
|
|
175
205
|
return false;
|
|
176
|
-
if (
|
|
177
|
-
|
|
206
|
+
if (widgetScopeCache?.token !== token) {
|
|
207
|
+
const scope = readEmbedTokenScope(token);
|
|
208
|
+
widgetScopeCache = {
|
|
178
209
|
token,
|
|
179
|
-
readOnly: isMcpDirectoryWidgetReadCapabilityScope(
|
|
210
|
+
readOnly: isMcpDirectoryWidgetReadCapabilityScope(scope),
|
|
211
|
+
writable: isMcpDirectoryWidgetWriteCapabilityScope(scope),
|
|
180
212
|
};
|
|
181
213
|
}
|
|
182
|
-
return
|
|
214
|
+
return widgetScopeCache.readOnly || widgetScopeCache.writable;
|
|
215
|
+
}
|
|
216
|
+
export function hasMcpDirectoryWidgetWriteCapabilityToken() {
|
|
217
|
+
const token = getEmbedAuthToken();
|
|
218
|
+
if (!token)
|
|
219
|
+
return false;
|
|
220
|
+
if (widgetScopeCache?.token !== token) {
|
|
221
|
+
const scope = readEmbedTokenScope(token);
|
|
222
|
+
widgetScopeCache = {
|
|
223
|
+
token,
|
|
224
|
+
readOnly: isMcpDirectoryWidgetReadCapabilityScope(scope),
|
|
225
|
+
writable: isMcpDirectoryWidgetWriteCapabilityScope(scope),
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
return widgetScopeCache.writable;
|
|
183
229
|
}
|
|
184
230
|
/**
|
|
185
231
|
* True when this document is the app nested in an MCP App widget shell (the
|
|
@@ -187,7 +233,21 @@ export function hasMcpDirectoryWidgetCapabilityToken() {
|
|
|
187
233
|
* server limits to the widget's own resource reads.
|
|
188
234
|
*/
|
|
189
235
|
export function isMcpDirectoryWidgetReadOnlyEmbed() {
|
|
190
|
-
|
|
236
|
+
const token = getEmbedAuthToken();
|
|
237
|
+
if (!token)
|
|
238
|
+
return false;
|
|
239
|
+
if (widgetScopeCache?.token !== token) {
|
|
240
|
+
const scope = readEmbedTokenScope(token);
|
|
241
|
+
widgetScopeCache = {
|
|
242
|
+
token,
|
|
243
|
+
readOnly: isMcpDirectoryWidgetReadCapabilityScope(scope),
|
|
244
|
+
writable: isMcpDirectoryWidgetWriteCapabilityScope(scope),
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
return widgetScopeCache.readOnly && isEmbedMcpChatBridgeActive();
|
|
248
|
+
}
|
|
249
|
+
export function isMcpDirectoryWidgetWriteEmbed() {
|
|
250
|
+
return (hasMcpDirectoryWidgetWriteCapabilityToken() && isEmbedMcpChatBridgeActive());
|
|
191
251
|
}
|
|
192
252
|
export function isEmbedAuthActive() {
|
|
193
253
|
const win = browserWindow();
|
|
@@ -303,7 +363,10 @@ export function _resetEmbedAuthForTests() {
|
|
|
303
363
|
}
|
|
304
364
|
installed = false;
|
|
305
365
|
memoryToken = null;
|
|
306
|
-
|
|
366
|
+
renewedFromUrlToken = null;
|
|
367
|
+
pendingWidgetSessionRenewal = null;
|
|
368
|
+
widgetSessionRenewalRequestId = 0;
|
|
369
|
+
widgetScopeCache = null;
|
|
307
370
|
mcpChatBridgeActive = false;
|
|
308
371
|
mcpChatBridgeScope = null;
|
|
309
372
|
authFailureCache.clear();
|
|
@@ -526,6 +589,63 @@ function requestUrlAndKey(input, init, win) {
|
|
|
526
589
|
shouldGuard: shouldGuardAuthFailure(method, url),
|
|
527
590
|
};
|
|
528
591
|
}
|
|
592
|
+
function requestWidgetSessionRenewal(win) {
|
|
593
|
+
if (pendingWidgetSessionRenewal)
|
|
594
|
+
return pendingWidgetSessionRenewal;
|
|
595
|
+
if (!win.parent || win.parent === win)
|
|
596
|
+
return Promise.resolve(false);
|
|
597
|
+
widgetSessionRenewalRequestId += 1;
|
|
598
|
+
const requestId = `embed-renewal-${Date.now()}-${widgetSessionRenewalRequestId}`;
|
|
599
|
+
const renewal = new Promise((resolve) => {
|
|
600
|
+
let settled = false;
|
|
601
|
+
let timeoutId = null;
|
|
602
|
+
const finish = (succeeded) => {
|
|
603
|
+
if (settled)
|
|
604
|
+
return;
|
|
605
|
+
settled = true;
|
|
606
|
+
if (timeoutId !== null)
|
|
607
|
+
win.clearTimeout(timeoutId);
|
|
608
|
+
win.removeEventListener("message", onMessage);
|
|
609
|
+
resolve(succeeded);
|
|
610
|
+
};
|
|
611
|
+
const onMessage = (event) => {
|
|
612
|
+
if (event.source !== win.parent)
|
|
613
|
+
return;
|
|
614
|
+
const message = event.data;
|
|
615
|
+
const data = message && typeof message === "object" ? message.data : null;
|
|
616
|
+
if (message?.type !== "agentNative.embedSessionRenewed" ||
|
|
617
|
+
data?.requestId !== requestId) {
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
if (data.ok !== true) {
|
|
621
|
+
finish(false);
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
try {
|
|
625
|
+
win.parent.postMessage({ type: "agentNative.embedSessionRenewalApplied", requestId }, "*");
|
|
626
|
+
}
|
|
627
|
+
catch (error) {
|
|
628
|
+
console.warn("[agent-native] could not acknowledge embedded session renewal", error);
|
|
629
|
+
}
|
|
630
|
+
finish(true);
|
|
631
|
+
};
|
|
632
|
+
win.addEventListener("message", onMessage);
|
|
633
|
+
timeoutId = win.setTimeout(() => finish(false), EMBED_SESSION_RENEWAL_TIMEOUT_MS);
|
|
634
|
+
try {
|
|
635
|
+
win.parent.postMessage({
|
|
636
|
+
type: "agentNative.embedSessionExpired",
|
|
637
|
+
data: { requestId },
|
|
638
|
+
}, "*");
|
|
639
|
+
}
|
|
640
|
+
catch {
|
|
641
|
+
finish(false);
|
|
642
|
+
}
|
|
643
|
+
}).finally(() => {
|
|
644
|
+
pendingWidgetSessionRenewal = null;
|
|
645
|
+
});
|
|
646
|
+
pendingWidgetSessionRenewal = renewal;
|
|
647
|
+
return renewal;
|
|
648
|
+
}
|
|
529
649
|
export function ensureEmbedAuthFetchInterceptor() {
|
|
530
650
|
const win = browserWindow();
|
|
531
651
|
if (!win)
|
|
@@ -534,7 +654,7 @@ export function ensureEmbedAuthFetchInterceptor() {
|
|
|
534
654
|
markEmbedMcpChatBridgeActive();
|
|
535
655
|
const urlToken = readTokenFromUrl(win);
|
|
536
656
|
if (urlToken) {
|
|
537
|
-
|
|
657
|
+
getEmbedAuthToken();
|
|
538
658
|
stripTokenFromUrl(win);
|
|
539
659
|
}
|
|
540
660
|
ensureMcpChatBridgeViewportClamp(win);
|
|
@@ -562,7 +682,35 @@ export function ensureEmbedAuthFetchInterceptor() {
|
|
|
562
682
|
if (token && sameOrigin(input, win)) {
|
|
563
683
|
[fetchInput, fetchInit] = withEmbedAuthHeaders(input, init, token, win);
|
|
564
684
|
}
|
|
565
|
-
const
|
|
685
|
+
const canRenewWidgetSession = Boolean(token) &&
|
|
686
|
+
isMcpDirectoryWidgetWriteEmbed() &&
|
|
687
|
+
request &&
|
|
688
|
+
sameOrigin(input, win);
|
|
689
|
+
let replayRequest = null;
|
|
690
|
+
let firstRequest = null;
|
|
691
|
+
if (canRenewWidgetSession) {
|
|
692
|
+
try {
|
|
693
|
+
firstRequest = new Request(fetchInput, fetchInit);
|
|
694
|
+
replayRequest = firstRequest.clone();
|
|
695
|
+
}
|
|
696
|
+
catch {
|
|
697
|
+
// coercion-ok: non-cloneable streamed writes retain their original response and are not replayed.
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
let response = firstRequest
|
|
701
|
+
? await originalFetch(firstRequest)
|
|
702
|
+
: await originalFetch(fetchInput, fetchInit);
|
|
703
|
+
if (response.status === 401 && canRenewWidgetSession) {
|
|
704
|
+
const sessionExpired = response.headers.get(MCP_DIRECTORY_WIDGET_SESSION_EXPIRED_HEADER) ===
|
|
705
|
+
"1";
|
|
706
|
+
if (sessionExpired && replayRequest && token) {
|
|
707
|
+
const renewed = await requestWidgetSessionRenewal(win);
|
|
708
|
+
if (renewed) {
|
|
709
|
+
const [retryInput, retryInit] = withEmbedAuthHeaders(replayRequest, undefined, token, win);
|
|
710
|
+
response = await originalFetch(retryInput, retryInit);
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
566
714
|
if (request?.shouldGuard && isAuthFailureStatus(response.status)) {
|
|
567
715
|
await recordAuthFailure(request.key, response);
|
|
568
716
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { initializeAgentNativeClient } from "../client-bootstrap.js";
|
|
2
2
|
export { agentNativeApiDisabledReason, AgentNativeApiDisabledError, setAgentNativeApiDisabled, } from "../api-surface.js";
|
|
3
|
-
export { ensureEmbedAuthFetchInterceptor, getEmbedAuthToken, isEmbedAuthActive, isEmbedMcpChatBridgeActive, isMcpDirectoryWidgetReadOnlyEmbed, } from "../embed-auth.js";
|
|
3
|
+
export { ensureEmbedAuthFetchInterceptor, getEmbedAuthToken, isEmbedAuthActive, isEmbedMcpChatBridgeActive, isMcpDirectoryWidgetReadOnlyEmbed, isMcpDirectoryWidgetWriteEmbed, } from "../embed-auth.js";
|
|
4
4
|
export { sendToFrame, onFrameMessage, requestUserInfo, getFrameOrigin, getFramePostMessageTargetOrigin, getCallbackOrigin, oauthRedirectUri, isInFrame, isTrustedFrameMessage, enterStyleEditing, enterTextEditing, exitSelectionMode, type UserInfo, } from "../frame.js";
|
|
5
5
|
export { getBuilderParentOrigin, isInBuilderFrame, sendToBuilderChat, shouldParentFrameOwnAgentPanel, isTrustedBuilderMessage, tryDelegateBuildRequestToBuilder, type BuilderChatMessage, } from "../builder-frame.js";
|
|
6
6
|
export { getClientSurface, type ClientSurface } from "../client-surface.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { initializeAgentNativeClient } from "../client-bootstrap.js";
|
|
2
2
|
export { agentNativeApiDisabledReason, AgentNativeApiDisabledError, setAgentNativeApiDisabled, } from "../api-surface.js";
|
|
3
|
-
export { ensureEmbedAuthFetchInterceptor, getEmbedAuthToken, isEmbedAuthActive, isEmbedMcpChatBridgeActive, isMcpDirectoryWidgetReadOnlyEmbed, } from "../embed-auth.js";
|
|
3
|
+
export { ensureEmbedAuthFetchInterceptor, getEmbedAuthToken, isEmbedAuthActive, isEmbedMcpChatBridgeActive, isMcpDirectoryWidgetReadOnlyEmbed, isMcpDirectoryWidgetWriteEmbed, } from "../embed-auth.js";
|
|
4
4
|
export { sendToFrame, onFrameMessage, requestUserInfo, getFrameOrigin, getFramePostMessageTargetOrigin, getCallbackOrigin, oauthRedirectUri, isInFrame, isTrustedFrameMessage, enterStyleEditing, enterTextEditing, exitSelectionMode, } from "../frame.js";
|
|
5
5
|
export { getBuilderParentOrigin, isInBuilderFrame, sendToBuilderChat, shouldParentFrameOwnAgentPanel, isTrustedBuilderMessage, tryDelegateBuildRequestToBuilder, } from "../builder-frame.js";
|
|
6
6
|
export { getClientSurface } from "../client-surface.js";
|
|
@@ -64,6 +64,7 @@ export declare function useIsMcpAppWidgetEmbed(): boolean;
|
|
|
64
64
|
* instead of showing errors for requests that can never land.
|
|
65
65
|
*/
|
|
66
66
|
export declare function useIsMcpDirectoryWidgetReadOnlyEmbed(): boolean;
|
|
67
|
+
export declare function useIsMcpDirectoryWidgetWriteEmbed(): boolean;
|
|
67
68
|
export declare function isOpenAiMcpAppHost(): boolean;
|
|
68
69
|
export declare function initializeMcpAppHost(): Promise<boolean>;
|
|
69
70
|
export declare function sendMcpAppHostMessage(chat: McpAppHostChatMessage): Promise<boolean | null> | false;
|
|
@@ -2,7 +2,7 @@ import { useSyncExternalStore } from "react";
|
|
|
2
2
|
import { EMBED_MODE_QUERY_PARAM, EMBED_TOKEN_QUERY_PARAM, MCP_APP_CHAT_BRIDGE_QUERY_PARAM, } from "../shared/embed-auth.js";
|
|
3
3
|
import { MCP_APP_HOST_FILL_ATTRIBUTE, mcpAppHostFillsContainer, } from "../shared/mcp-app-display.js";
|
|
4
4
|
import { MCP_APP_WIDGET_EMBED_ATTRIBUTE } from "../shared/mcp-app-widget-embed.js";
|
|
5
|
-
import { getEmbedAuthToken, hasMcpDirectoryWidgetCapabilityToken, isEmbedAuthActive, markEmbedMcpChatBridgeActive, isEmbedMcpChatBridgeActive, isMcpDirectoryWidgetReadOnlyEmbed, readEmbedMcpChatBridgeFlagFromUrl, } from "./embed-auth.js";
|
|
5
|
+
import { getEmbedAuthToken, hasMcpDirectoryWidgetCapabilityToken, isEmbedAuthActive, markEmbedMcpChatBridgeActive, isEmbedMcpChatBridgeActive, isMcpDirectoryWidgetReadOnlyEmbed, isMcpDirectoryWidgetWriteEmbed, readEmbedMcpChatBridgeFlagFromUrl, } from "./embed-auth.js";
|
|
6
6
|
import { getFrameOrigin } from "./frame.js";
|
|
7
7
|
export const AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES = {
|
|
8
8
|
HOST_CONTEXT: "agentNative.mcpHostContext",
|
|
@@ -410,6 +410,9 @@ export function useIsMcpAppWidgetEmbed() {
|
|
|
410
410
|
export function useIsMcpDirectoryWidgetReadOnlyEmbed() {
|
|
411
411
|
return useSyncExternalStore(() => () => { }, isMcpDirectoryWidgetReadOnlyEmbed, () => false);
|
|
412
412
|
}
|
|
413
|
+
export function useIsMcpDirectoryWidgetWriteEmbed() {
|
|
414
|
+
return useSyncExternalStore(() => () => { }, isMcpDirectoryWidgetWriteEmbed, () => false);
|
|
415
|
+
}
|
|
413
416
|
export function isOpenAiMcpAppHost() {
|
|
414
417
|
return (isInChildFrame() && isMcpAppBridgeEnabled() && readOpenAiBridge() !== null);
|
|
415
418
|
}
|
package/dist/collab/routes.d.ts
CHANGED
|
@@ -13,8 +13,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
|
|
|
13
13
|
};
|
|
14
14
|
}>>;
|
|
15
15
|
export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
16
|
-
ok?: undefined;
|
|
17
16
|
error: string;
|
|
17
|
+
ok?: undefined;
|
|
18
18
|
} | {
|
|
19
19
|
error?: undefined;
|
|
20
20
|
ok: boolean;
|
|
@@ -33,9 +33,9 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
33
33
|
idempotencyKey: string;
|
|
34
34
|
deleted: boolean;
|
|
35
35
|
} | {
|
|
36
|
+
id?: undefined;
|
|
36
37
|
error: string;
|
|
37
38
|
url?: undefined;
|
|
38
|
-
id?: undefined;
|
|
39
39
|
provider?: undefined;
|
|
40
40
|
configured?: undefined;
|
|
41
41
|
} | {
|
|
@@ -45,8 +45,8 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
45
45
|
configured?: undefined;
|
|
46
46
|
error?: undefined;
|
|
47
47
|
} | {
|
|
48
|
-
url?: undefined;
|
|
49
48
|
id?: undefined;
|
|
49
|
+
url?: undefined;
|
|
50
50
|
provider?: undefined;
|
|
51
51
|
error: string;
|
|
52
52
|
configured: boolean;
|
|
@@ -34,6 +34,8 @@ export interface MCPConfig {
|
|
|
34
34
|
productionActions?: Record<string, ActionEntry>;
|
|
35
35
|
/** Unlisted from this MCP surface; used only when minting scoped widget tickets. */
|
|
36
36
|
widgetReadActions?: Record<string, ActionEntry>;
|
|
37
|
+
/** Unlisted from this MCP surface; editor mutations callable only by scoped widget grants. */
|
|
38
|
+
widgetWriteActions?: Record<string, ActionEntry>;
|
|
37
39
|
askAgent?: (message: string) => Promise<string>;
|
|
38
40
|
builtinCrossAppTools?: boolean;
|
|
39
41
|
/**
|
|
@@ -55,7 +57,15 @@ export interface MCPConfig {
|
|
|
55
57
|
widgets?: boolean;
|
|
56
58
|
widgetDomain?: string;
|
|
57
59
|
widgetTargets?: Record<string, (args: Record<string, unknown>, result: unknown) => McpDirectoryWidgetTarget | null>;
|
|
60
|
+
authorizeWidgetWrite?: (input: {
|
|
61
|
+
toolName: string;
|
|
62
|
+
args: Record<string, unknown>;
|
|
63
|
+
result: unknown;
|
|
64
|
+
target: McpDirectoryWidgetTarget;
|
|
65
|
+
identity: MCPCallerIdentity;
|
|
66
|
+
}) => boolean | Promise<boolean>;
|
|
58
67
|
widgetReadActionArguments?: Record<string, Record<string, McpDirectoryWidgetReadArgument>>;
|
|
68
|
+
widgetWriteActionArguments?: Record<string, Record<string, McpDirectoryWidgetReadArgument>>;
|
|
59
69
|
/** Actions whose capability-backed `mcp-widget` execution is strictly read-only. */
|
|
60
70
|
widgetReadOnlyActions?: readonly string[];
|
|
61
71
|
/** Unlisted public reads that are available only through a scoped widget ticket. */
|
|
@@ -79,10 +89,14 @@ export interface MCPConfig {
|
|
|
79
89
|
export interface McpDirectoryWidgetTarget {
|
|
80
90
|
targetPath: string;
|
|
81
91
|
resourceIds: Record<string, string>;
|
|
92
|
+
/** Mutations available to this artifact's editor, selected from the profile allowlist. */
|
|
93
|
+
writeActions?: readonly string[];
|
|
82
94
|
}
|
|
83
95
|
export interface MCPCallerIdentity {
|
|
84
96
|
userEmail: string | undefined;
|
|
85
97
|
identityAssurance?: "user" | "organization" | "service";
|
|
98
|
+
/** Issue time, in milliseconds, from a verified app-issued MCP credential. */
|
|
99
|
+
mcpCredentialIssuedAtMs?: number;
|
|
86
100
|
orgId?: string | null;
|
|
87
101
|
orgDomain: string | undefined;
|
|
88
102
|
oauthScopes?: string[];
|
|
@@ -108,6 +122,7 @@ export declare class McpDirectoryProfileValidationError extends Error {
|
|
|
108
122
|
}
|
|
109
123
|
export declare function selectMcpActionSurface(config: MCPConfig, requestMeta?: MCPRequestMeta): Record<string, ActionEntry>;
|
|
110
124
|
export declare function selectMcpDirectoryWidgetReadActions(profile: MCPConfig["directoryProfile"] | undefined, actions: Record<string, ActionEntry>): Record<string, ActionEntry> | undefined;
|
|
125
|
+
export declare function selectMcpDirectoryWidgetWriteActions(profile: MCPConfig["directoryProfile"] | undefined, actions: Record<string, ActionEntry>): Record<string, ActionEntry> | undefined;
|
|
111
126
|
export declare function getConfiguredMcpOwnerEmail(): string | undefined;
|
|
112
127
|
export declare function validateMcpDirectoryProfile(config: MCPConfig, sourceActions?: Record<string, ActionEntry>): void;
|
|
113
128
|
export declare function validateMcpDirectoryWidgetDomain(domain: string | undefined): void;
|