@agent-native/core 0.18.1 → 0.19.1
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/README.md +1 -11
- package/dist/a2a/caller-auth.d.ts +1 -0
- package/dist/a2a/caller-auth.d.ts.map +1 -1
- package/dist/a2a/caller-auth.js +1 -1
- package/dist/a2a/caller-auth.js.map +1 -1
- package/dist/a2a/client.d.ts +7 -0
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +3 -0
- package/dist/a2a/client.js.map +1 -1
- package/dist/agent/production-agent.d.ts +1 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +34 -2
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/cli/code-agent-executor.d.ts.map +1 -1
- package/dist/cli/code-agent-executor.js +47 -256
- package/dist/cli/code-agent-executor.js.map +1 -1
- package/dist/cli/connect.d.ts +94 -0
- package/dist/cli/connect.d.ts.map +1 -0
- package/dist/cli/connect.js +443 -0
- package/dist/cli/connect.js.map +1 -0
- package/dist/cli/index.js +16 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp-config-writers.d.ts +71 -0
- package/dist/cli/mcp-config-writers.d.ts.map +1 -0
- package/dist/cli/mcp-config-writers.js +210 -0
- package/dist/cli/mcp-config-writers.js.map +1 -0
- package/dist/client/AgentPanel.d.ts +3 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +4 -4
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +3 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +22 -66
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +4 -1
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/composer/PromptComposer.d.ts +6 -1
- package/dist/client/composer/PromptComposer.d.ts.map +1 -1
- package/dist/client/composer/PromptComposer.js +5 -4
- package/dist/client/composer/PromptComposer.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts +6 -1
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +20 -10
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/conversation/AgentConversation.d.ts +18 -0
- package/dist/client/conversation/AgentConversation.d.ts.map +1 -0
- package/dist/client/conversation/AgentConversation.js +94 -0
- package/dist/client/conversation/AgentConversation.js.map +1 -0
- package/dist/client/conversation/AgentConversation.spec.d.ts +2 -0
- package/dist/client/conversation/AgentConversation.spec.d.ts.map +1 -0
- package/dist/client/conversation/AgentConversation.spec.js +69 -0
- package/dist/client/conversation/AgentConversation.spec.js.map +1 -0
- package/dist/client/conversation/index.d.ts +4 -0
- package/dist/client/conversation/index.d.ts.map +1 -0
- package/dist/client/conversation/index.js +3 -0
- package/dist/client/conversation/index.js.map +1 -0
- package/dist/client/conversation/types.d.ts +54 -0
- package/dist/client/conversation/types.d.ts.map +1 -0
- package/dist/client/conversation/types.js +2 -0
- package/dist/client/conversation/types.js.map +1 -0
- package/dist/client/conversation/use-near-bottom-autoscroll.d.ts +15 -0
- package/dist/client/conversation/use-near-bottom-autoscroll.d.ts.map +1 -0
- package/dist/client/conversation/use-near-bottom-autoscroll.js +66 -0
- package/dist/client/conversation/use-near-bottom-autoscroll.js.map +1 -0
- package/dist/client/dynamic-suggestions.d.ts +43 -0
- package/dist/client/dynamic-suggestions.d.ts.map +1 -0
- package/dist/client/dynamic-suggestions.js +344 -0
- package/dist/client/dynamic-suggestions.js.map +1 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +2 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/resources/ResourceTree.d.ts.map +1 -1
- package/dist/client/resources/ResourceTree.js +2 -2
- package/dist/client/resources/ResourceTree.js.map +1 -1
- package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
- package/dist/client/resources/ResourcesPanel.js +4 -28
- package/dist/client/resources/ResourcesPanel.js.map +1 -1
- package/dist/client/settings/SettingsPanel.js +2 -2
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/code-agents/index.d.ts +1 -0
- package/dist/code-agents/index.d.ts.map +1 -1
- package/dist/code-agents/index.js +1 -0
- package/dist/code-agents/index.js.map +1 -1
- package/dist/code-agents/transcript-normalizer.d.ts +50 -0
- package/dist/code-agents/transcript-normalizer.d.ts.map +1 -0
- package/dist/code-agents/transcript-normalizer.js +356 -0
- package/dist/code-agents/transcript-normalizer.js.map +1 -0
- package/dist/coding-tools/index.d.ts +31 -0
- package/dist/coding-tools/index.d.ts.map +1 -0
- package/dist/coding-tools/index.js +411 -0
- package/dist/coding-tools/index.js.map +1 -0
- package/dist/extensions/schema.d.ts +1 -1
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +30 -0
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/mcp/builtin-tools.d.ts.map +1 -1
- package/dist/mcp/builtin-tools.js +85 -26
- package/dist/mcp/builtin-tools.js.map +1 -1
- package/dist/mcp/connect-route.d.ts +43 -0
- package/dist/mcp/connect-route.d.ts.map +1 -0
- package/dist/mcp/connect-route.js +744 -0
- package/dist/mcp/connect-route.js.map +1 -0
- package/dist/mcp/connect-store.d.ts +132 -0
- package/dist/mcp/connect-store.d.ts.map +1 -0
- package/dist/mcp/connect-store.js +434 -0
- package/dist/mcp/connect-store.js.map +1 -0
- package/dist/mcp/org-directory.d.ts +83 -0
- package/dist/mcp/org-directory.d.ts.map +1 -0
- package/dist/mcp/org-directory.js +201 -0
- package/dist/mcp/org-directory.js.map +1 -0
- package/dist/mcp/server.d.ts +38 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +208 -77
- package/dist/mcp/server.js.map +1 -1
- package/dist/scripts/dev/index.d.ts +6 -4
- package/dist/scripts/dev/index.d.ts.map +1 -1
- package/dist/scripts/dev/index.js +28 -13
- package/dist/scripts/dev/index.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +6 -6
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +32 -32
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-teams.js +2 -2
- package/dist/server/agent-teams.js.map +1 -1
- package/dist/server/agents-bundle.d.ts +3 -3
- package/dist/server/agents-bundle.js +5 -5
- package/dist/server/agents-bundle.js.map +1 -1
- package/dist/server/auth.d.ts +17 -0
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +149 -33
- package/dist/server/auth.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts +43 -0
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +25 -0
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts +12 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +42 -0
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/identity-sso-store.d.ts +86 -0
- package/dist/server/identity-sso-store.d.ts.map +1 -0
- package/dist/server/identity-sso-store.js +243 -0
- package/dist/server/identity-sso-store.js.map +1 -0
- package/dist/server/identity-sso.d.ts +78 -0
- package/dist/server/identity-sso.d.ts.map +1 -0
- package/dist/server/identity-sso.js +425 -0
- package/dist/server/identity-sso.js.map +1 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +2 -1
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/server/sentry.d.ts.map +1 -1
- package/dist/server/sentry.js +17 -2
- package/dist/server/sentry.js.map +1 -1
- package/dist/sharing/schema.d.ts +1 -1
- package/docs/content/client.md +15 -0
- package/docs/content/code-agents-ui.md +25 -4
- package/docs/content/cross-app-sso.md +118 -0
- package/docs/content/drop-in-agent.md +3 -1
- package/docs/content/external-agents.md +130 -51
- package/docs/content/frames.md +1 -1
- package/docs/content/migration-workbench.md +6 -1
- package/package.json +2 -1
package/dist/server/auth.js
CHANGED
|
@@ -47,6 +47,10 @@ import { extractOAuthStateAppId } from "../shared/oauth-state.js";
|
|
|
47
47
|
import { isValidWorkspaceAppIdFormat } from "../shared/workspace-app-id.js";
|
|
48
48
|
import { normalizeWorkspaceAppAudience, workspaceAppAudienceFromEnv, workspaceAppRouteAccessFromEnv, } from "../shared/workspace-app-audience.js";
|
|
49
49
|
import { BUILDER_CONNECT_OWNER_COOKIE, BUILDER_CONNECT_PARAM, BUILDER_STATE_PARAM, verifyBuilderCallbackStateAndGetOwner, verifyBuilderConnectTokenAndGetOwner, } from "./builder-browser.js";
|
|
50
|
+
// Pure env-read feature switch from a leaf module (no dependency back on
|
|
51
|
+
// auth.ts), so the guard and the SSO route handler share one validator and
|
|
52
|
+
// can never disagree about whether federated SSO is enabled.
|
|
53
|
+
import { isIdentitySsoEnabled } from "./identity-sso-store.js";
|
|
50
54
|
/**
|
|
51
55
|
* Get the configured session max age. Desktop SSO broker writes from
|
|
52
56
|
* OAuth flows read this so expiration stays consistent with the cookie.
|
|
@@ -310,6 +314,39 @@ export function getConfiguredLoginHtml(event) {
|
|
|
310
314
|
const rawPath = queryStart >= 0 ? url.slice(0, queryStart) : url;
|
|
311
315
|
return config.getLoginHtml?.(event, rawPath) ?? config.loginHtml ?? null;
|
|
312
316
|
}
|
|
317
|
+
/**
|
|
318
|
+
* True only when the request originates from the local machine — the raw
|
|
319
|
+
* socket peer is `127.0.0.0/8`, `::1`, or the IPv4-mapped `::ffff:127.0.0.1`
|
|
320
|
+
* (an optional IPv6 zone id like `fe80::1%en0` is stripped first).
|
|
321
|
+
*
|
|
322
|
+
* `getRequestIP(event)` is called WITHOUT `{ xForwardedFor: true }`, so it
|
|
323
|
+
* returns the real connection peer and never an attacker-controlled
|
|
324
|
+
* `X-Forwarded-For` value — a remote client cannot spoof its way past this.
|
|
325
|
+
* Used to scope local-only conveniences (the desktop SSO broker and the dev
|
|
326
|
+
* auto-account) so a directly network-reachable dev server never exposes
|
|
327
|
+
* them to a remote visitor. NOTE: a reverse proxy / tunnel that connects to
|
|
328
|
+
* the dev server over localhost still appears as loopback, so this is a
|
|
329
|
+
* necessary but not sufficient gate — callers pair it with NODE_ENV and,
|
|
330
|
+
* for the dev account, a throwaway per-DB password.
|
|
331
|
+
*/
|
|
332
|
+
export function isLoopbackAddress(ip) {
|
|
333
|
+
// Strip an optional IPv6 zone id (e.g. "fe80::1%en0") before comparing.
|
|
334
|
+
const normalised = (ip ?? "").split("%")[0];
|
|
335
|
+
return (normalised === "127.0.0.1" ||
|
|
336
|
+
normalised === "::1" ||
|
|
337
|
+
normalised === "::ffff:127.0.0.1" ||
|
|
338
|
+
normalised.startsWith("127."));
|
|
339
|
+
}
|
|
340
|
+
function isLoopbackRequest(event) {
|
|
341
|
+
let ip;
|
|
342
|
+
try {
|
|
343
|
+
ip = getRequestIP(event) ?? undefined;
|
|
344
|
+
}
|
|
345
|
+
catch {
|
|
346
|
+
ip = undefined;
|
|
347
|
+
}
|
|
348
|
+
return isLoopbackAddress(ip);
|
|
349
|
+
}
|
|
313
350
|
/**
|
|
314
351
|
* Read the desktop-SSO broker file, but only if the request is plausibly
|
|
315
352
|
* from the Electron desktop app *and* coming from the local machine.
|
|
@@ -329,21 +366,7 @@ async function readDesktopSsoSafely(event) {
|
|
|
329
366
|
return null;
|
|
330
367
|
if (!isElectronRequest(event))
|
|
331
368
|
return null;
|
|
332
|
-
|
|
333
|
-
let ip;
|
|
334
|
-
try {
|
|
335
|
-
ip = getRequestIP(event) ?? undefined;
|
|
336
|
-
}
|
|
337
|
-
catch {
|
|
338
|
-
ip = undefined;
|
|
339
|
-
}
|
|
340
|
-
// Strip an optional zone id (e.g. "fe80::1%en0") before comparing.
|
|
341
|
-
const normalised = (ip ?? "").split("%")[0];
|
|
342
|
-
const isLoopback = normalised === "127.0.0.1" ||
|
|
343
|
-
normalised === "::1" ||
|
|
344
|
-
normalised === "::ffff:127.0.0.1" ||
|
|
345
|
-
normalised.startsWith("127.");
|
|
346
|
-
if (!isLoopback)
|
|
369
|
+
if (!isLoopbackRequest(event))
|
|
347
370
|
return null;
|
|
348
371
|
return await readDesktopSso();
|
|
349
372
|
}
|
|
@@ -452,7 +475,7 @@ const EXPECTED_AUTH_FAILURE_PATTERNS = [
|
|
|
452
475
|
/already\s+(exists|registered|in\s+use)/i,
|
|
453
476
|
/not\s+verified/i,
|
|
454
477
|
];
|
|
455
|
-
function isExpectedAuthFailure(error) {
|
|
478
|
+
export function isExpectedAuthFailure(error) {
|
|
456
479
|
const msg = error?.message;
|
|
457
480
|
if (typeof msg !== "string")
|
|
458
481
|
return false;
|
|
@@ -912,6 +935,43 @@ function createAuthGuardFn() {
|
|
|
912
935
|
if (p === "/_agent-native/mcp") {
|
|
913
936
|
return;
|
|
914
937
|
}
|
|
938
|
+
// MCP connect — frictionless external-agent connection. Like /open
|
|
939
|
+
// above, the connect *page* resolves the browser session itself and
|
|
940
|
+
// serves its own login form when unauthenticated (so the post-login
|
|
941
|
+
// reload returns to the same URL, carrying the device user_code in the
|
|
942
|
+
// query). The two unauthenticated device endpoints below are the CLI's
|
|
943
|
+
// OAuth-style polling pair: `device/start` (mint a device+user code) and
|
|
944
|
+
// `device/poll` (exchange an approved code for the token) — both must be
|
|
945
|
+
// reachable without a browser session because the CLI has none. They are
|
|
946
|
+
// protected by short-TTL, single-use, crypto-random codes + a creation
|
|
947
|
+
// rate-limit, not cookies.
|
|
948
|
+
//
|
|
949
|
+
// Everything that MINTS or MUTATES on behalf of the user — `/token`,
|
|
950
|
+
// `/device/authorize`, `/tokens`, `/tokens/revoke` — is intentionally
|
|
951
|
+
// NOT bypassed: the guard's default 401-for-/_agent-native/* is the
|
|
952
|
+
// correct gate for them. Those are POSTed by the in-page fetch, which
|
|
953
|
+
// carries the session cookie, so the guard (which only 401s when there
|
|
954
|
+
// is no session) lets the authenticated same-origin request through and
|
|
955
|
+
// the handler then re-checks the session itself (defense in depth).
|
|
956
|
+
if (p === "/_agent-native/mcp/connect" ||
|
|
957
|
+
p === "/_agent-native/mcp/connect/device/start" ||
|
|
958
|
+
p === "/_agent-native/mcp/connect/device/poll") {
|
|
959
|
+
return;
|
|
960
|
+
}
|
|
961
|
+
// Cross-app SSO ("Sign in with Agent-Native") — CLIENT side. Both the
|
|
962
|
+
// `/login` entry point and the `/callback` (hit by a user who is, by
|
|
963
|
+
// definition, NOT yet signed in to THIS app) must bypass the blanket
|
|
964
|
+
// 401-for-/_agent-native/*: they resolve / mint the browser session
|
|
965
|
+
// themselves and verify a signature-bound, single-use, CSRF-stated
|
|
966
|
+
// hub token — not a cookie. This bypass is GATED on the opt-in env var
|
|
967
|
+
// so an unset `AGENT_NATIVE_IDENTITY_HUB_URL` is a true no-op (the
|
|
968
|
+
// guard's behaviour is byte-for-byte unchanged when SSO is off). The
|
|
969
|
+
// handler itself 404s when disabled as defence in depth.
|
|
970
|
+
if (isIdentitySsoEnabled() &&
|
|
971
|
+
(p === "/_agent-native/identity/login" ||
|
|
972
|
+
p === "/_agent-native/identity/callback")) {
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
915
975
|
// Internal processor endpoint for the A2A async-mode fanout. Mirrors the
|
|
916
976
|
// integration webhook fanout: when `message/send` is called with
|
|
917
977
|
// `async: true`, the JSON-RPC handler enqueues to a2a_tasks and self-
|
|
@@ -1031,7 +1091,8 @@ function createAuthGuardFn() {
|
|
|
1031
1091
|
// validator (a bare `dev@local` has no TLD and is rejected as INVALID_EMAIL,
|
|
1032
1092
|
// which silently broke the zero-setup auto-sign-in on every fresh dev DB).
|
|
1033
1093
|
const AUTO_DEV_ACCOUNT_EMAIL = "dev@local.test";
|
|
1034
|
-
|
|
1094
|
+
// No fixed password: maybeAutoCreateDevSession mints a random one per DB
|
|
1095
|
+
// and prints it to the console once (see there).
|
|
1035
1096
|
// Pre-fix local dev DBs may already contain a `dev@local` user. Treat that
|
|
1036
1097
|
// legacy address as the dev account too, so the "any real users?" check
|
|
1037
1098
|
// below doesn't mistake the old auto-account for a real signup (which would
|
|
@@ -1054,19 +1115,31 @@ const LEGACY_AUTO_DEV_ACCOUNT_EMAIL = "dev@local";
|
|
|
1054
1115
|
* leaves the user on the regular sign-in form; without this guard the
|
|
1055
1116
|
* post-logout reload would silently re-create the session.
|
|
1056
1117
|
*
|
|
1057
|
-
*
|
|
1058
|
-
*
|
|
1059
|
-
*
|
|
1060
|
-
*
|
|
1061
|
-
*
|
|
1062
|
-
*
|
|
1063
|
-
*
|
|
1118
|
+
* Hardening (this is a convenience, not an auth bypass — it uses the
|
|
1119
|
+
* real Better Auth sign-up/sign-in, but a known-credential local account
|
|
1120
|
+
* is still worth not shipping):
|
|
1121
|
+
* - **Loopback only.** Gated on `isLoopbackRequest`, so a tunnelled /
|
|
1122
|
+
* reverse-proxied / misconfigured-non-prod dev server never auto-signs
|
|
1123
|
+
* in a directly-remote visitor (mirrors the desktop SSO broker).
|
|
1124
|
+
* - **Random per-DB password.** The account password is freshly
|
|
1125
|
+
* generated on creation and printed to the server console exactly
|
|
1126
|
+
* once — there is no source-code-known credential. After logout the
|
|
1127
|
+
* auto-flow won't refire (dev row exists), so signing back in uses
|
|
1128
|
+
* that printed password; lost it ⇒ drop the row or wipe the local DB.
|
|
1129
|
+
* - **NODE_ENV.** Still gated on development/test.
|
|
1130
|
+
*
|
|
1131
|
+
* Set `AGENT_NATIVE_DISABLE_AUTO_DEV_ACCOUNT=1` to opt out entirely
|
|
1132
|
+
* (useful for tests that exercise the unauthenticated branch).
|
|
1064
1133
|
*/
|
|
1065
1134
|
async function maybeAutoCreateDevSession(event, redirectTo) {
|
|
1066
1135
|
if (!isDevEnvironment())
|
|
1067
1136
|
return null;
|
|
1068
1137
|
if (process.env.AGENT_NATIVE_DISABLE_AUTO_DEV_ACCOUNT === "1")
|
|
1069
1138
|
return null;
|
|
1139
|
+
// Local machine only: never auto-sign-in a remote visitor, even if a
|
|
1140
|
+
// dev server is exposed (tunnel, reverse proxy, misconfigured NODE_ENV).
|
|
1141
|
+
if (!isLoopbackRequest(event))
|
|
1142
|
+
return null;
|
|
1070
1143
|
try {
|
|
1071
1144
|
const db = getDbExec();
|
|
1072
1145
|
// Exclude BOTH the current and the legacy dev-account email so a
|
|
@@ -1097,14 +1170,21 @@ async function maybeAutoCreateDevSession(event, redirectTo) {
|
|
|
1097
1170
|
const auth = await getBetterAuth();
|
|
1098
1171
|
if (!auth)
|
|
1099
1172
|
return null;
|
|
1100
|
-
//
|
|
1101
|
-
//
|
|
1102
|
-
//
|
|
1173
|
+
// Random per-DB password — there is no source-code-known credential
|
|
1174
|
+
// for this account. Printed once below so the developer can sign back
|
|
1175
|
+
// in after logout (the auto-flow won't refire while the dev row
|
|
1176
|
+
// exists).
|
|
1177
|
+
const devPassword = crypto.randomBytes(18).toString("base64url");
|
|
1178
|
+
// The dev account does not exist at this point (the devUsers check
|
|
1179
|
+
// above returned early otherwise). The "already exists" swallow only
|
|
1180
|
+
// matters under a rare concurrent first-hit race — in that case the
|
|
1181
|
+
// sign-in below fails the password check and we return null, leaving
|
|
1182
|
+
// the racing request that already won to keep the session.
|
|
1103
1183
|
try {
|
|
1104
1184
|
await auth.api.signUpEmail({
|
|
1105
1185
|
body: {
|
|
1106
1186
|
email: AUTO_DEV_ACCOUNT_EMAIL,
|
|
1107
|
-
password:
|
|
1187
|
+
password: devPassword,
|
|
1108
1188
|
name: "Dev",
|
|
1109
1189
|
},
|
|
1110
1190
|
});
|
|
@@ -1116,17 +1196,26 @@ async function maybeAutoCreateDevSession(event, redirectTo) {
|
|
|
1116
1196
|
const result = await auth.api.signInEmail({
|
|
1117
1197
|
body: {
|
|
1118
1198
|
email: AUTO_DEV_ACCOUNT_EMAIL,
|
|
1119
|
-
password:
|
|
1199
|
+
password: devPassword,
|
|
1120
1200
|
},
|
|
1121
1201
|
});
|
|
1122
1202
|
if (!result?.token)
|
|
1123
1203
|
return null;
|
|
1124
1204
|
setFrameworkSessionCookie(event, result.token);
|
|
1125
1205
|
await addSession(result.token, AUTO_DEV_ACCOUNT_EMAIL);
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1206
|
+
// Print the throwaway credential exactly once so the developer can
|
|
1207
|
+
// sign back in manually after logout (auto-flow won't refire once the
|
|
1208
|
+
// dev row exists). Local console only — never Sentry.
|
|
1209
|
+
console.log(`\n[agent-native] Local dev auto-login ready.\n` +
|
|
1210
|
+
` email: ${AUTO_DEV_ACCOUNT_EMAIL}\n` +
|
|
1211
|
+
` password: ${devPassword}\n` +
|
|
1212
|
+
` (random, this DB only — needed to sign back in after logout.\n` +
|
|
1213
|
+
` Set AGENT_NATIVE_DISABLE_AUTO_DEV_ACCOUNT=1 to disable.)\n`);
|
|
1214
|
+
// Emit the session cookie ON the 302 itself. Returning a bare
|
|
1215
|
+
// `new Response(...)` here drops the cookie staged on event.node.res
|
|
1216
|
+
// (see redirectWithStagedCookies), so the developer would 302 to the
|
|
1217
|
+
// app and immediately bounce back to the login form.
|
|
1218
|
+
return redirectWithStagedCookies(event, redirectTo);
|
|
1130
1219
|
}
|
|
1131
1220
|
catch (e) {
|
|
1132
1221
|
// Local-dev only — log to console for debugging, but don't surface
|
|
@@ -1279,6 +1368,33 @@ export function setFrameworkSessionCookie(event, token) {
|
|
|
1279
1368
|
maxAge: sessionMaxAge,
|
|
1280
1369
|
});
|
|
1281
1370
|
}
|
|
1371
|
+
/**
|
|
1372
|
+
* Build a redirect `Response` that carries whatever `Set-Cookie` headers were
|
|
1373
|
+
* just staged on the event (e.g. by `setFrameworkSessionCookie`).
|
|
1374
|
+
*
|
|
1375
|
+
* h3 v2's `setCookie` appends the cookie onto `event.res.headers`. When a
|
|
1376
|
+
* handler returns a plain object/string, h3's `prepareResponse` merges those
|
|
1377
|
+
* staged headers into the synthesized response, so the cookie survives. But
|
|
1378
|
+
* when a handler returns a web `Response`, `prepareResponse` only merges the
|
|
1379
|
+
* staged headers if the Response is 2xx — its `!val.ok` early-return hands a
|
|
1380
|
+
* non-2xx Response (like a 302) straight back WITHOUT merging. A bare
|
|
1381
|
+
* `new Response("", { status: 302, headers: { Location } })` therefore 302s
|
|
1382
|
+
* the browser with no session cookie, so the zero-setup dev auto-sign-in
|
|
1383
|
+
* bounces straight back to the login form.
|
|
1384
|
+
*
|
|
1385
|
+
* Mirroring the staged cookies onto the redirect Response's own headers makes
|
|
1386
|
+
* them part of the Response that's returned as-is, so the 302 actually
|
|
1387
|
+
* carries the session cookie. (`event.res.headers` is also left intact for
|
|
1388
|
+
* any non-Response continuation path; h3 only skips the merge for the
|
|
1389
|
+
* Response branch, so there's no double-emit.)
|
|
1390
|
+
*/
|
|
1391
|
+
function redirectWithStagedCookies(event, location, status = 302) {
|
|
1392
|
+
const headers = new Headers({ Location: location });
|
|
1393
|
+
const staged = event.res?.headers?.getSetCookie?.() ?? [];
|
|
1394
|
+
for (const cookie of staged)
|
|
1395
|
+
headers.append("set-cookie", cookie);
|
|
1396
|
+
return new Response("", { status, headers });
|
|
1397
|
+
}
|
|
1282
1398
|
function isHttpsRequest(event) {
|
|
1283
1399
|
try {
|
|
1284
1400
|
const xfProto = getHeader(event, "x-forwarded-proto");
|