@agent-native/core 0.164.3 → 0.164.11
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/corpus/README.md +1 -1
- package/corpus/templates/calendar/app/components/calendar/CreateEventDialog.tsx +36 -47
- package/corpus/templates/calendar/app/components/calendar/DayView.tsx +3 -0
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +18 -1
- package/corpus/templates/calendar/app/components/calendar/InlineEventPickers.tsx +256 -38
- package/corpus/templates/calendar/app/hooks/use-google-auth.ts +43 -3
- package/corpus/templates/calendar/app/i18n-data.ts +120 -0
- package/corpus/templates/calendar/app/lib/event-form-utils.ts +113 -0
- package/corpus/templates/calendar/server/handlers/google-auth.ts +119 -3
- package/corpus/templates/calendar/server/routes/[base]/_agent-native/google/add-account/auth-url.post.ts +1 -0
- package/corpus/templates/calendar/server/routes/[base]/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/calendar/server/routes/_agent-native/google/add-account/auth-url.post.ts +1 -0
- package/corpus/templates/calendar/server/routes/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +1 -1
- package/corpus/templates/clips/app/components/player/video-player.tsx +12 -0
- package/corpus/templates/clips/app/routes/_app.dictate.tsx +18 -4
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +114 -20
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +86 -78
- package/corpus/templates/clips/changelog/2026-08-19-clips-nightly-builds-are-available-for-trying-the-latest-upd.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-19-social-preview-video-frames.md +6 -0
- package/corpus/templates/clips/desktop/README.md +19 -4
- package/corpus/templates/clips/desktop/src/app.tsx +78 -16
- package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +3 -2
- package/corpus/templates/clips/desktop/src-tauri/tauri.conf.json +1 -0
- package/corpus/templates/clips/server/lib/slack-unfurls.ts +7 -13
- package/corpus/templates/clips/server/routes/[base]/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/clips/server/routes/_agent-native/google/auth-url.get.ts +41 -3
- package/corpus/templates/clips/server/routes/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/clips/server/routes/_agent-native/google/callback.get.ts +22 -1
- package/corpus/templates/clips/server/routes/api/clips-updater.json.get.ts +41 -22
- package/corpus/templates/clips/shared/share-meta.ts +67 -3
- package/corpus/templates/content/actions/list-content-databases.ts +95 -1
- package/corpus/templates/content/changelog/2026-08-11-content-mutations-delegated-from-verified-slack-dms-now-use-.md +6 -0
- package/corpus/templates/content/shared/api.ts +11 -0
- package/corpus/templates/factory/AGENTS.md +1 -1
- package/corpus/templates/factory/actions/list-factory-automations.ts +4 -0
- package/corpus/templates/factory/actions/start-builder-for-item.ts +19 -17
- package/corpus/templates/factory/app/components/factory/FactoryAuditView.tsx +100 -36
- package/corpus/templates/factory/app/i18n/en-US.ts +4 -0
- package/corpus/templates/factory/app/routes/factory.tsx +209 -46
- package/corpus/templates/factory/server/connectors/slack.ts +44 -2
- package/corpus/templates/factory/server/plugins/agent-chat.ts +9 -7
- package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +13 -0
- package/corpus/templates/factory/server/triage/slack-client.ts +5 -0
- package/corpus/templates/factory/server/triage/slack-poller.ts +72 -4
- package/corpus/templates/mail/actions/view-screen.ts +1 -1
- package/corpus/templates/mail/app/components/GoogleConnectBanner.tsx +100 -18
- package/corpus/templates/mail/server/handlers/google-auth.ts +125 -24
- package/corpus/templates/mail/server/lib/gmail-query.ts +5 -2
- package/corpus/templates/mail/server/routes/[base]/_agent-native/google/add-account/auth-url.post.ts +1 -0
- package/corpus/templates/mail/server/routes/[base]/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/mail/server/routes/_agent-native/google/add-account/auth-url.post.ts +1 -0
- package/corpus/templates/mail/server/routes/_agent-native/google/auth-url.post.ts +1 -0
- package/corpus/templates/plan/app/pages/PlansPage.tsx +0 -12
- package/corpus/templates/plan/changelog/2026-08-19-plan-prompts-now-guide-you-to-connect-ai-before-sending-and-.md +6 -0
- package/corpus/templates/slides/actions/approve-deck-access-request.ts +234 -0
- package/corpus/templates/slides/actions/get-deck-access-status.ts +35 -2
- package/corpus/templates/slides/actions/request-deck-access.ts +263 -64
- package/corpus/templates/slides/app/components/editor/MissingDeckAccessPane.tsx +196 -0
- package/corpus/templates/slides/app/components/editor/RequestDeckAccessDialog.tsx +101 -0
- package/corpus/templates/slides/app/hooks/use-deck-access.ts +7 -4
- package/corpus/templates/slides/app/i18n/en-US.ts +29 -6
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +147 -169
- package/corpus/templates/slides/app/routes/access-request.approve.tsx +250 -0
- package/corpus/templates/slides/server/db/schema.ts +8 -0
- package/corpus/templates/slides/server/lib/access-request-email.ts +36 -0
- package/corpus/templates/slides/server/lib/emails.ts +26 -0
- package/corpus/templates/slides/server/plugins/agent-chat.ts +7 -0
- package/corpus/templates/slides/server/plugins/db.ts +50 -0
- package/corpus/templates/slides/shared/deck-access.ts +31 -0
- package/dist/a2a/artifact-response.d.ts +50 -0
- package/dist/a2a/artifact-response.js +266 -39
- package/dist/a2a/index.d.ts +2 -0
- package/dist/a2a/index.js +1 -0
- package/dist/a2a/task-store.d.ts +1 -0
- package/dist/a2a/task-store.js +1 -1
- package/dist/agent/observational-memory/store.d.ts +1 -0
- package/dist/agent/observational-memory/store.js +1 -1
- package/dist/agent/run-store.d.ts +1 -0
- package/dist/agent/run-store.js +1 -1
- package/dist/agent/tool-approval-store.d.ts +1 -0
- package/dist/agent/tool-approval-store.js +1 -1
- package/dist/application-state/store.d.ts +1 -0
- package/dist/application-state/store.js +1 -1
- package/dist/browser-sessions/store.d.ts +1 -0
- package/dist/browser-sessions/store.js +1 -1
- package/dist/checkpoints/store.d.ts +1 -0
- package/dist/checkpoints/store.js +1 -1
- package/dist/cli/code-agent-schedules.d.ts +11 -0
- package/dist/cli/code-agent-schedules.js +44 -5
- package/dist/client/AgentPanel.d.ts +5 -1
- package/dist/client/AgentPanel.js +2 -2
- package/dist/client/AssistantChat.d.ts +5 -1
- package/dist/client/AssistantChat.js +40 -6
- package/dist/client/EnvironmentBadge.d.ts +7 -13
- package/dist/client/EnvironmentBadge.js +43 -92
- package/dist/client/agent-chat/index.d.ts +1 -0
- package/dist/client/agent-chat/index.js +1 -0
- package/dist/client/agent-chat-adapter.js +76 -50
- package/dist/client/app-providers.js +4 -4
- package/dist/client/chat/message-components.d.ts +4 -0
- package/dist/client/chat/message-components.js +28 -1
- package/dist/client/chat/run-recovery.js +26 -0
- package/dist/client/chat-first/apps-rail.d.ts +1 -0
- package/dist/client/chat-first/apps-rail.js +28 -2
- package/dist/client/sse-event-processor.js +13 -8
- package/dist/client/use-active-agent-chat-run.d.ts +2 -0
- package/dist/client/use-active-agent-chat-run.js +22 -0
- package/dist/coding-tools/sandbox/executions-store.d.ts +1 -0
- package/dist/coding-tools/sandbox/executions-store.js +1 -1
- package/dist/collab/awareness-store.d.ts +1 -0
- package/dist/collab/awareness-store.js +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/storage.d.ts +1 -0
- package/dist/collab/storage.js +1 -1
- package/dist/db/client.js +3 -3
- package/dist/db/ddl-guard.js +8 -0
- package/dist/db/migration-runtime.d.ts +23 -0
- package/dist/db/migration-runtime.js +41 -0
- package/dist/db/migrations.d.ts +1 -2
- package/dist/db/migrations.js +2 -24
- package/dist/email-catalog/log.d.ts +1 -0
- package/dist/email-catalog/log.js +1 -1
- package/dist/guards/index.d.ts +1 -0
- package/dist/guards/index.js +1 -0
- package/dist/guards/release-schema-complete.d.ts +22 -0
- package/dist/guards/release-schema-complete.js +144 -0
- package/dist/integrations/a2a-continuations-store.d.ts +1 -0
- package/dist/integrations/a2a-continuations-store.js +1 -1
- package/dist/integrations/adapters/slack.js +58 -7
- package/dist/integrations/awaiting-input-store.d.ts +1 -0
- package/dist/integrations/awaiting-input-store.js +1 -1
- package/dist/integrations/config-store.d.ts +1 -0
- package/dist/integrations/config-store.js +1 -1
- package/dist/integrations/controls-store.d.ts +1 -0
- package/dist/integrations/controls-store.js +1 -1
- package/dist/integrations/identity-links-store.d.ts +1 -0
- package/dist/integrations/identity-links-store.js +1 -1
- package/dist/integrations/installations-store.d.ts +1 -0
- package/dist/integrations/installations-store.js +1 -1
- package/dist/integrations/remote-commands-store.d.ts +1 -0
- package/dist/integrations/remote-commands-store.js +1 -1
- package/dist/integrations/remote-devices-store.d.ts +1 -0
- package/dist/integrations/remote-devices-store.js +1 -1
- package/dist/integrations/remote-push-store.d.ts +1 -0
- package/dist/integrations/remote-push-store.js +1 -1
- package/dist/integrations/remote-run-events-store.d.ts +1 -0
- package/dist/integrations/remote-run-events-store.js +1 -1
- package/dist/integrations/scope-store.d.ts +1 -0
- package/dist/integrations/scope-store.js +1 -1
- package/dist/integrations/thread-mapping-store.d.ts +1 -0
- package/dist/integrations/thread-mapping-store.js +1 -1
- package/dist/integrations/usage-budget-store.d.ts +1 -0
- package/dist/integrations/usage-budget-store.js +1 -1
- package/dist/jobs/background-automation-runner.js +111 -9
- package/dist/jobs/run-history.d.ts +1 -0
- package/dist/jobs/run-history.js +1 -1
- package/dist/jobs/scheduler-health.d.ts +1 -0
- package/dist/jobs/scheduler-health.js +1 -1
- package/dist/mcp/approval-store.d.ts +1 -0
- package/dist/mcp/approval-store.js +1 -1
- package/dist/mcp/connect-store.d.ts +1 -0
- package/dist/mcp/connect-store.js +1 -1
- package/dist/mcp/oauth-store.d.ts +1 -0
- package/dist/mcp/oauth-store.js +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/notifications/store.d.ts +1 -0
- package/dist/notifications/store.js +1 -1
- package/dist/oauth-tokens/store.d.ts +1 -0
- package/dist/oauth-tokens/store.js +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/progress/store.d.ts +1 -0
- package/dist/progress/store.js +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +5 -5
- package/dist/provider-api/actions/provider-api.d.ts +4 -4
- package/dist/provider-api/corpus-jobs-store.d.ts +1 -0
- package/dist/provider-api/corpus-jobs-store.js +1 -1
- package/dist/provider-api/custom-registry.d.ts +1 -0
- package/dist/provider-api/custom-registry.js +1 -1
- package/dist/provider-api/quota-governor.d.ts +1 -0
- package/dist/provider-api/quota-governor.js +1 -1
- package/dist/provider-api/staged-datasets-store.d.ts +1 -0
- package/dist/provider-api/staged-datasets-store.js +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/resources/store.d.ts +1 -0
- package/dist/resources/store.js +1 -1
- package/dist/scripts/dev/index.js +15 -1
- package/dist/search/index.js +3 -0
- package/dist/secrets/storage.d.ts +1 -0
- package/dist/secrets/storage.js +1 -1
- package/dist/server/agent-chat/action-filters-a2a.d.ts +2 -1
- package/dist/server/agent-chat/action-filters-a2a.js +10 -2
- package/dist/server/agent-chat-plugin.js +71 -20
- package/dist/server/agent-teams-run-queue.d.ts +1 -0
- package/dist/server/agent-teams-run-queue.js +1 -1
- package/dist/server/auth-marketing.js +3 -1
- package/dist/server/auth.d.ts +18 -1
- package/dist/server/auth.js +370 -154
- package/dist/server/embed-session.d.ts +1 -0
- package/dist/server/embed-session.js +1 -1
- package/dist/server/google-auth-plugin.js +3 -1
- package/dist/server/google-oauth.d.ts +10 -0
- package/dist/server/google-oauth.js +25 -1
- package/dist/server/identity-sso-store.d.ts +1 -0
- package/dist/server/identity-sso-store.js +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/onboarding-html.js +200 -31
- package/dist/server/poll.d.ts +2 -0
- package/dist/server/poll.js +19 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/release-migrations.js +5 -0
- package/dist/server/release-schema.d.ts +46 -0
- package/dist/server/release-schema.js +307 -0
- package/dist/settings/store.d.ts +1 -0
- package/dist/settings/store.js +1 -1
- package/dist/shared/environment-lanes.d.ts +28 -0
- package/dist/shared/environment-lanes.js +61 -0
- package/dist/sharing/actions/share-resource.js +22 -2
- package/dist/styles/agent-native.css +17 -15
- package/dist/triggers/routes.d.ts +11 -0
- package/dist/triggers/routes.js +10 -0
- package/dist/usage/alerts-store.d.ts +1 -0
- package/dist/usage/alerts-store.js +1 -1
- package/dist/usage/store.d.ts +1 -0
- package/dist/usage/store.js +1 -1
- package/docs/content/drop-in-agent.mdx +4 -4
- package/docs/content/faq.mdx +15 -15
- package/docs/content/getting-started.mdx +173 -41
- package/docs/content/key-concepts.mdx +10 -10
- package/docs/content/using-your-agent.mdx +2 -2
- package/docs/content/what-is-agent-native.mdx +79 -228
- package/package.json +2 -2
|
@@ -70,7 +70,7 @@ async function fetchEmailList(
|
|
|
70
70
|
|
|
71
71
|
const gmailQuery = buildGmailEmailSearchQuery({ view, q: search });
|
|
72
72
|
const effectiveQuery =
|
|
73
|
-
view === "all" && !search ? "" : gmailQuery || "in:inbox
|
|
73
|
+
view === "all" && !search ? "" : gmailQuery || "in:inbox";
|
|
74
74
|
const { messages } = await listGmailMessages(
|
|
75
75
|
effectiveQuery,
|
|
76
76
|
50,
|
|
@@ -76,6 +76,25 @@ const ADD_ACCOUNT_POLL_ABORT_MS = Math.max(
|
|
|
76
76
|
ADD_ACCOUNT_POLL_INTERVAL_MS * 4,
|
|
77
77
|
);
|
|
78
78
|
|
|
79
|
+
function newDesktopOAuthVerifier(): string | null {
|
|
80
|
+
const cryptoApi = globalThis.crypto;
|
|
81
|
+
const randomUuid = cryptoApi?.randomUUID;
|
|
82
|
+
if (typeof randomUuid === "function") {
|
|
83
|
+
return `${randomUuid.call(cryptoApi)}${randomUuid.call(cryptoApi)}`;
|
|
84
|
+
}
|
|
85
|
+
if (typeof cryptoApi?.getRandomValues === "function") {
|
|
86
|
+
const bytes = new Uint8Array(32);
|
|
87
|
+
cryptoApi.getRandomValues(bytes);
|
|
88
|
+
let binary = "";
|
|
89
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
90
|
+
return btoa(binary)
|
|
91
|
+
.replace(/\+/g, "-")
|
|
92
|
+
.replace(/\//g, "_")
|
|
93
|
+
.replace(/=+$/, "");
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
|
|
79
98
|
interface GoogleConnectBannerProps {
|
|
80
99
|
variant?: "banner" | "hero";
|
|
81
100
|
}
|
|
@@ -128,20 +147,81 @@ export function GoogleConnectBanner({
|
|
|
128
147
|
const flowId =
|
|
129
148
|
crypto.randomUUID?.() ||
|
|
130
149
|
Math.random().toString(36).slice(2) + Date.now().toString(36);
|
|
150
|
+
const verifier = newDesktopOAuthVerifier();
|
|
151
|
+
if (!verifier) {
|
|
152
|
+
setDesktopAuthIssue({
|
|
153
|
+
code: "desktop_auth_start_failed",
|
|
154
|
+
message: t("mail.error.failedToConnect"),
|
|
155
|
+
});
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
131
158
|
const origin = window.location.origin;
|
|
132
159
|
const endpoint = addAccount
|
|
133
160
|
? "/_agent-native/google/add-account/auth-url"
|
|
134
161
|
: "/_agent-native/google/auth-url";
|
|
135
|
-
const
|
|
136
|
-
oauthRedirectUri("/_agent-native/google/callback"),
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
)
|
|
162
|
+
const params = new URLSearchParams({
|
|
163
|
+
redirect_uri: oauthRedirectUri("/_agent-native/google/callback"),
|
|
164
|
+
desktop: "1",
|
|
165
|
+
flow_id: flowId,
|
|
166
|
+
});
|
|
167
|
+
const popup = window.open("", "_blank");
|
|
168
|
+
if (!popup) {
|
|
169
|
+
setDesktopAuthIssue({
|
|
170
|
+
code: "popup_blocked",
|
|
171
|
+
message: t("mail.error.failedToConnect"),
|
|
172
|
+
});
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
let pollHandle: ReturnType<typeof setInterval> | null = null;
|
|
176
|
+
const stopPoll = () => {
|
|
177
|
+
if (!pollHandle) return;
|
|
178
|
+
clearInterval(pollHandle);
|
|
179
|
+
if (desktopPollRef.current === pollHandle) {
|
|
180
|
+
desktopPollRef.current = null;
|
|
181
|
+
}
|
|
182
|
+
pollHandle = null;
|
|
183
|
+
};
|
|
184
|
+
void fetch(`${origin}${agentNativePath(endpoint)}?${params.toString()}`, {
|
|
185
|
+
method: "POST",
|
|
186
|
+
credentials: "include",
|
|
187
|
+
headers: { "X-Agent-Native-Desktop-Verifier": verifier },
|
|
188
|
+
})
|
|
189
|
+
.then(async (response) => {
|
|
190
|
+
let data: {
|
|
191
|
+
url?: unknown;
|
|
192
|
+
message?: unknown;
|
|
193
|
+
error?: unknown;
|
|
194
|
+
};
|
|
195
|
+
try {
|
|
196
|
+
data = (await response.json()) as typeof data;
|
|
197
|
+
} catch {
|
|
198
|
+
throw new Error(t("mail.googleConnect.connectionFailed"));
|
|
199
|
+
}
|
|
200
|
+
if (!response.ok || typeof data?.url !== "string") {
|
|
201
|
+
const message =
|
|
202
|
+
typeof data.message === "string"
|
|
203
|
+
? data.message
|
|
204
|
+
: typeof data.error === "string"
|
|
205
|
+
? data.error
|
|
206
|
+
: t("mail.googleConnect.connectionFailed");
|
|
207
|
+
throw new Error(message);
|
|
208
|
+
}
|
|
209
|
+
popup.location.href = data.url;
|
|
210
|
+
})
|
|
211
|
+
.catch((error) => {
|
|
212
|
+
stopPoll();
|
|
213
|
+
popup.close();
|
|
214
|
+
setDesktopAuthIssue({
|
|
215
|
+
code: "desktop_auth_start_failed",
|
|
216
|
+
message:
|
|
217
|
+
error instanceof Error
|
|
218
|
+
? error.message
|
|
219
|
+
: t("mail.googleConnect.connectionFailed"),
|
|
220
|
+
});
|
|
221
|
+
});
|
|
142
222
|
const start = Date.now();
|
|
143
223
|
if (desktopPollRef.current) clearInterval(desktopPollRef.current);
|
|
144
|
-
|
|
224
|
+
pollHandle = setInterval(async () => {
|
|
145
225
|
if (document.hidden || desktopPollInFlightRef.current) return;
|
|
146
226
|
desktopPollInFlightRef.current = true;
|
|
147
227
|
const controller = new AbortController();
|
|
@@ -153,18 +233,21 @@ export function GoogleConnectBanner({
|
|
|
153
233
|
try {
|
|
154
234
|
const res = await fetch(
|
|
155
235
|
agentNativePath(
|
|
156
|
-
`/_agent-native/auth/desktop-exchange?flow_id=${flowId}`,
|
|
236
|
+
`/_agent-native/auth/desktop-exchange?flow_id=${encodeURIComponent(flowId)}`,
|
|
157
237
|
),
|
|
158
|
-
{
|
|
238
|
+
{
|
|
239
|
+
headers: {
|
|
240
|
+
"X-Agent-Native-Desktop-Verifier": verifier,
|
|
241
|
+
},
|
|
242
|
+
signal: controller.signal,
|
|
243
|
+
},
|
|
159
244
|
);
|
|
160
245
|
const data = await res.json();
|
|
161
246
|
if (data?.error) {
|
|
162
|
-
|
|
163
|
-
desktopPollRef.current = null;
|
|
247
|
+
stopPoll();
|
|
164
248
|
setDesktopAuthIssue(data);
|
|
165
249
|
} else if (data?.token) {
|
|
166
|
-
|
|
167
|
-
desktopPollRef.current = null;
|
|
250
|
+
stopPoll();
|
|
168
251
|
await fetch(
|
|
169
252
|
agentNativePath(
|
|
170
253
|
`/_agent-native/auth/session?_session=${data.token}`,
|
|
@@ -176,13 +259,11 @@ export function GoogleConnectBanner({
|
|
|
176
259
|
);
|
|
177
260
|
window.location.reload();
|
|
178
261
|
} else if (Date.now() - start > 120_000) {
|
|
179
|
-
|
|
180
|
-
desktopPollRef.current = null;
|
|
262
|
+
stopPoll();
|
|
181
263
|
}
|
|
182
264
|
} catch {
|
|
183
265
|
if (Date.now() - start > 120_000) {
|
|
184
|
-
|
|
185
|
-
desktopPollRef.current = null;
|
|
266
|
+
stopPoll();
|
|
186
267
|
}
|
|
187
268
|
}
|
|
188
269
|
} finally {
|
|
@@ -190,6 +271,7 @@ export function GoogleConnectBanner({
|
|
|
190
271
|
desktopPollInFlightRef.current = false;
|
|
191
272
|
}
|
|
192
273
|
}, DESKTOP_POLL_INTERVAL_MS);
|
|
274
|
+
desktopPollRef.current = pollHandle;
|
|
193
275
|
}
|
|
194
276
|
|
|
195
277
|
const [authError, setAuthError] = useState<string | null>(null);
|
|
@@ -15,6 +15,9 @@ import {
|
|
|
15
15
|
oauthCallbackResponse,
|
|
16
16
|
oauthDesktopExchangePage,
|
|
17
17
|
oauthErrorPage,
|
|
18
|
+
registerDesktopExchange,
|
|
19
|
+
prepareDesktopOAuthBrowserBinding,
|
|
20
|
+
matchesDesktopOAuthBrowserBinding,
|
|
18
21
|
safeReturnPath,
|
|
19
22
|
setDesktopExchange,
|
|
20
23
|
setDesktopExchangeError,
|
|
@@ -22,6 +25,8 @@ import {
|
|
|
22
25
|
import { getUserSetting, putUserSetting } from "@agent-native/core/settings";
|
|
23
26
|
import {
|
|
24
27
|
defineEventHandler,
|
|
28
|
+
getHeader,
|
|
29
|
+
getMethod,
|
|
25
30
|
getQuery,
|
|
26
31
|
setResponseStatus,
|
|
27
32
|
type H3Event,
|
|
@@ -64,17 +69,25 @@ function googleOAuthErrorPayload(
|
|
|
64
69
|
error?.name === "OAuthAccountOwnedByOtherUserError"
|
|
65
70
|
) {
|
|
66
71
|
const account = error.accountId || "This Google account";
|
|
72
|
+
const message = `${account} is connected to another login. Sign out, then sign in with ${account}.`;
|
|
67
73
|
return {
|
|
68
|
-
message
|
|
74
|
+
message,
|
|
69
75
|
code: "account_owner_mismatch",
|
|
70
76
|
accountId: error.accountId,
|
|
71
77
|
};
|
|
72
78
|
}
|
|
73
79
|
|
|
74
80
|
const msg = error?.message || "Unknown error";
|
|
81
|
+
const statusCode = Number(error?.statusCode || error?.status || 0);
|
|
75
82
|
const isPermission =
|
|
83
|
+
error?.oauthErrorCode === "access_denied" ||
|
|
84
|
+
error?.oauthErrorCode === "forbidden" ||
|
|
85
|
+
error?.oauthErrorCode === "insufficient_scope" ||
|
|
76
86
|
msg.includes("Insufficient Permission") ||
|
|
77
|
-
msg.includes("insufficient_scope")
|
|
87
|
+
msg.includes("insufficient_scope") ||
|
|
88
|
+
/insufficient authentication scopes/i.test(msg) ||
|
|
89
|
+
(statusCode === 403 &&
|
|
90
|
+
/\b(?:scope|permission|forbidden|access denied)\b/i.test(msg));
|
|
78
91
|
return {
|
|
79
92
|
message: isPermission
|
|
80
93
|
? "This account wasn't granted the required permissions. Make sure you check all the permission boxes on the consent screen. If the app is in testing mode, add this email as a test user in Google Cloud Console."
|
|
@@ -99,6 +112,7 @@ function googleOAuthErrorResponse(
|
|
|
99
112
|
export const getGoogleAuthUrl = defineEventHandler(async (event: H3Event) => {
|
|
100
113
|
try {
|
|
101
114
|
const q = getQuery(event);
|
|
115
|
+
const method = getMethod(event);
|
|
102
116
|
const redirectUri = resolveOAuthRedirectUri(event);
|
|
103
117
|
if (!redirectUri) {
|
|
104
118
|
setResponseStatus(event, 400);
|
|
@@ -113,6 +127,34 @@ export const getGoogleAuthUrl = defineEventHandler(async (event: H3Event) => {
|
|
|
113
127
|
const desktop =
|
|
114
128
|
isElectron(event) || q.desktop === "1" || q.desktop === "true";
|
|
115
129
|
const flowId = desktop ? (q.flow_id as string) || undefined : undefined;
|
|
130
|
+
if (method === "POST" && (!desktop || !flowId)) {
|
|
131
|
+
setResponseStatus(event, 400);
|
|
132
|
+
return { error: "Invalid desktop exchange challenge." };
|
|
133
|
+
}
|
|
134
|
+
let desktopVerifierHash: string | undefined;
|
|
135
|
+
let desktopBrowserBindingHash: string | undefined;
|
|
136
|
+
if (flowId) {
|
|
137
|
+
if (method !== "POST" || q.redirect !== undefined) {
|
|
138
|
+
setResponseStatus(event, 400);
|
|
139
|
+
return { error: "Invalid desktop exchange challenge." };
|
|
140
|
+
}
|
|
141
|
+
const verifier = getHeader(event, "x-agent-native-desktop-verifier");
|
|
142
|
+
if (!verifier || q.verifier !== undefined) {
|
|
143
|
+
setResponseStatus(event, 400);
|
|
144
|
+
return { error: "Invalid desktop exchange challenge." };
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
desktopBrowserBindingHash = prepareDesktopOAuthBrowserBinding(event);
|
|
148
|
+
desktopVerifierHash = await registerDesktopExchange(
|
|
149
|
+
flowId,
|
|
150
|
+
verifier,
|
|
151
|
+
desktopBrowserBindingHash,
|
|
152
|
+
);
|
|
153
|
+
} catch {
|
|
154
|
+
setResponseStatus(event, 400);
|
|
155
|
+
return { error: "Invalid desktop exchange challenge." };
|
|
156
|
+
}
|
|
157
|
+
}
|
|
116
158
|
const requestedReturn =
|
|
117
159
|
typeof q.return === "string" ? safeReturnPath(q.return) : "/";
|
|
118
160
|
const returnUrl = requestedReturn !== "/" ? requestedReturn : undefined;
|
|
@@ -127,6 +169,8 @@ export const getGoogleAuthUrl = defineEventHandler(async (event: H3Event) => {
|
|
|
127
169
|
app: OAUTH_STATE_APP_ID,
|
|
128
170
|
returnUrl,
|
|
129
171
|
flowId,
|
|
172
|
+
desktopVerifierHash,
|
|
173
|
+
desktopBrowserBindingHash,
|
|
130
174
|
});
|
|
131
175
|
const url = await getAuthUrl(undefined, redirectUri, state, owner);
|
|
132
176
|
if (q.redirect === "1") {
|
|
@@ -159,22 +203,28 @@ export const handleGoogleCallback = defineEventHandler(
|
|
|
159
203
|
);
|
|
160
204
|
desktop = state.desktop ?? false;
|
|
161
205
|
flowId = state.flowId;
|
|
206
|
+
if (
|
|
207
|
+
flowId &&
|
|
208
|
+
(!state.desktopVerifierHash ||
|
|
209
|
+
!state.desktopBrowserBindingHash ||
|
|
210
|
+
!matchesDesktopOAuthBrowserBinding(
|
|
211
|
+
event,
|
|
212
|
+
state.desktopBrowserBindingHash,
|
|
213
|
+
))
|
|
214
|
+
) {
|
|
215
|
+
throw new Error("Desktop OAuth browser binding is invalid.");
|
|
216
|
+
}
|
|
162
217
|
|
|
163
218
|
// Handle Google authorization errors (e.g. user denied access, invalid client)
|
|
164
219
|
const googleError = query.error as string | undefined;
|
|
165
220
|
if (googleError) {
|
|
166
221
|
const errorDesc =
|
|
167
222
|
(query.error_description as string | undefined) || googleError;
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
: `Connection failed: ${errorDesc}`;
|
|
174
|
-
return googleOAuthErrorResponse(event, new Error(userMessage), {
|
|
175
|
-
desktop,
|
|
176
|
-
flowId,
|
|
177
|
-
});
|
|
223
|
+
return googleOAuthErrorResponse(
|
|
224
|
+
event,
|
|
225
|
+
Object.assign(new Error(errorDesc), { oauthErrorCode: googleError }),
|
|
226
|
+
{ desktop, flowId },
|
|
227
|
+
);
|
|
178
228
|
}
|
|
179
229
|
|
|
180
230
|
const code = query.code as string;
|
|
@@ -183,7 +233,13 @@ export const handleGoogleCallback = defineEventHandler(
|
|
|
183
233
|
return { error: "Missing authorization code" };
|
|
184
234
|
}
|
|
185
235
|
|
|
186
|
-
const {
|
|
236
|
+
const {
|
|
237
|
+
redirectUri,
|
|
238
|
+
owner: stateOwner,
|
|
239
|
+
addAccount,
|
|
240
|
+
returnUrl,
|
|
241
|
+
desktopVerifierHash,
|
|
242
|
+
} = state;
|
|
187
243
|
|
|
188
244
|
// 1. Resolve owner (needs session context, before exchangeCode)
|
|
189
245
|
const { owner, hasProductionSession } = await resolveOAuthOwner(
|
|
@@ -249,7 +305,15 @@ export const handleGoogleCallback = defineEventHandler(
|
|
|
249
305
|
});
|
|
250
306
|
|
|
251
307
|
if (flowId && sessionToken) {
|
|
252
|
-
|
|
308
|
+
if (!desktopVerifierHash) {
|
|
309
|
+
throw new Error("Missing desktop exchange challenge.");
|
|
310
|
+
}
|
|
311
|
+
await setDesktopExchange(
|
|
312
|
+
flowId,
|
|
313
|
+
sessionToken,
|
|
314
|
+
email,
|
|
315
|
+
desktopVerifierHash,
|
|
316
|
+
);
|
|
253
317
|
}
|
|
254
318
|
|
|
255
319
|
// 4. Return platform-appropriate response
|
|
@@ -284,6 +348,7 @@ export const getGoogleAddAccountUrl = defineEventHandler(
|
|
|
284
348
|
}
|
|
285
349
|
try {
|
|
286
350
|
const q = getQuery(event);
|
|
351
|
+
const method = getMethod(event);
|
|
287
352
|
const redirectUri = resolveOAuthRedirectUri(event);
|
|
288
353
|
if (!redirectUri) {
|
|
289
354
|
setResponseStatus(event, 400);
|
|
@@ -295,6 +360,34 @@ export const getGoogleAddAccountUrl = defineEventHandler(
|
|
|
295
360
|
const desktop =
|
|
296
361
|
isElectron(event) || q.desktop === "1" || q.desktop === "true";
|
|
297
362
|
const flowId = desktop ? (q.flow_id as string) || undefined : undefined;
|
|
363
|
+
if (method === "POST" && (!desktop || !flowId)) {
|
|
364
|
+
setResponseStatus(event, 400);
|
|
365
|
+
return { error: "Invalid desktop exchange challenge." };
|
|
366
|
+
}
|
|
367
|
+
let desktopVerifierHash: string | undefined;
|
|
368
|
+
let desktopBrowserBindingHash: string | undefined;
|
|
369
|
+
if (flowId) {
|
|
370
|
+
if (method !== "POST" || q.redirect !== undefined) {
|
|
371
|
+
setResponseStatus(event, 400);
|
|
372
|
+
return { error: "Invalid desktop exchange challenge." };
|
|
373
|
+
}
|
|
374
|
+
const verifier = getHeader(event, "x-agent-native-desktop-verifier");
|
|
375
|
+
if (!verifier || q.verifier !== undefined) {
|
|
376
|
+
setResponseStatus(event, 400);
|
|
377
|
+
return { error: "Invalid desktop exchange challenge." };
|
|
378
|
+
}
|
|
379
|
+
try {
|
|
380
|
+
desktopBrowserBindingHash = prepareDesktopOAuthBrowserBinding(event);
|
|
381
|
+
desktopVerifierHash = await registerDesktopExchange(
|
|
382
|
+
flowId,
|
|
383
|
+
verifier,
|
|
384
|
+
desktopBrowserBindingHash,
|
|
385
|
+
);
|
|
386
|
+
} catch {
|
|
387
|
+
setResponseStatus(event, 400);
|
|
388
|
+
return { error: "Invalid desktop exchange challenge." };
|
|
389
|
+
}
|
|
390
|
+
}
|
|
298
391
|
const state = encodeOAuthState({
|
|
299
392
|
redirectUri,
|
|
300
393
|
owner: session.email,
|
|
@@ -302,6 +395,8 @@ export const getGoogleAddAccountUrl = defineEventHandler(
|
|
|
302
395
|
addAccount: true,
|
|
303
396
|
app: OAUTH_STATE_APP_ID,
|
|
304
397
|
flowId,
|
|
398
|
+
desktopVerifierHash,
|
|
399
|
+
desktopBrowserBindingHash,
|
|
305
400
|
});
|
|
306
401
|
const url = await getAuthUrl(
|
|
307
402
|
undefined,
|
|
@@ -333,22 +428,28 @@ export const handleGoogleAddAccountCallback = defineEventHandler(
|
|
|
333
428
|
);
|
|
334
429
|
desktop = state.desktop ?? false;
|
|
335
430
|
flowId = state.flowId;
|
|
431
|
+
if (
|
|
432
|
+
flowId &&
|
|
433
|
+
(!state.desktopVerifierHash ||
|
|
434
|
+
!state.desktopBrowserBindingHash ||
|
|
435
|
+
!matchesDesktopOAuthBrowserBinding(
|
|
436
|
+
event,
|
|
437
|
+
state.desktopBrowserBindingHash,
|
|
438
|
+
))
|
|
439
|
+
) {
|
|
440
|
+
throw new Error("Desktop OAuth browser binding is invalid.");
|
|
441
|
+
}
|
|
336
442
|
|
|
337
443
|
// Handle Google authorization errors (e.g. user denied access, invalid client)
|
|
338
444
|
const googleError = query.error as string | undefined;
|
|
339
445
|
if (googleError) {
|
|
340
446
|
const errorDesc =
|
|
341
447
|
(query.error_description as string | undefined) || googleError;
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
: `Connection failed: ${errorDesc}`;
|
|
348
|
-
return googleOAuthErrorResponse(event, new Error(userMessage), {
|
|
349
|
-
desktop,
|
|
350
|
-
flowId,
|
|
351
|
-
});
|
|
448
|
+
return googleOAuthErrorResponse(
|
|
449
|
+
event,
|
|
450
|
+
Object.assign(new Error(errorDesc), { oauthErrorCode: googleError }),
|
|
451
|
+
{ desktop, flowId },
|
|
452
|
+
);
|
|
352
453
|
}
|
|
353
454
|
|
|
354
455
|
const { redirectUri, owner: stateOwner } = state;
|
|
@@ -6,8 +6,11 @@ import { isSelfAddressedThread } from "@shared/self-notes.js";
|
|
|
6
6
|
import type { EmailMessage } from "@shared/types.js";
|
|
7
7
|
|
|
8
8
|
export const VIEW_QUERIES: Record<string, string> = {
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
// Keep sent replies in a matching Gmail thread. The local thread filter
|
|
10
|
+
// below excludes sent-only threads while preserving received inbox threads
|
|
11
|
+
// whose latest message was sent by the user.
|
|
12
|
+
inbox: "in:inbox",
|
|
13
|
+
unread: "is:unread in:inbox",
|
|
11
14
|
starred: "is:starred",
|
|
12
15
|
sent: "in:sent",
|
|
13
16
|
drafts: "in:drafts",
|
package/corpus/templates/mail/server/routes/[base]/_agent-native/google/add-account/auth-url.post.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "../../../../_agent-native/google/add-account/auth-url.post.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "../../../_agent-native/google/auth-url.post.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getGoogleAddAccountUrl as default } from "../../../../handlers/google-auth.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getGoogleAuthUrl as default } from "../../../handlers/google-auth.js";
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SIDEBAR_STATE_CHANGE_EVENT,
|
|
3
|
-
BuilderSetupCard,
|
|
4
3
|
sendToAgentChat,
|
|
5
4
|
setAgentChatContextItem,
|
|
6
5
|
useAgentEngineConfigured,
|
|
@@ -8466,23 +8465,12 @@ function CreatePlanDialog({
|
|
|
8466
8465
|
</DialogDescription>
|
|
8467
8466
|
</DialogHeader>
|
|
8468
8467
|
<div className="grid gap-3">
|
|
8469
|
-
{canCreate && agentMissing ? (
|
|
8470
|
-
<BuilderSetupCard
|
|
8471
|
-
fullWidth
|
|
8472
|
-
onConnected={() =>
|
|
8473
|
-
window.dispatchEvent(
|
|
8474
|
-
new Event("agent-engine:configured-changed"),
|
|
8475
|
-
)
|
|
8476
|
-
}
|
|
8477
|
-
/>
|
|
8478
|
-
) : null}
|
|
8479
8468
|
<div className="rounded-xl border border-border bg-background p-2 shadow-sm">
|
|
8480
8469
|
<PromptComposer
|
|
8481
8470
|
autoFocus
|
|
8482
8471
|
disabled={composerLocked}
|
|
8483
8472
|
attachmentsEnabled={false}
|
|
8484
8473
|
showModelSelector={false}
|
|
8485
|
-
modelStatusChecksEnabled={false}
|
|
8486
8474
|
placeholder={t("plansPage.create.placeholder")}
|
|
8487
8475
|
draftScope="plans:create-plan"
|
|
8488
8476
|
initialText={promptSeed}
|