@agent-native/core 0.7.37 → 0.7.39

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.
@@ -1 +1 @@
1
- {"version":3,"file":"framework-request-handler.d.ts","sourceRoot":"","sources":["../../src/server/framework-request-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,YAAY,EAAW,MAAM,IAAI,CAAC;AAMhD,QAAA,MAAM,gBAAgB,mBAAmB,CAAC;AAyC1C;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IAC/C,GAAG,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;CAClC;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,GAAG,GAAG,SAAS,CA2CjD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAOjE;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAiB3E;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAMpE;AAgQD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,GAAG,CAAC,CAyBd;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"framework-request-handler.d.ts","sourceRoot":"","sources":["../../src/server/framework-request-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,YAAY,EAAW,MAAM,IAAI,CAAC;AAMhD,QAAA,MAAM,gBAAgB,mBAAmB,CAAC;AAiD1C;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IAC/C,GAAG,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;CAClC;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,GAAG,GAAG,SAAS,CA2CjD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAOjE;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAiB3E;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAMpE;AAgQD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,GAAG,CAAC,CAyBd;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
@@ -3,6 +3,7 @@ import { getMissingDefaultPlugins } from "../deploy/route-discovery.js";
3
3
  const BOOTSTRAPPED = new WeakSet();
4
4
  const IN_BOOTSTRAP = new WeakSet();
5
5
  const FRAMEWORK_PREFIX = "/_agent-native";
6
+ const WELL_KNOWN_PREFIX = "/.well-known";
6
7
  const APP_SHIM_KEY = "_agentNativeH3Shim";
7
8
  const BOOTSTRAP_PROMISE_KEY = "_agentNativeBootstrapPromise";
8
9
  const PLUGIN_READY_KEY = "_agentNativePluginReadyPromise";
@@ -20,12 +21,16 @@ function getAppBasePath() {
20
21
  function pathMatchesPrefix(reqPath, prefix) {
21
22
  return reqPath === prefix || reqPath.startsWith(prefix + "/");
22
23
  }
24
+ function supportsAppBasePathMount(path) {
25
+ return (pathMatchesPrefix(path, FRAMEWORK_PREFIX) ||
26
+ pathMatchesPrefix(path, WELL_KNOWN_PREFIX));
27
+ }
23
28
  function resolveMountMatch(reqPath, path) {
24
29
  if (pathMatchesPrefix(reqPath, path)) {
25
30
  return { mountPath: path, strippedPath: reqPath.slice(path.length) || "/" };
26
31
  }
27
32
  const appBasePath = getAppBasePath();
28
- if (!appBasePath || !path.startsWith(FRAMEWORK_PREFIX))
33
+ if (!appBasePath || !supportsAppBasePathMount(path))
29
34
  return null;
30
35
  const prefixedPath = `${appBasePath}${path}`;
31
36
  if (!pathMatchesPrefix(reqPath, prefixedPath))
@@ -1 +1 @@
1
- {"version":3,"file":"framework-request-handler.js","sourceRoot":"","sources":["../../src/server/framework-request-handler.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Framework request handler — registers framework routes on Nitro's h3 instance.\n *\n * Nitro 3 exposes its h3 app as `nitroApp.h3`. We register framework routes\n * directly on it as middleware (`nitroApp.h3[\"~middleware\"]`), giving each\n * plugin a path-prefix-matched handler that runs before any file-based route.\n *\n * Plugins call `getH3App(nitroApp).use(path, handler)` exactly like h3 v1's\n * `app.use()` — the wrapper translates that into v2 middleware registration.\n *\n * Default plugins that the template doesn't provide are auto-mounted on the\n * first call to `getH3App()` per nitroApp instance.\n */\nimport type { EventHandler, H3Event } from \"h3\";\nimport { setResponseHeader, setResponseStatus } from \"h3\";\nimport { getMissingDefaultPlugins } from \"../deploy/route-discovery.js\";\n\nconst BOOTSTRAPPED = new WeakSet<object>();\nconst IN_BOOTSTRAP = new WeakSet<object>();\nconst FRAMEWORK_PREFIX = \"/_agent-native\";\nconst APP_SHIM_KEY = \"_agentNativeH3Shim\";\nconst BOOTSTRAP_PROMISE_KEY = \"_agentNativeBootstrapPromise\";\nconst PLUGIN_READY_KEY = \"_agentNativePluginReadyPromise\";\n\nfunction normalizeAppBasePath(value: string | undefined): string {\n if (!value || value === \"/\") return \"\";\n const trimmed = value.trim();\n if (!trimmed || trimmed === \"/\") return \"\";\n return `/${trimmed.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\")}`;\n}\n\nfunction getAppBasePath(): string {\n return normalizeAppBasePath(\n process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH,\n );\n}\n\nfunction pathMatchesPrefix(reqPath: string, prefix: string): boolean {\n return reqPath === prefix || reqPath.startsWith(prefix + \"/\");\n}\n\nfunction resolveMountMatch(\n reqPath: string,\n path: string,\n): { mountPath: string; strippedPath: string } | null {\n if (pathMatchesPrefix(reqPath, path)) {\n return { mountPath: path, strippedPath: reqPath.slice(path.length) || \"/\" };\n }\n\n const appBasePath = getAppBasePath();\n if (!appBasePath || !path.startsWith(FRAMEWORK_PREFIX)) return null;\n\n const prefixedPath = `${appBasePath}${path}`;\n if (!pathMatchesPrefix(reqPath, prefixedPath)) return null;\n return {\n mountPath: prefixedPath,\n strippedPath: reqPath.slice(prefixedPath.length) || \"/\",\n };\n}\n\n/**\n * Wrapper around Nitro's h3 instance that exposes a v1-style `.use()` API\n * for registering path-prefix middleware.\n */\nexport interface H3AppShim {\n use(path: string, handler: EventHandler): void;\n use(handler: EventHandler): void;\n}\n\n/**\n * Get (or create) the shared H3 app wrapper for a nitroApp. Plugins use this\n * to register routes via `.use(path, handler)`.\n *\n * On the first call per nitroApp, we kick off auto-mounting any missing\n * default plugins. User-facing plugin factories (createAgentChatPlugin,\n * createAuthPlugin, etc.) await this bootstrap via `awaitBootstrap()` so the\n * default plugins finish registering middleware before requests arrive.\n */\nexport function getH3App(nitroApp: any): H3AppShim {\n if (!nitroApp) throw new Error(\"getH3App: nitroApp is required\");\n\n // Reuse the cached shim if we've wrapped this nitroApp before\n const cached = nitroApp[APP_SHIM_KEY] as H3AppShim | undefined;\n if (cached) return cached;\n\n const shim: H3AppShim = {\n use(arg1: string | EventHandler, arg2?: EventHandler) {\n const path = typeof arg1 === \"string\" ? arg1 : \"\";\n const handler = (typeof arg1 === \"string\" ? arg2 : arg1) as EventHandler;\n if (typeof handler !== \"function\") {\n throw new Error(\"getH3App.use: handler must be a function\");\n }\n registerMiddleware(nitroApp, path, handler);\n },\n };\n\n nitroApp[APP_SHIM_KEY] = shim;\n\n if (!BOOTSTRAPPED.has(nitroApp)) {\n BOOTSTRAPPED.add(nitroApp);\n nitroApp[BOOTSTRAP_PROMISE_KEY] = bootstrapDefaultPlugins(nitroApp).catch(\n (err) => {\n console.warn(\n \"[agent-native] Failed to auto-mount default plugins:\",\n (err as Error).message,\n );\n },\n );\n\n // Readiness gate: Nitro v3 doesn't await async plugins, so routes\n // registered inside an async plugin may not exist when the first\n // request arrives. This middleware holds /_agent-native requests\n // until all tracked plugin inits complete.\n registerMiddleware(nitroApp, FRAMEWORK_PREFIX, (async (event: H3Event) => {\n await awaitPluginsReady(nitroApp);\n // Fall through — the actual route handler runs next.\n return undefined;\n }) as EventHandler);\n }\n\n return shim;\n}\n\n/**\n * Wait for the framework's default-plugin bootstrap to complete.\n *\n * Called by user-facing plugin factories (`createAgentChatPlugin`, etc.) at\n * the top of their plugin function, so that by the time the function returns\n * — and Nitro starts accepting requests — all default plugins have finished\n * registering their middleware.\n *\n * No-op when called from inside the bootstrap itself (avoids deadlock when a\n * default plugin happens to be running as part of bootstrap).\n */\nexport async function awaitBootstrap(nitroApp: any): Promise<void> {\n if (!nitroApp || IN_BOOTSTRAP.has(nitroApp)) return;\n // Trigger bootstrap if it hasn't been already (idempotent — getH3App\n // creates the shim and kicks off bootstrap on first call).\n getH3App(nitroApp);\n const promise = nitroApp[BOOTSTRAP_PROMISE_KEY];\n if (promise) await promise;\n}\n\n/**\n * Track an async plugin's initialization promise. Nitro v3 calls plugins\n * synchronously and doesn't await async return values, so routes registered\n * inside an async plugin may not be ready when the first request arrives.\n *\n * Call this from the TOP of any async plugin so that the readiness gate\n * (installed by getH3App) can hold /_agent-native requests until the plugin\n * finishes mounting its routes.\n */\nexport function trackPluginInit(nitroApp: any, promise: Promise<void>): void {\n if (!nitroApp) return;\n // Attach a no-op catch so the promise doesn't surface as an unhandled\n // rejection when Nitro v3 drops the async return value. The actual error\n // is still observable when awaitPluginsReady() re-awaits the promise.\n const safe = promise.catch((err) => {\n console.error(\n \"[agent-native] Plugin init failed:\",\n (err as Error).message || err,\n );\n });\n const existing = nitroApp[PLUGIN_READY_KEY] as Promise<void>[] | undefined;\n if (existing) {\n existing.push(safe);\n } else {\n nitroApp[PLUGIN_READY_KEY] = [safe];\n }\n}\n\n/**\n * Await all tracked plugin initializations. Called by the readiness gate\n * middleware before dispatching framework routes.\n */\nexport async function awaitPluginsReady(nitroApp: any): Promise<void> {\n const promises = nitroApp[PLUGIN_READY_KEY] as Promise<void>[] | undefined;\n if (promises?.length) {\n await Promise.all(promises);\n nitroApp[PLUGIN_READY_KEY] = [];\n }\n}\n\n/**\n * Register a path-prefix middleware on Nitro's h3 instance.\n *\n * The middleware:\n * - Returns `next()` (continues) if the request path doesn't match.\n * - Otherwise dispatches to the handler. If the handler returns a value,\n * it short-circuits the request. If it returns undefined, next() runs.\n *\n * Path matching emulates h3 v1's `app.use(path, ...)` behavior:\n * - Exact-match prefix: `/foo` matches `/foo`, `/foo/bar`, but not `/foobar`\n * - Empty path: middleware runs on every request\n */\nfunction registerMiddleware(\n nitroApp: any,\n path: string,\n handler: EventHandler,\n) {\n const h3 = nitroApp.h3;\n if (!h3 || !Array.isArray(h3[\"~middleware\"])) {\n throw new Error(\n \"[agent-native] Cannot register route: nitroApp.h3 is not available. \" +\n \"Make sure you're calling getH3App() from inside a Nitro plugin.\",\n );\n }\n\n const middleware = async (event: H3Event, next: () => any) => {\n let originalPathname: string | undefined;\n let originalEventPath: string | undefined;\n let hadEventPath = false;\n const restoreOriginalPath = () => {\n if (originalPathname !== undefined) {\n try {\n event.url.pathname = originalPathname;\n } catch {\n // ignore\n }\n originalPathname = undefined;\n }\n if (hadEventPath) {\n try {\n (event as any).path = originalEventPath;\n } catch {\n // ignore\n }\n } else {\n try {\n delete (event as any).path;\n } catch {\n // ignore\n }\n }\n };\n if (path) {\n const reqPath = event.url?.pathname ?? \"\";\n const match = resolveMountMatch(reqPath, path);\n if (!match) {\n return next();\n }\n // Strip the mount prefix from event.url.pathname so handlers that\n // dispatch sub-routes can read `event.path` (or `event.url.pathname`)\n // and see the path RELATIVE to their mount point — matching h3 v1's\n // `app.use(path, handler)` semantics.\n const eventAny = event as any;\n hadEventPath = \"path\" in eventAny;\n originalEventPath = eventAny.path;\n try {\n originalPathname = event.url.pathname;\n // Save the full path in context so handlers that need the original URL\n // (e.g. Better Auth, which extracts its own basePath prefix) can\n // reconstruct a Request with the un-stripped URL.\n eventAny.context = eventAny.context ?? {};\n eventAny.context._mountedPathname = originalPathname;\n eventAny.context._mountPrefix = match.mountPath;\n event.url.pathname = match.strippedPath;\n eventAny.path = `${match.strippedPath}${event.url.search || \"\"}`;\n } catch {\n // event.url is read-only on some runtimes — fall through. Handlers\n // that don't depend on prefix stripping (most of them) still work.\n }\n }\n try {\n const result = await handler(event);\n if (result === undefined) {\n // Restore the original pathname BEFORE calling next() so downstream\n // middleware sees the full URL — not the stripped mount-relative path.\n // Matches h3 v2's own sub-app middleware pattern where the restore\n // happens inside the next() callback, not after it returns.\n restoreOriginalPath();\n return next();\n }\n return result;\n } catch (err) {\n // Log 500s to the server console so they're debuggable, and respond\n // with JSON instead of the default HTML error page so clients can\n // surface error messages. This only applies to routes mounted under\n // the framework prefix (or middleware mounted at `/`, for which we\n // still want visibility).\n const reqPath = originalPathname ?? event.url?.pathname ?? \"\";\n const e = err as any;\n const status =\n typeof e?.statusCode === \"number\"\n ? e.statusCode\n : typeof e?.status === \"number\"\n ? e.status\n : 500;\n console.error(\n `[agent-native] ${event.method ?? \"\"} ${reqPath} failed (${status}):`,\n e?.stack || e?.message || e,\n );\n try {\n setResponseStatus(event, status);\n setResponseHeader(event, \"content-type\", \"application/json\");\n } catch {\n // Response already sent — best effort.\n }\n return {\n error: e?.message || \"Internal server error\",\n // Only surface the stack to clients when explicitly enabled.\n // `NODE_ENV !== \"production\"` was unsafe — preview deploys and\n // any host that forgets to set NODE_ENV=production leaked stack\n // traces (file paths, dependency versions, internal route\n // topology) to anonymous callers. Operators who want stacks in\n // dev set `AGENT_NATIVE_DEBUG_ERRORS=1` explicitly.\n ...(status >= 500 &&\n process.env.AGENT_NATIVE_DEBUG_ERRORS === \"1\" &&\n e?.stack\n ? { stack: e.stack }\n : {}),\n };\n } finally {\n // Restore the original pathname so downstream middleware sees the\n // full URL.\n restoreOriginalPath();\n }\n };\n\n h3[\"~middleware\"].push(middleware);\n}\n\n/**\n * Auto-mount any default framework plugins that the template doesn't provide.\n *\n * Runs once per nitroApp on the first `getH3App()` call. Uses route-discovery\n * to find which default plugin stems are missing from `server/plugins/`, then\n * dynamically imports and mounts them. If a workspace core is present in the\n * ancestor chain, plugin slots the workspace core exports are mounted from\n * there instead of from @agent-native/core — this is the middle layer of the\n * three-layer inheritance model (app local > workspace core > framework).\n */\nasync function bootstrapDefaultPlugins(nitroApp: any): Promise<void> {\n IN_BOOTSTRAP.add(nitroApp);\n try {\n const cwd = process.cwd();\n const missing = await getMissingDefaultPlugins(cwd);\n if (missing.length === 0) return;\n\n // Lazy import to avoid circular dependency at module load time\n const serverModule = await import(\"./index.js\");\n const terminalModule = await import(\"../terminal/terminal-plugin.js\");\n const integrationsModule = await import(\"../integrations/plugin.js\");\n const orgModule = await import(\"../org/plugin.js\");\n const onboardingModule = await import(\"../onboarding/plugin.js\");\n\n const frameworkImpls: Record<\n string,\n ((nitroApp: any) => void | Promise<void>) | undefined\n > = {\n \"agent-chat\": (serverModule as any).defaultAgentChatPlugin,\n auth: (serverModule as any).defaultAuthPlugin,\n \"core-routes\": (serverModule as any).defaultCoreRoutesPlugin,\n integrations: (integrationsModule as any).defaultIntegrationsPlugin,\n onboarding: (onboardingModule as any).defaultOnboardingPlugin,\n org: (orgModule as any).defaultOrgPlugin,\n resources: (serverModule as any).defaultResourcesPlugin,\n terminal: (terminalModule as any).defaultTerminalPlugin,\n };\n\n // Workspace core layer: if the app is inside an enterprise monorepo with\n // `agent-native.workspaceCore` configured, pull in any plugin slots the\n // workspace core exports from its server entry. We dynamically import the\n // workspace core package at runtime.\n let workspaceImpls: Record<\n string,\n ((nitroApp: any) => void | Promise<void>) | undefined\n > = {};\n try {\n const { getWorkspaceCoreExports } =\n await import(\"../deploy/workspace-core.js\");\n const ws = await getWorkspaceCoreExports(cwd);\n if (ws && Object.keys(ws.plugins).length > 0) {\n try {\n const wsServerModule = await loadWorkspaceCoreServer(\n ws.packageName,\n ws.packageDir,\n );\n for (const [slot, exportName] of Object.entries(ws.plugins)) {\n if (!exportName) continue;\n const impl = (wsServerModule as any)[exportName];\n if (typeof impl === \"function\") {\n workspaceImpls[slot] = impl;\n }\n }\n if (process.env.DEBUG) {\n console.log(\n `[agent-native] Workspace core ${ws.packageName} provides plugin slots: ${Object.keys(workspaceImpls).join(\", \")}`,\n );\n }\n } catch (e) {\n const msg = (e as Error).message ?? \"\";\n // Common cause: workspace-core's package.json points \"./server\"\n // at a TS source file (the scaffold default), but Node can't\n // resolve relative `.js` imports inside it without a TS loader.\n // Tell the user to compile to dist/ rather than just dumping the\n // raw resolution error.\n const tsLoadHint = /\\.js' imported from .*\\.ts/.test(msg)\n ? \" — workspace-core src is TypeScript but isn't being compiled. \" +\n \"Run `pnpm --filter \" +\n ws.packageName +\n \" build` and point its `./server` export at dist/server/index.js.\"\n : \"\";\n console.warn(\n `[agent-native] Failed to load workspace core ${ws.packageName}/server: ${msg}${tsLoadHint}`,\n );\n }\n }\n } catch {\n // Workspace shared package isn't available (e.g. running on an edge\n // runtime without fs). Silently fall through to framework defaults.\n }\n\n if (process.env.DEBUG)\n console.log(\n `[agent-native] Auto-mounting ${missing.length} default plugin(s): ${missing.join(\", \")}`,\n );\n\n for (const stem of missing) {\n // Prefer workspace-core impl over framework default when both exist.\n const impl = workspaceImpls[stem] ?? frameworkImpls[stem];\n if (typeof impl === \"function\") {\n try {\n await impl(nitroApp);\n } catch (e) {\n console.warn(\n `[agent-native] Failed to auto-mount default plugin ${stem}:`,\n (e as Error).message,\n );\n }\n }\n }\n } finally {\n IN_BOOTSTRAP.delete(nitroApp);\n }\n}\n\n/**\n * Load a workspace-core's `/server` entry, transparently handling TS source.\n *\n * The scaffolded workspace-core template ships TS sources without a build\n * step (exports point at `./src/server/index.ts`), so plain `await import()`\n * blows up the moment Node hits a relative `.js` import inside (the standard\n * TS ESM convention) — and even before that, Node may resolve the package\n * relative to the framework's own location rather than the user's monorepo.\n *\n * We try Node's plain `import()` first (fastest path when the user has\n * compiled to dist/) and fall through to jiti on any error. jiti is anchored\n * to a real file inside the workspace-core's directory, so its module\n * resolution starts in the right node_modules tree (handles pnpm hoisting\n * and linked workspaces) AND handles TS source files + `.js` → `.ts` ESM\n * extension remapping.\n *\n * Edge runtimes without `fs` won't be able to load jiti at all; the outer\n * try/catch silently falls through to framework defaults in that case.\n */\nexport async function loadWorkspaceCoreServer(\n packageName: string,\n packageDir: string,\n): Promise<any> {\n let firstErr: unknown;\n try {\n return await import(/* @vite-ignore */ `${packageName}/server`);\n } catch (e) {\n firstErr = e;\n }\n\n try {\n const { createJiti } = await import(\"jiti\");\n const { pathToFileURL } = await import(\"node:url\");\n const path = await import(\"node:path\");\n // Anchor jiti to a real file inside the workspace-core package so its\n // module resolution starts in the right node_modules tree (handles pnpm\n // hoisting and linked workspaces).\n const anchor = pathToFileURL(\n path.join(packageDir, \"package.json\"),\n ).toString();\n const jiti = createJiti(anchor, { interopDefault: true });\n return await jiti.import(`${packageName}/server`);\n } catch (jitiErr) {\n // jiti also failed — rethrow the original Node error since it's usually\n // more informative about *why* the package wasn't resolvable.\n throw firstErr ?? jitiErr;\n }\n}\n\nexport { FRAMEWORK_PREFIX };\n"]}
1
+ {"version":3,"file":"framework-request-handler.js","sourceRoot":"","sources":["../../src/server/framework-request-handler.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Framework request handler — registers framework routes on Nitro's h3 instance.\n *\n * Nitro 3 exposes its h3 app as `nitroApp.h3`. We register framework routes\n * directly on it as middleware (`nitroApp.h3[\"~middleware\"]`), giving each\n * plugin a path-prefix-matched handler that runs before any file-based route.\n *\n * Plugins call `getH3App(nitroApp).use(path, handler)` exactly like h3 v1's\n * `app.use()` — the wrapper translates that into v2 middleware registration.\n *\n * Default plugins that the template doesn't provide are auto-mounted on the\n * first call to `getH3App()` per nitroApp instance.\n */\nimport type { EventHandler, H3Event } from \"h3\";\nimport { setResponseHeader, setResponseStatus } from \"h3\";\nimport { getMissingDefaultPlugins } from \"../deploy/route-discovery.js\";\n\nconst BOOTSTRAPPED = new WeakSet<object>();\nconst IN_BOOTSTRAP = new WeakSet<object>();\nconst FRAMEWORK_PREFIX = \"/_agent-native\";\nconst WELL_KNOWN_PREFIX = \"/.well-known\";\nconst APP_SHIM_KEY = \"_agentNativeH3Shim\";\nconst BOOTSTRAP_PROMISE_KEY = \"_agentNativeBootstrapPromise\";\nconst PLUGIN_READY_KEY = \"_agentNativePluginReadyPromise\";\n\nfunction normalizeAppBasePath(value: string | undefined): string {\n if (!value || value === \"/\") return \"\";\n const trimmed = value.trim();\n if (!trimmed || trimmed === \"/\") return \"\";\n return `/${trimmed.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\")}`;\n}\n\nfunction getAppBasePath(): string {\n return normalizeAppBasePath(\n process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH,\n );\n}\n\nfunction pathMatchesPrefix(reqPath: string, prefix: string): boolean {\n return reqPath === prefix || reqPath.startsWith(prefix + \"/\");\n}\n\nfunction supportsAppBasePathMount(path: string): boolean {\n return (\n pathMatchesPrefix(path, FRAMEWORK_PREFIX) ||\n pathMatchesPrefix(path, WELL_KNOWN_PREFIX)\n );\n}\n\nfunction resolveMountMatch(\n reqPath: string,\n path: string,\n): { mountPath: string; strippedPath: string } | null {\n if (pathMatchesPrefix(reqPath, path)) {\n return { mountPath: path, strippedPath: reqPath.slice(path.length) || \"/\" };\n }\n\n const appBasePath = getAppBasePath();\n if (!appBasePath || !supportsAppBasePathMount(path)) return null;\n\n const prefixedPath = `${appBasePath}${path}`;\n if (!pathMatchesPrefix(reqPath, prefixedPath)) return null;\n return {\n mountPath: prefixedPath,\n strippedPath: reqPath.slice(prefixedPath.length) || \"/\",\n };\n}\n\n/**\n * Wrapper around Nitro's h3 instance that exposes a v1-style `.use()` API\n * for registering path-prefix middleware.\n */\nexport interface H3AppShim {\n use(path: string, handler: EventHandler): void;\n use(handler: EventHandler): void;\n}\n\n/**\n * Get (or create) the shared H3 app wrapper for a nitroApp. Plugins use this\n * to register routes via `.use(path, handler)`.\n *\n * On the first call per nitroApp, we kick off auto-mounting any missing\n * default plugins. User-facing plugin factories (createAgentChatPlugin,\n * createAuthPlugin, etc.) await this bootstrap via `awaitBootstrap()` so the\n * default plugins finish registering middleware before requests arrive.\n */\nexport function getH3App(nitroApp: any): H3AppShim {\n if (!nitroApp) throw new Error(\"getH3App: nitroApp is required\");\n\n // Reuse the cached shim if we've wrapped this nitroApp before\n const cached = nitroApp[APP_SHIM_KEY] as H3AppShim | undefined;\n if (cached) return cached;\n\n const shim: H3AppShim = {\n use(arg1: string | EventHandler, arg2?: EventHandler) {\n const path = typeof arg1 === \"string\" ? arg1 : \"\";\n const handler = (typeof arg1 === \"string\" ? arg2 : arg1) as EventHandler;\n if (typeof handler !== \"function\") {\n throw new Error(\"getH3App.use: handler must be a function\");\n }\n registerMiddleware(nitroApp, path, handler);\n },\n };\n\n nitroApp[APP_SHIM_KEY] = shim;\n\n if (!BOOTSTRAPPED.has(nitroApp)) {\n BOOTSTRAPPED.add(nitroApp);\n nitroApp[BOOTSTRAP_PROMISE_KEY] = bootstrapDefaultPlugins(nitroApp).catch(\n (err) => {\n console.warn(\n \"[agent-native] Failed to auto-mount default plugins:\",\n (err as Error).message,\n );\n },\n );\n\n // Readiness gate: Nitro v3 doesn't await async plugins, so routes\n // registered inside an async plugin may not exist when the first\n // request arrives. This middleware holds /_agent-native requests\n // until all tracked plugin inits complete.\n registerMiddleware(nitroApp, FRAMEWORK_PREFIX, (async (event: H3Event) => {\n await awaitPluginsReady(nitroApp);\n // Fall through — the actual route handler runs next.\n return undefined;\n }) as EventHandler);\n }\n\n return shim;\n}\n\n/**\n * Wait for the framework's default-plugin bootstrap to complete.\n *\n * Called by user-facing plugin factories (`createAgentChatPlugin`, etc.) at\n * the top of their plugin function, so that by the time the function returns\n * — and Nitro starts accepting requests — all default plugins have finished\n * registering their middleware.\n *\n * No-op when called from inside the bootstrap itself (avoids deadlock when a\n * default plugin happens to be running as part of bootstrap).\n */\nexport async function awaitBootstrap(nitroApp: any): Promise<void> {\n if (!nitroApp || IN_BOOTSTRAP.has(nitroApp)) return;\n // Trigger bootstrap if it hasn't been already (idempotent — getH3App\n // creates the shim and kicks off bootstrap on first call).\n getH3App(nitroApp);\n const promise = nitroApp[BOOTSTRAP_PROMISE_KEY];\n if (promise) await promise;\n}\n\n/**\n * Track an async plugin's initialization promise. Nitro v3 calls plugins\n * synchronously and doesn't await async return values, so routes registered\n * inside an async plugin may not be ready when the first request arrives.\n *\n * Call this from the TOP of any async plugin so that the readiness gate\n * (installed by getH3App) can hold /_agent-native requests until the plugin\n * finishes mounting its routes.\n */\nexport function trackPluginInit(nitroApp: any, promise: Promise<void>): void {\n if (!nitroApp) return;\n // Attach a no-op catch so the promise doesn't surface as an unhandled\n // rejection when Nitro v3 drops the async return value. The actual error\n // is still observable when awaitPluginsReady() re-awaits the promise.\n const safe = promise.catch((err) => {\n console.error(\n \"[agent-native] Plugin init failed:\",\n (err as Error).message || err,\n );\n });\n const existing = nitroApp[PLUGIN_READY_KEY] as Promise<void>[] | undefined;\n if (existing) {\n existing.push(safe);\n } else {\n nitroApp[PLUGIN_READY_KEY] = [safe];\n }\n}\n\n/**\n * Await all tracked plugin initializations. Called by the readiness gate\n * middleware before dispatching framework routes.\n */\nexport async function awaitPluginsReady(nitroApp: any): Promise<void> {\n const promises = nitroApp[PLUGIN_READY_KEY] as Promise<void>[] | undefined;\n if (promises?.length) {\n await Promise.all(promises);\n nitroApp[PLUGIN_READY_KEY] = [];\n }\n}\n\n/**\n * Register a path-prefix middleware on Nitro's h3 instance.\n *\n * The middleware:\n * - Returns `next()` (continues) if the request path doesn't match.\n * - Otherwise dispatches to the handler. If the handler returns a value,\n * it short-circuits the request. If it returns undefined, next() runs.\n *\n * Path matching emulates h3 v1's `app.use(path, ...)` behavior:\n * - Exact-match prefix: `/foo` matches `/foo`, `/foo/bar`, but not `/foobar`\n * - Empty path: middleware runs on every request\n */\nfunction registerMiddleware(\n nitroApp: any,\n path: string,\n handler: EventHandler,\n) {\n const h3 = nitroApp.h3;\n if (!h3 || !Array.isArray(h3[\"~middleware\"])) {\n throw new Error(\n \"[agent-native] Cannot register route: nitroApp.h3 is not available. \" +\n \"Make sure you're calling getH3App() from inside a Nitro plugin.\",\n );\n }\n\n const middleware = async (event: H3Event, next: () => any) => {\n let originalPathname: string | undefined;\n let originalEventPath: string | undefined;\n let hadEventPath = false;\n const restoreOriginalPath = () => {\n if (originalPathname !== undefined) {\n try {\n event.url.pathname = originalPathname;\n } catch {\n // ignore\n }\n originalPathname = undefined;\n }\n if (hadEventPath) {\n try {\n (event as any).path = originalEventPath;\n } catch {\n // ignore\n }\n } else {\n try {\n delete (event as any).path;\n } catch {\n // ignore\n }\n }\n };\n if (path) {\n const reqPath = event.url?.pathname ?? \"\";\n const match = resolveMountMatch(reqPath, path);\n if (!match) {\n return next();\n }\n // Strip the mount prefix from event.url.pathname so handlers that\n // dispatch sub-routes can read `event.path` (or `event.url.pathname`)\n // and see the path RELATIVE to their mount point — matching h3 v1's\n // `app.use(path, handler)` semantics.\n const eventAny = event as any;\n hadEventPath = \"path\" in eventAny;\n originalEventPath = eventAny.path;\n try {\n originalPathname = event.url.pathname;\n // Save the full path in context so handlers that need the original URL\n // (e.g. Better Auth, which extracts its own basePath prefix) can\n // reconstruct a Request with the un-stripped URL.\n eventAny.context = eventAny.context ?? {};\n eventAny.context._mountedPathname = originalPathname;\n eventAny.context._mountPrefix = match.mountPath;\n event.url.pathname = match.strippedPath;\n eventAny.path = `${match.strippedPath}${event.url.search || \"\"}`;\n } catch {\n // event.url is read-only on some runtimes — fall through. Handlers\n // that don't depend on prefix stripping (most of them) still work.\n }\n }\n try {\n const result = await handler(event);\n if (result === undefined) {\n // Restore the original pathname BEFORE calling next() so downstream\n // middleware sees the full URL — not the stripped mount-relative path.\n // Matches h3 v2's own sub-app middleware pattern where the restore\n // happens inside the next() callback, not after it returns.\n restoreOriginalPath();\n return next();\n }\n return result;\n } catch (err) {\n // Log 500s to the server console so they're debuggable, and respond\n // with JSON instead of the default HTML error page so clients can\n // surface error messages. This only applies to routes mounted under\n // the framework prefix (or middleware mounted at `/`, for which we\n // still want visibility).\n const reqPath = originalPathname ?? event.url?.pathname ?? \"\";\n const e = err as any;\n const status =\n typeof e?.statusCode === \"number\"\n ? e.statusCode\n : typeof e?.status === \"number\"\n ? e.status\n : 500;\n console.error(\n `[agent-native] ${event.method ?? \"\"} ${reqPath} failed (${status}):`,\n e?.stack || e?.message || e,\n );\n try {\n setResponseStatus(event, status);\n setResponseHeader(event, \"content-type\", \"application/json\");\n } catch {\n // Response already sent — best effort.\n }\n return {\n error: e?.message || \"Internal server error\",\n // Only surface the stack to clients when explicitly enabled.\n // `NODE_ENV !== \"production\"` was unsafe — preview deploys and\n // any host that forgets to set NODE_ENV=production leaked stack\n // traces (file paths, dependency versions, internal route\n // topology) to anonymous callers. Operators who want stacks in\n // dev set `AGENT_NATIVE_DEBUG_ERRORS=1` explicitly.\n ...(status >= 500 &&\n process.env.AGENT_NATIVE_DEBUG_ERRORS === \"1\" &&\n e?.stack\n ? { stack: e.stack }\n : {}),\n };\n } finally {\n // Restore the original pathname so downstream middleware sees the\n // full URL.\n restoreOriginalPath();\n }\n };\n\n h3[\"~middleware\"].push(middleware);\n}\n\n/**\n * Auto-mount any default framework plugins that the template doesn't provide.\n *\n * Runs once per nitroApp on the first `getH3App()` call. Uses route-discovery\n * to find which default plugin stems are missing from `server/plugins/`, then\n * dynamically imports and mounts them. If a workspace core is present in the\n * ancestor chain, plugin slots the workspace core exports are mounted from\n * there instead of from @agent-native/core — this is the middle layer of the\n * three-layer inheritance model (app local > workspace core > framework).\n */\nasync function bootstrapDefaultPlugins(nitroApp: any): Promise<void> {\n IN_BOOTSTRAP.add(nitroApp);\n try {\n const cwd = process.cwd();\n const missing = await getMissingDefaultPlugins(cwd);\n if (missing.length === 0) return;\n\n // Lazy import to avoid circular dependency at module load time\n const serverModule = await import(\"./index.js\");\n const terminalModule = await import(\"../terminal/terminal-plugin.js\");\n const integrationsModule = await import(\"../integrations/plugin.js\");\n const orgModule = await import(\"../org/plugin.js\");\n const onboardingModule = await import(\"../onboarding/plugin.js\");\n\n const frameworkImpls: Record<\n string,\n ((nitroApp: any) => void | Promise<void>) | undefined\n > = {\n \"agent-chat\": (serverModule as any).defaultAgentChatPlugin,\n auth: (serverModule as any).defaultAuthPlugin,\n \"core-routes\": (serverModule as any).defaultCoreRoutesPlugin,\n integrations: (integrationsModule as any).defaultIntegrationsPlugin,\n onboarding: (onboardingModule as any).defaultOnboardingPlugin,\n org: (orgModule as any).defaultOrgPlugin,\n resources: (serverModule as any).defaultResourcesPlugin,\n terminal: (terminalModule as any).defaultTerminalPlugin,\n };\n\n // Workspace core layer: if the app is inside an enterprise monorepo with\n // `agent-native.workspaceCore` configured, pull in any plugin slots the\n // workspace core exports from its server entry. We dynamically import the\n // workspace core package at runtime.\n let workspaceImpls: Record<\n string,\n ((nitroApp: any) => void | Promise<void>) | undefined\n > = {};\n try {\n const { getWorkspaceCoreExports } =\n await import(\"../deploy/workspace-core.js\");\n const ws = await getWorkspaceCoreExports(cwd);\n if (ws && Object.keys(ws.plugins).length > 0) {\n try {\n const wsServerModule = await loadWorkspaceCoreServer(\n ws.packageName,\n ws.packageDir,\n );\n for (const [slot, exportName] of Object.entries(ws.plugins)) {\n if (!exportName) continue;\n const impl = (wsServerModule as any)[exportName];\n if (typeof impl === \"function\") {\n workspaceImpls[slot] = impl;\n }\n }\n if (process.env.DEBUG) {\n console.log(\n `[agent-native] Workspace core ${ws.packageName} provides plugin slots: ${Object.keys(workspaceImpls).join(\", \")}`,\n );\n }\n } catch (e) {\n const msg = (e as Error).message ?? \"\";\n // Common cause: workspace-core's package.json points \"./server\"\n // at a TS source file (the scaffold default), but Node can't\n // resolve relative `.js` imports inside it without a TS loader.\n // Tell the user to compile to dist/ rather than just dumping the\n // raw resolution error.\n const tsLoadHint = /\\.js' imported from .*\\.ts/.test(msg)\n ? \" — workspace-core src is TypeScript but isn't being compiled. \" +\n \"Run `pnpm --filter \" +\n ws.packageName +\n \" build` and point its `./server` export at dist/server/index.js.\"\n : \"\";\n console.warn(\n `[agent-native] Failed to load workspace core ${ws.packageName}/server: ${msg}${tsLoadHint}`,\n );\n }\n }\n } catch {\n // Workspace shared package isn't available (e.g. running on an edge\n // runtime without fs). Silently fall through to framework defaults.\n }\n\n if (process.env.DEBUG)\n console.log(\n `[agent-native] Auto-mounting ${missing.length} default plugin(s): ${missing.join(\", \")}`,\n );\n\n for (const stem of missing) {\n // Prefer workspace-core impl over framework default when both exist.\n const impl = workspaceImpls[stem] ?? frameworkImpls[stem];\n if (typeof impl === \"function\") {\n try {\n await impl(nitroApp);\n } catch (e) {\n console.warn(\n `[agent-native] Failed to auto-mount default plugin ${stem}:`,\n (e as Error).message,\n );\n }\n }\n }\n } finally {\n IN_BOOTSTRAP.delete(nitroApp);\n }\n}\n\n/**\n * Load a workspace-core's `/server` entry, transparently handling TS source.\n *\n * The scaffolded workspace-core template ships TS sources without a build\n * step (exports point at `./src/server/index.ts`), so plain `await import()`\n * blows up the moment Node hits a relative `.js` import inside (the standard\n * TS ESM convention) — and even before that, Node may resolve the package\n * relative to the framework's own location rather than the user's monorepo.\n *\n * We try Node's plain `import()` first (fastest path when the user has\n * compiled to dist/) and fall through to jiti on any error. jiti is anchored\n * to a real file inside the workspace-core's directory, so its module\n * resolution starts in the right node_modules tree (handles pnpm hoisting\n * and linked workspaces) AND handles TS source files + `.js` → `.ts` ESM\n * extension remapping.\n *\n * Edge runtimes without `fs` won't be able to load jiti at all; the outer\n * try/catch silently falls through to framework defaults in that case.\n */\nexport async function loadWorkspaceCoreServer(\n packageName: string,\n packageDir: string,\n): Promise<any> {\n let firstErr: unknown;\n try {\n return await import(/* @vite-ignore */ `${packageName}/server`);\n } catch (e) {\n firstErr = e;\n }\n\n try {\n const { createJiti } = await import(\"jiti\");\n const { pathToFileURL } = await import(\"node:url\");\n const path = await import(\"node:path\");\n // Anchor jiti to a real file inside the workspace-core package so its\n // module resolution starts in the right node_modules tree (handles pnpm\n // hoisting and linked workspaces).\n const anchor = pathToFileURL(\n path.join(packageDir, \"package.json\"),\n ).toString();\n const jiti = createJiti(anchor, { interopDefault: true });\n return await jiti.import(`${packageName}/server`);\n } catch (jitiErr) {\n // jiti also failed — rethrow the original Node error since it's usually\n // more informative about *why* the package wasn't resolvable.\n throw firstErr ?? jitiErr;\n }\n}\n\nexport { FRAMEWORK_PREFIX };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"google-oauth.d.ts","sourceRoot":"","sources":["../../src/server/google-oauth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"google-oauth.d.ts","sourceRoot":"","sources":["../../src/server/google-oauth.ts"],"names":[],"mappings":"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"}
@@ -111,6 +111,39 @@ export function getAppUrl(event, path = "/") {
111
111
  const cleanPath = path.startsWith("/") ? path : `/${path}`;
112
112
  return `${getOrigin(event)}${getAppBasePath()}${cleanPath}`;
113
113
  }
114
+ function getOriginalRequestPath(event) {
115
+ const mountedPathname = event.context?._mountedPathname;
116
+ if (typeof mountedPathname === "string" && mountedPathname) {
117
+ return mountedPathname;
118
+ }
119
+ const urlPathname = event.url?.pathname;
120
+ if (typeof urlPathname === "string" && urlPathname)
121
+ return urlPathname;
122
+ const nodeUrl = event.node?.req?.url;
123
+ if (typeof nodeUrl === "string" && nodeUrl) {
124
+ const queryStart = nodeUrl.indexOf("?");
125
+ return queryStart >= 0 ? nodeUrl.slice(0, queryStart) : nodeUrl;
126
+ }
127
+ const eventPath = event.path;
128
+ if (typeof eventPath === "string" && eventPath) {
129
+ const queryStart = eventPath.indexOf("?");
130
+ return queryStart >= 0 ? eventPath.slice(0, queryStart) : eventPath;
131
+ }
132
+ return "/";
133
+ }
134
+ function isRequestUnderAppBasePath(event) {
135
+ const basePath = getAppBasePath();
136
+ if (!basePath)
137
+ return false;
138
+ const requestPath = getOriginalRequestPath(event);
139
+ return (requestPath === `${basePath}/_agent-native` ||
140
+ requestPath.startsWith(`${basePath}/_agent-native/`));
141
+ }
142
+ function getDefaultOAuthRedirectUrl(event, path) {
143
+ const cleanPath = path.startsWith("/") ? path : `/${path}`;
144
+ const basePath = isRequestUnderAppBasePath(event) ? getAppBasePath() : "";
145
+ return `${getOrigin(event)}${basePath}${cleanPath}`;
146
+ }
114
147
  // ─── redirect_uri Allowlist ──────────────────────────────────────────────────
115
148
  /**
116
149
  * Validate a user-supplied `redirect_uri` for OAuth flows.
@@ -159,11 +192,17 @@ export function isAllowedOAuthRedirectUri(candidate, event) {
159
192
  return false;
160
193
  if (url.host !== expectedUrl.host)
161
194
  return false;
162
- // Must live under the framework's namespace.
195
+ // Must live under the framework's namespace. Workspace deploys can route
196
+ // root /_agent-native/* to Dispatch even when Dispatch itself is mounted at
197
+ // /dispatch, but app-prefixed requests should not be able to swap their
198
+ // callback to that root namespace.
163
199
  const basePath = getAppBasePath();
164
- const required = `${basePath}/_agent-native/`;
165
- if (!url.pathname.startsWith(required))
200
+ const allowedPrefixes = basePath && isRequestUnderAppBasePath(event)
201
+ ? [`${basePath}/_agent-native/`]
202
+ : ["/_agent-native/"];
203
+ if (!allowedPrefixes.some((prefix) => url.pathname.startsWith(prefix))) {
166
204
  return false;
205
+ }
167
206
  return true;
168
207
  }
169
208
  /**
@@ -185,7 +224,7 @@ export function resolveOAuthRedirectUri(event, defaultPath = "/_agent-native/goo
185
224
  if (typeof supplied === "string" && supplied.length > 0) {
186
225
  return isAllowedOAuthRedirectUri(supplied, event) ? supplied : null;
187
226
  }
188
- return getAppUrl(event, defaultPath);
227
+ return getDefaultOAuthRedirectUrl(event, defaultPath);
189
228
  }
190
229
  /**
191
230
  * Ephemeral in-memory state-signing key for development. Generated lazily
@@ -1 +1 @@
1
- {"version":3,"file":"google-oauth.js","sourceRoot":"","sources":["../../src/server/google-oauth.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared Google OAuth utilities for all templates.\n *\n * Handles platform detection (desktop/mobile), state encoding,\n * session token creation, and deep-link responses — the logic\n * that was previously copy-pasted across every template's\n * google-auth.ts handler.\n */\n\nimport crypto from \"node:crypto\";\nimport {\n getHeader,\n getQuery,\n setCookie,\n setResponseStatus,\n setResponseHeader,\n type H3Event,\n} from \"h3\";\nimport {\n addSession,\n getSession,\n COOKIE_NAME,\n getSessionMaxAge,\n safeReturnPath,\n} from \"./auth.js\";\nimport { getAppName } from \"./app-name.js\";\nimport { writeDesktopSso } from \"./desktop-sso.js\";\n\n// ─── Platform Detection ─────────────────────────────────────────────────────\n\n/** Return an HTML response with the correct Content-Type.\n * Uses a web-standard Response to ensure the header survives\n * Nitro dev mode's mock-node-response pipeline. */\nfunction htmlResponse(html: string, status = 200): Response {\n return new Response(html, {\n status,\n headers: { \"Content-Type\": \"text/html; charset=utf-8\" },\n });\n}\n\n/**\n * HTML escape — minimal but covers the cases that matter when interpolating\n * user-controlled values into our OAuth callback HTML. Mirrors the helper in\n * email-template.ts; kept inline here to avoid a circular import.\n */\nfunction escapeHtml(s: string): string {\n return String(s ?? \"\")\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\n/** Detect requests from the Electron desktop app webview. */\nexport function isElectron(event: H3Event): boolean {\n return /Electron/i.test(getHeader(event, \"user-agent\") || \"\");\n}\n\n/** Detect requests from a mobile browser (iOS/Android). */\nexport function isMobile(event: H3Event): boolean {\n return /iPhone|iPad|iPod|Android/i.test(getHeader(event, \"user-agent\") || \"\");\n}\n\n/**\n * Build the static allowlist of origins we trust for `getOrigin`. Reads\n * `APP_URL` and `BETTER_AUTH_URL` (both are deployment-known public URLs).\n * Each entry is normalised to `${proto}://${host}` (no path). Duplicates\n * collapse, invalid entries are dropped silently.\n */\nfunction getConfiguredOriginAllowlist(): Set<string> {\n const out = new Set<string>();\n for (const raw of [process.env.APP_URL, process.env.BETTER_AUTH_URL]) {\n if (!raw) continue;\n try {\n const u = new URL(raw);\n out.add(`${u.protocol}//${u.host}`);\n } catch {\n // Ignore — env value isn't a parseable URL.\n }\n }\n return out;\n}\n\n/**\n * Get the origin from forwarded headers or Host.\n *\n * Defends against Host-header injection: in production we require the\n * resolved origin to match `APP_URL` / `BETTER_AUTH_URL`, falling back to\n * those values when the inbound headers are missing or don't match. In\n * dev we accept the inbound `Host` so localhost / ngrok / preview hosts\n * keep working without configuration. The protocol defaults to `https`\n * in production (so a TLS-terminating proxy that drops `x-forwarded-proto`\n * doesn't downgrade us to plain HTTP).\n */\nexport function getOrigin(event: H3Event): string {\n const headerHost =\n getHeader(event, \"x-forwarded-host\") || getHeader(event, \"host\");\n const isProd = process.env.NODE_ENV === \"production\";\n const headerProto =\n getHeader(event, \"x-forwarded-proto\") || (isProd ? \"https\" : \"http\");\n\n if (isProd) {\n const allow = getConfiguredOriginAllowlist();\n // If the deploy declares its public URL, prefer it over inbound headers.\n if (allow.size > 0) {\n const inbound = headerHost ? `${headerProto}://${headerHost}` : \"\";\n if (inbound && allow.has(inbound)) return inbound;\n // Inbound didn't match — fall back to the first configured origin.\n return [...allow][0];\n }\n // No allowlist configured: still default to https, but accept the\n // inbound Host (best we can do without a configured base URL).\n return `${headerProto}://${headerHost ?? \"\"}`;\n }\n\n return `${headerProto}://${headerHost ?? \"localhost\"}`;\n}\n\nfunction normalizeAppBasePath(value: string | undefined): string {\n if (!value || value === \"/\") return \"\";\n const trimmed = value.trim();\n if (!trimmed || trimmed === \"/\") return \"\";\n return `/${trimmed.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\")}`;\n}\n\n/** App mount prefix, if the template is served under APP_BASE_PATH. */\nexport function getAppBasePath(): string {\n return normalizeAppBasePath(\n process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH,\n );\n}\n\n/** Build an absolute same-origin URL that preserves APP_BASE_PATH. */\nexport function getAppUrl(event: H3Event, path = \"/\"): string {\n const cleanPath = path.startsWith(\"/\") ? path : `/${path}`;\n return `${getOrigin(event)}${getAppBasePath()}${cleanPath}`;\n}\n\n// ─── redirect_uri Allowlist ──────────────────────────────────────────────────\n\n/**\n * Validate a user-supplied `redirect_uri` for OAuth flows.\n *\n * Defends against authorization-code interception (RFC 6819 §4.4.1.7):\n * even though the upstream provider (Google/Atlassian/Zoom) refuses\n * unregistered redirect URIs, prefix-style registrations and side\n * registrations on the same host let a malicious caller swap in an\n * attacker-controlled URI that the provider still accepts. We reject any\n * candidate that isn't on this server's own origin AND under the\n * framework's `/_agent-native/` namespace. Returns the validated URI on\n * success, or `undefined` on rejection — callers must treat `undefined`\n * as a 400.\n *\n * The intentional shape is exact-prefix:\n * - Origin must equal `getOrigin(event)` — no Host-header injection\n * reusing somebody else's registered redirect URI.\n * - Path must start with `${appBasePath}/_agent-native/` so we never\n * hand auth codes to a public marketing or open-redirect endpoint\n * on the same registered host.\n *\n * For desktop / native flows that need ephemeral `http://127.0.0.1:<port>`\n * loopback URIs, callers should validate those at the template level\n * with a dedicated allowlist — this helper rejects them by design.\n */\nexport function isAllowedOAuthRedirectUri(\n candidate: string,\n event: H3Event,\n): boolean {\n if (typeof candidate !== \"string\" || candidate.length === 0) return false;\n let url: URL;\n try {\n url = new URL(candidate);\n } catch {\n return false;\n }\n // Must be same origin as our server.\n const expectedOrigin = getOrigin(event);\n let expectedUrl: URL;\n try {\n expectedUrl = new URL(expectedOrigin);\n } catch {\n return false;\n }\n if (url.protocol !== expectedUrl.protocol) return false;\n if (url.host !== expectedUrl.host) return false;\n // Must live under the framework's namespace.\n const basePath = getAppBasePath();\n const required = `${basePath}/_agent-native/`;\n if (!url.pathname.startsWith(required)) return false;\n return true;\n}\n\n/**\n * Resolve the `redirect_uri` for an outbound OAuth `auth-url` request.\n *\n * Reads `?redirect_uri=` from the query and validates it via\n * `isAllowedOAuthRedirectUri`. Returns:\n * - the validated URI when supplied and allowed, OR\n * - the framework default when no override was supplied, OR\n * - `null` when an override was supplied but rejected — callers must\n * respond with 400 in that case.\n *\n * Templates that need a non-default redirect path can pass it via\n * `defaultPath` (e.g. `\"/_agent-native/google/desktop-callback\"` for\n * desktop flows).\n */\nexport function resolveOAuthRedirectUri(\n event: H3Event,\n defaultPath = \"/_agent-native/google/callback\",\n): string | null {\n const supplied = getQuery(event).redirect_uri;\n if (typeof supplied === \"string\" && supplied.length > 0) {\n return isAllowedOAuthRedirectUri(supplied, event) ? supplied : null;\n }\n return getAppUrl(event, defaultPath);\n}\n\n// ─── OAuth State ─────────────────────────────────────────────────────────────\n\nexport interface OAuthStatePayload {\n redirectUri: string;\n owner?: string;\n desktop?: boolean;\n addAccount?: boolean;\n app?: string;\n /**\n * Same-origin path to redirect to after a successful web-flow sign-in.\n * Threaded through the (HMAC-signed) state so it survives the round trip\n * to Google. Validated again on decode via safeReturnPath as defence in\n * depth. Has no effect on desktop / mobile / add-account flows, which\n * use their own deep-link / close-tab handling.\n */\n returnUrl?: string;\n flowId?: string;\n}\n\n/**\n * Ephemeral in-memory state-signing key for development. Generated lazily\n * on first read so dev sessions don't depend on filesystem writability or\n * env-var configuration. Sessions reset on each restart, which is fine\n * for dev — no real users / production data are involved.\n */\nlet _devStateSigningKey: string | undefined;\n\n/**\n * Derive a server-only signing key for HMAC verification of OAuth state.\n *\n * Uses a dedicated secret — never an OAuth client secret. Reusing a\n * client_secret (which is shared with Google / GitHub / Atlassian) as our\n * own HMAC key conflates two trust domains: rotating the client secret\n * silently invalidates every in-flight OAuth state, and any leak of the\n * client secret also lets an attacker forge our state envelopes.\n *\n * Resolution order:\n * 1. OAUTH_STATE_SECRET (preferred — dedicated to this purpose)\n * 2. BETTER_AUTH_SECRET (already used by Better Auth as a server secret)\n * 3. In dev only, an ephemeral random key (per-process)\n *\n * In production, throws if neither secret is set.\n */\nfunction getStateSigningKey(): string {\n const secret =\n process.env.OAUTH_STATE_SECRET || process.env.BETTER_AUTH_SECRET;\n if (secret) return secret;\n\n const isProd = process.env.NODE_ENV === \"production\";\n if (isProd) {\n throw new Error(\n \"OAuth state signing requires a server secret. \" +\n \"Set OAUTH_STATE_SECRET or BETTER_AUTH_SECRET in production.\",\n );\n }\n\n if (!_devStateSigningKey) {\n _devStateSigningKey = crypto.randomBytes(32).toString(\"hex\");\n }\n return _devStateSigningKey;\n}\n\n/**\n * Options for the named-argument form of {@link encodeOAuthState}.\n * Prefer this form — the positional overload is easy to misuse (the mail\n * and calendar templates historically passed `flowId` in the `returnUrl`\n * slot, smuggling state into a defence-in-depth path).\n */\nexport interface EncodeOAuthStateOptions {\n redirectUri: string;\n owner?: string;\n desktop?: boolean;\n addAccount?: boolean;\n app?: string;\n returnUrl?: string;\n flowId?: string;\n}\n\n/**\n * Encode OAuth state into a signed base64url string.\n * The state is HMAC-signed so the callback can verify it wasn't forged,\n * preventing CSRF attacks on the OAuth flow.\n *\n * Two call shapes are supported:\n * - Recommended: pass an options object — clear, mismatch-proof.\n * `encodeOAuthState({ redirectUri, owner, desktop, ... })`\n * - Legacy positional form (kept working for backward compatibility):\n * `encodeOAuthState(redirectUri, owner, desktop, addAccount, app, returnUrl, flowId)`.\n * Callers should migrate to the options form — see the audit on\n * templates/mail and templates/calendar where the positional shape\n * led to `flowId` being smuggled in via the `returnUrl` slot.\n */\nexport function encodeOAuthState(opts: EncodeOAuthStateOptions): string;\nexport function encodeOAuthState(\n redirectUri: string,\n owner?: string,\n desktop?: boolean,\n addAccount?: boolean,\n app?: string,\n returnUrl?: string,\n flowId?: string,\n): string;\nexport function encodeOAuthState(\n redirectUriOrOpts: string | EncodeOAuthStateOptions,\n owner?: string,\n desktop?: boolean,\n addAccount?: boolean,\n app?: string,\n returnUrl?: string,\n flowId?: string,\n): string {\n const opts: EncodeOAuthStateOptions =\n typeof redirectUriOrOpts === \"string\"\n ? {\n redirectUri: redirectUriOrOpts,\n owner,\n desktop,\n addAccount,\n app,\n returnUrl,\n flowId,\n }\n : redirectUriOrOpts;\n\n const nonce = crypto.randomBytes(8).toString(\"hex\");\n const payload: Record<string, string | boolean> = {\n n: nonce,\n r: opts.redirectUri,\n };\n if (opts.owner) payload.o = opts.owner;\n if (opts.desktop) payload.d = true;\n if (opts.addAccount) payload.a = true;\n if (opts.app) payload.app = opts.app;\n if (opts.returnUrl) payload.r2 = opts.returnUrl;\n if (opts.flowId) payload.f = opts.flowId;\n const data = Buffer.from(JSON.stringify(payload)).toString(\"base64url\");\n const sig = crypto\n .createHmac(\"sha256\", getStateSigningKey())\n .update(data)\n .digest(\"base64url\");\n return `${data}.${sig}`;\n}\n\n/**\n * Decode and verify OAuth state from the callback's state query parameter.\n * Rejects forged or tampered state by checking the HMAC signature.\n * Falls back to the provided URI if decoding or verification fails.\n */\nexport function decodeOAuthState(\n stateParam: string | undefined,\n fallbackUri: string,\n): OAuthStatePayload {\n if (stateParam) {\n try {\n const dotIdx = stateParam.lastIndexOf(\".\");\n if (dotIdx === -1) return { redirectUri: fallbackUri };\n\n const data = stateParam.slice(0, dotIdx);\n const sig = stateParam.slice(dotIdx + 1);\n const expected = crypto\n .createHmac(\"sha256\", getStateSigningKey())\n .update(data)\n .digest(\"base64url\");\n\n if (\n sig.length !== expected.length ||\n !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))\n ) {\n return { redirectUri: fallbackUri };\n }\n\n const parsed = JSON.parse(Buffer.from(data, \"base64url\").toString());\n return {\n redirectUri: parsed.r || fallbackUri,\n owner: parsed.o || undefined,\n desktop: !!parsed.d,\n addAccount: !!parsed.a,\n app: typeof parsed.app === \"string\" ? parsed.app : undefined,\n // Pass returnUrl through as-is — same-origin validation runs at the\n // consumer (oauthCallbackResponse → safeReturnPath). The state is\n // HMAC-signed, but we still validate at consumption as defence in\n // depth in case the signing key ever leaks.\n returnUrl: typeof parsed.r2 === \"string\" ? parsed.r2 : undefined,\n flowId: parsed.f || undefined,\n };\n } catch {}\n }\n return { redirectUri: fallbackUri };\n}\n\n// ─── Session Creation ────────────────────────────────────────────────────────\n\nexport interface OAuthOwnerResult {\n owner: string | undefined;\n isDevSession: boolean;\n hasProductionSession: boolean;\n}\n\n/**\n * Determine the token owner from the current session and OAuth state.\n * Call this BEFORE exchangeCode to get the owner parameter.\n */\nexport async function resolveOAuthOwner(\n event: H3Event,\n stateOwner?: string,\n): Promise<OAuthOwnerResult> {\n const existingSession = await getSession(event);\n const isDevSession = existingSession?.email === \"local@localhost\";\n const hasProductionSession = !!(existingSession?.email && !isDevSession);\n\n // Never use \"local@localhost\" as a token owner — it creates shared-ownership\n // bugs where multiple users can see the same tokens.\n const owner = hasProductionSession\n ? existingSession!.email\n : stateOwner || undefined;\n\n return { owner, isDevSession, hasProductionSession };\n}\n\nexport interface OAuthSessionResult {\n sessionToken: string | undefined;\n}\n\n/**\n * Create a session token after a successful OAuth exchange.\n *\n * Desktop and mobile apps have separate cookie jars from the system\n * browser, so they always get a fresh session token (even if the browser\n * already has one). The token is then passed via deep link so the native\n * app can inject it.\n */\nexport async function createOAuthSession(\n event: H3Event,\n email: string,\n opts: {\n hasProductionSession: boolean;\n desktop?: boolean;\n },\n): Promise<OAuthSessionResult> {\n const mobile = isMobile(event);\n const needsDeepLink = opts.desktop || mobile;\n const maxAge = getSessionMaxAge();\n\n let sessionToken: string | undefined;\n if (!opts.hasProductionSession || needsDeepLink) {\n sessionToken = crypto.randomBytes(32).toString(\"hex\");\n await addSession(sessionToken, email);\n setCookie(event, COOKIE_NAME, sessionToken, {\n httpOnly: true,\n secure: process.env.NODE_ENV === \"production\",\n sameSite: \"lax\",\n path: \"/\",\n maxAge,\n });\n // Desktop SSO: record this session in the home-dir broker file so\n // sibling templates (each with its own database) can resolve the\n // same token without a DB row of their own. Only the PRIMARY\n // sign-in writes the broker — if a production session already\n // exists, this is an add-account flow (connecting a secondary\n // Google account for scraping) and must never switch the active\n // user across sibling templates.\n if (opts.desktop && !opts.hasProductionSession) {\n await writeDesktopSso({\n email,\n token: sessionToken,\n expiresAt: Date.now() + maxAge * 1000,\n });\n }\n }\n\n return { sessionToken };\n}\n\n// ─── Callback Responses ──────────────────────────────────────────────────────\n\n/**\n * Return the appropriate response after a successful OAuth callback.\n *\n * Handles mobile deep links, desktop deep links, add-account close-tab\n * pages, and plain web redirects — so templates don't have to.\n */\nexport function oauthCallbackResponse(\n event: H3Event,\n email: string,\n opts: {\n sessionToken?: string;\n desktop?: boolean;\n addAccount?: boolean;\n /**\n * Same-origin path to return the viewer to after a successful web\n * sign-in. Validated via safeReturnPath; falls back to \"/\" for any\n * shape that escapes same-origin. Has no effect on desktop / mobile\n * / add-account flows — those use their own deep-link handling.\n */\n returnUrl?: string;\n flowId?: string;\n appName?: string;\n },\n): Response | string | unknown | Promise<Response | string | unknown> {\n const mobile = isMobile(event);\n const query = getQuery(event);\n const callbackState =\n typeof query.state === \"string\" && query.state.length > 0\n ? query.state\n : undefined;\n\n // Mobile: deep link back to native app\n if (mobile) {\n const deepLink = buildOAuthCompleteDeepLink(\n opts.sessionToken,\n callbackState,\n );\n return htmlResponse(\n `<!DOCTYPE html><html><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\"><title>Connected</title></head><body style=\"background:#111;color:#aaa;font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0\"><p>Connected! Returning to app…</p><script>window.location.href=${JSON.stringify(deepLink)};setTimeout(function(){window.location.href=\"/\"},1500)</script></body></html>`,\n );\n }\n\n // Desktop add-account: close-tab page (must come before general desktop check\n // to ensure no deep link fires and the existing session is never switched).\n if (opts.desktop && opts.addAccount) {\n const safeEmail = email ? escapeHtml(email) : \"\";\n const safeAppName = escapeHtml(resolveOAuthAppName(opts.appName));\n const msg = safeEmail ? `Connected ${safeEmail}!` : \"Connected!\";\n return htmlResponse(\n `<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Connected</title></head><body style=\"background:#111;color:#ccc;font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;flex-direction:column;gap:8px\"><p style=\"font-size:16px\">${msg}</p><p style=\"font-size:13px;color:#888\">You can close this tab and return to ${safeAppName}.</p></body></html>`,\n );\n }\n\n // Electron desktop exchange flow: mail/calendar still pass a flow id so the\n // renderer can poll as a fallback, but the main handoff should use the\n // protocol deep link so the popup returns focus to the desktop app.\n if (opts.desktop && opts.flowId && isElectron(event) && opts.sessionToken) {\n return desktopSuccessPage(event, email, opts.sessionToken, callbackState);\n }\n\n // Desktop exchange flow (non-Electron tray app): the tray app polls the\n // desktop-exchange endpoint for the token — no deep link needed.\n if (opts.desktop && opts.flowId) {\n const safeEmail = email ? escapeHtml(email) : \"\";\n const safeAppName = escapeHtml(resolveOAuthAppName(opts.appName));\n const msg = safeEmail ? `Signed in as ${safeEmail}!` : \"Signed in!\";\n return htmlResponse(\n `<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Connected</title></head><body style=\"background:#111;color:#ccc;font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;flex-direction:column;gap:8px\"><p style=\"font-size:16px\">${msg}</p><p style=\"font-size:13px;color:#888\">You can close this tab and return to ${safeAppName}.</p></body></html>`,\n );\n }\n\n // Desktop login: deep link back to Electron app\n if (opts.desktop) {\n return desktopSuccessPage(event, email, opts.sessionToken, callbackState);\n }\n\n // Add-account web flow: close-tab page. The email is rendered into the\n // page via DOM `textContent` (safe), but we still JSON-stringify so a\n // payload containing `</script>` can't break out of the script tag —\n // and explicitly assert it's a string so a callbacks like `null` or\n // an object won't end up serialised into the page.\n if (opts.addAccount) {\n const safeEmail = JSON.stringify(typeof email === \"string\" ? email : \"\");\n return htmlResponse(`<!DOCTYPE html><html><body><script>\n window.close();\n var p = document.createElement('p');\n p.style.cssText = 'font-family:system-ui;text-align:center;margin-top:40vh';\n p.textContent = 'Connected ' + ${safeEmail} + '! You can close this tab.';\n document.body.appendChild(p);\n </script></body></html>`);\n }\n\n // Web: redirect to the requested return path (validated same-origin) or\n // \"/\" if no return was supplied / the return failed validation. Returning\n // an empty string body keeps h3's `prepareResponseBody` → `FastResponse`\n // path, which merges the prepared event headers (Location + any cookies\n // set via `setCookie(event, ...)`).\n setResponseStatus(event, 302);\n setResponseHeader(event, \"Location\", safeReturnPath(opts.returnUrl));\n return \"\";\n}\n\n/** HTML error page for OAuth failures. The message is HTML-escaped — most\n * callers pass `error.message` from a token-exchange or userinfo failure,\n * which can echo upstream provider strings (and historically attacker-\n * controlled query params via the `error_description` field). */\nexport function oauthErrorPage(message: string): Response {\n const safe = escapeHtml(message);\n return htmlResponse(\n `<!DOCTYPE html><html><body>\n <div style=\"font-family:system-ui;max-width:420px;margin:30vh auto;text-align:center\">\n <p style=\"font-size:15px;color:#e55\">${safe}</p>\n <p style=\"margin-top:16px;font-size:13px;color:#888\"><a href=\"/\" style=\"color:#888\">Back to login</a></p>\n </div>\n </body></html>`,\n 400,\n );\n}\n\nexport function oauthDesktopExchangePage(\n message = \"Returning to the app...\",\n): Response {\n const safe = escapeHtml(message);\n return htmlResponse(\n `<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Returning</title></head><body style=\"background:#111;color:#aaa;font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0\"><p style=\"font-size:14px\">${safe}</p><script>window.close()</script></body></html>`,\n );\n}\n\n// ─── Internal ────────────────────────────────────────────────────────────────\n\nfunction resolveOAuthAppName(explicit?: string): string {\n const raw = explicit || getAppName() || \"Agent Native\";\n if (!/^[a-z0-9_-]+$/.test(raw)) return raw;\n return raw\n .split(/[-_]+/)\n .filter(Boolean)\n .map((word) => word[0].toUpperCase() + word.slice(1))\n .join(\" \");\n}\n\nfunction buildOAuthCompleteDeepLink(\n sessionToken?: string,\n state?: string,\n): string {\n const params = new URLSearchParams();\n if (sessionToken) params.set(\"token\", sessionToken);\n if (state) params.set(\"state\", state);\n const suffix = params.toString();\n return suffix\n ? `agentnative://oauth-complete?${suffix}`\n : \"agentnative://oauth-complete\";\n}\n\nfunction desktopSuccessPage(\n _event: H3Event,\n email?: string,\n sessionToken?: string,\n state?: string,\n): Response {\n const safeEmail = email ? escapeHtml(email) : \"\";\n const msg = safeEmail ? `Connected ${safeEmail}!` : \"Connected!\";\n if (sessionToken) {\n const deepLink = buildOAuthCompleteDeepLink(sessionToken, state);\n const deepLinkJson = JSON.stringify(deepLink);\n return htmlResponse(\n `<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Connected</title><style>@keyframes spin{to{transform:rotate(360deg)}}@keyframes fadeIn{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.spinner{width:28px;height:28px;border:2px solid #333;border-top-color:#fff;border-radius:50%;animation:spin .8s linear infinite}.fallback{display:none;flex-direction:column;align-items:center;gap:8px;animation:fadeIn .2s ease-out}.fallback.show{display:flex}</style></head><body style=\"background:#111;color:#ccc;font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;flex-direction:column;gap:16px\"><p style=\"font-size:16px;margin:0\">${msg}</p><div id=\"loading\" class=\"spinner\"></div><div id=\"fallback\" class=\"fallback\"><a href=${deepLinkJson} style=\"display:inline-block;padding:10px 24px;background:#fff;color:#000;border-radius:8px;text-decoration:none;font-size:14px;font-weight:500\">Open Agent Native</a><p style=\"font-size:12px;color:#666;margin:0\">If the app didn\\u2019t open automatically, click the button above.</p></div><script>window.location.href=${deepLinkJson};setTimeout(function(){document.getElementById(\"loading\").style.display=\"none\";document.getElementById(\"fallback\").classList.add(\"show\")},3000)</script></body></html>`,\n );\n }\n return htmlResponse(\n `<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Connected</title></head><body style=\"background:#111;color:#ccc;font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;flex-direction:column;gap:8px\"><p style=\"font-size:16px\">${msg}</p><p style=\"font-size:13px;color:#888\">You can close this tab and return to Agent Native.</p></body></html>`,\n );\n}\n"]}
1
+ {"version":3,"file":"google-oauth.js","sourceRoot":"","sources":["../../src/server/google-oauth.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared Google OAuth utilities for all templates.\n *\n * Handles platform detection (desktop/mobile), state encoding,\n * session token creation, and deep-link responses — the logic\n * that was previously copy-pasted across every template's\n * google-auth.ts handler.\n */\n\nimport crypto from \"node:crypto\";\nimport {\n getHeader,\n getQuery,\n setCookie,\n setResponseStatus,\n setResponseHeader,\n type H3Event,\n} from \"h3\";\nimport {\n addSession,\n getSession,\n COOKIE_NAME,\n getSessionMaxAge,\n safeReturnPath,\n} from \"./auth.js\";\nimport { getAppName } from \"./app-name.js\";\nimport { writeDesktopSso } from \"./desktop-sso.js\";\n\n// ─── Platform Detection ─────────────────────────────────────────────────────\n\n/** Return an HTML response with the correct Content-Type.\n * Uses a web-standard Response to ensure the header survives\n * Nitro dev mode's mock-node-response pipeline. */\nfunction htmlResponse(html: string, status = 200): Response {\n return new Response(html, {\n status,\n headers: { \"Content-Type\": \"text/html; charset=utf-8\" },\n });\n}\n\n/**\n * HTML escape — minimal but covers the cases that matter when interpolating\n * user-controlled values into our OAuth callback HTML. Mirrors the helper in\n * email-template.ts; kept inline here to avoid a circular import.\n */\nfunction escapeHtml(s: string): string {\n return String(s ?? \"\")\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\n/** Detect requests from the Electron desktop app webview. */\nexport function isElectron(event: H3Event): boolean {\n return /Electron/i.test(getHeader(event, \"user-agent\") || \"\");\n}\n\n/** Detect requests from a mobile browser (iOS/Android). */\nexport function isMobile(event: H3Event): boolean {\n return /iPhone|iPad|iPod|Android/i.test(getHeader(event, \"user-agent\") || \"\");\n}\n\n/**\n * Build the static allowlist of origins we trust for `getOrigin`. Reads\n * `APP_URL` and `BETTER_AUTH_URL` (both are deployment-known public URLs).\n * Each entry is normalised to `${proto}://${host}` (no path). Duplicates\n * collapse, invalid entries are dropped silently.\n */\nfunction getConfiguredOriginAllowlist(): Set<string> {\n const out = new Set<string>();\n for (const raw of [process.env.APP_URL, process.env.BETTER_AUTH_URL]) {\n if (!raw) continue;\n try {\n const u = new URL(raw);\n out.add(`${u.protocol}//${u.host}`);\n } catch {\n // Ignore — env value isn't a parseable URL.\n }\n }\n return out;\n}\n\n/**\n * Get the origin from forwarded headers or Host.\n *\n * Defends against Host-header injection: in production we require the\n * resolved origin to match `APP_URL` / `BETTER_AUTH_URL`, falling back to\n * those values when the inbound headers are missing or don't match. In\n * dev we accept the inbound `Host` so localhost / ngrok / preview hosts\n * keep working without configuration. The protocol defaults to `https`\n * in production (so a TLS-terminating proxy that drops `x-forwarded-proto`\n * doesn't downgrade us to plain HTTP).\n */\nexport function getOrigin(event: H3Event): string {\n const headerHost =\n getHeader(event, \"x-forwarded-host\") || getHeader(event, \"host\");\n const isProd = process.env.NODE_ENV === \"production\";\n const headerProto =\n getHeader(event, \"x-forwarded-proto\") || (isProd ? \"https\" : \"http\");\n\n if (isProd) {\n const allow = getConfiguredOriginAllowlist();\n // If the deploy declares its public URL, prefer it over inbound headers.\n if (allow.size > 0) {\n const inbound = headerHost ? `${headerProto}://${headerHost}` : \"\";\n if (inbound && allow.has(inbound)) return inbound;\n // Inbound didn't match — fall back to the first configured origin.\n return [...allow][0];\n }\n // No allowlist configured: still default to https, but accept the\n // inbound Host (best we can do without a configured base URL).\n return `${headerProto}://${headerHost ?? \"\"}`;\n }\n\n return `${headerProto}://${headerHost ?? \"localhost\"}`;\n}\n\nfunction normalizeAppBasePath(value: string | undefined): string {\n if (!value || value === \"/\") return \"\";\n const trimmed = value.trim();\n if (!trimmed || trimmed === \"/\") return \"\";\n return `/${trimmed.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\")}`;\n}\n\n/** App mount prefix, if the template is served under APP_BASE_PATH. */\nexport function getAppBasePath(): string {\n return normalizeAppBasePath(\n process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH,\n );\n}\n\n/** Build an absolute same-origin URL that preserves APP_BASE_PATH. */\nexport function getAppUrl(event: H3Event, path = \"/\"): string {\n const cleanPath = path.startsWith(\"/\") ? path : `/${path}`;\n return `${getOrigin(event)}${getAppBasePath()}${cleanPath}`;\n}\n\nfunction getOriginalRequestPath(event: H3Event): string {\n const mountedPathname = (event as any).context?._mountedPathname;\n if (typeof mountedPathname === \"string\" && mountedPathname) {\n return mountedPathname;\n }\n\n const urlPathname = (event as any).url?.pathname;\n if (typeof urlPathname === \"string\" && urlPathname) return urlPathname;\n\n const nodeUrl = event.node?.req?.url;\n if (typeof nodeUrl === \"string\" && nodeUrl) {\n const queryStart = nodeUrl.indexOf(\"?\");\n return queryStart >= 0 ? nodeUrl.slice(0, queryStart) : nodeUrl;\n }\n\n const eventPath = (event as any).path;\n if (typeof eventPath === \"string\" && eventPath) {\n const queryStart = eventPath.indexOf(\"?\");\n return queryStart >= 0 ? eventPath.slice(0, queryStart) : eventPath;\n }\n\n return \"/\";\n}\n\nfunction isRequestUnderAppBasePath(event: H3Event): boolean {\n const basePath = getAppBasePath();\n if (!basePath) return false;\n const requestPath = getOriginalRequestPath(event);\n return (\n requestPath === `${basePath}/_agent-native` ||\n requestPath.startsWith(`${basePath}/_agent-native/`)\n );\n}\n\nfunction getDefaultOAuthRedirectUrl(event: H3Event, path: string): string {\n const cleanPath = path.startsWith(\"/\") ? path : `/${path}`;\n const basePath = isRequestUnderAppBasePath(event) ? getAppBasePath() : \"\";\n return `${getOrigin(event)}${basePath}${cleanPath}`;\n}\n\n// ─── redirect_uri Allowlist ──────────────────────────────────────────────────\n\n/**\n * Validate a user-supplied `redirect_uri` for OAuth flows.\n *\n * Defends against authorization-code interception (RFC 6819 §4.4.1.7):\n * even though the upstream provider (Google/Atlassian/Zoom) refuses\n * unregistered redirect URIs, prefix-style registrations and side\n * registrations on the same host let a malicious caller swap in an\n * attacker-controlled URI that the provider still accepts. We reject any\n * candidate that isn't on this server's own origin AND under the\n * framework's `/_agent-native/` namespace. Returns the validated URI on\n * success, or `undefined` on rejection — callers must treat `undefined`\n * as a 400.\n *\n * The intentional shape is exact-prefix:\n * - Origin must equal `getOrigin(event)` — no Host-header injection\n * reusing somebody else's registered redirect URI.\n * - Path must start with `${appBasePath}/_agent-native/` so we never\n * hand auth codes to a public marketing or open-redirect endpoint\n * on the same registered host.\n *\n * For desktop / native flows that need ephemeral `http://127.0.0.1:<port>`\n * loopback URIs, callers should validate those at the template level\n * with a dedicated allowlist — this helper rejects them by design.\n */\nexport function isAllowedOAuthRedirectUri(\n candidate: string,\n event: H3Event,\n): boolean {\n if (typeof candidate !== \"string\" || candidate.length === 0) return false;\n let url: URL;\n try {\n url = new URL(candidate);\n } catch {\n return false;\n }\n // Must be same origin as our server.\n const expectedOrigin = getOrigin(event);\n let expectedUrl: URL;\n try {\n expectedUrl = new URL(expectedOrigin);\n } catch {\n return false;\n }\n if (url.protocol !== expectedUrl.protocol) return false;\n if (url.host !== expectedUrl.host) return false;\n // Must live under the framework's namespace. Workspace deploys can route\n // root /_agent-native/* to Dispatch even when Dispatch itself is mounted at\n // /dispatch, but app-prefixed requests should not be able to swap their\n // callback to that root namespace.\n const basePath = getAppBasePath();\n const allowedPrefixes =\n basePath && isRequestUnderAppBasePath(event)\n ? [`${basePath}/_agent-native/`]\n : [\"/_agent-native/\"];\n if (!allowedPrefixes.some((prefix) => url.pathname.startsWith(prefix))) {\n return false;\n }\n return true;\n}\n\n/**\n * Resolve the `redirect_uri` for an outbound OAuth `auth-url` request.\n *\n * Reads `?redirect_uri=` from the query and validates it via\n * `isAllowedOAuthRedirectUri`. Returns:\n * - the validated URI when supplied and allowed, OR\n * - the framework default when no override was supplied, OR\n * - `null` when an override was supplied but rejected — callers must\n * respond with 400 in that case.\n *\n * Templates that need a non-default redirect path can pass it via\n * `defaultPath` (e.g. `\"/_agent-native/google/desktop-callback\"` for\n * desktop flows).\n */\nexport function resolveOAuthRedirectUri(\n event: H3Event,\n defaultPath = \"/_agent-native/google/callback\",\n): string | null {\n const supplied = getQuery(event).redirect_uri;\n if (typeof supplied === \"string\" && supplied.length > 0) {\n return isAllowedOAuthRedirectUri(supplied, event) ? supplied : null;\n }\n return getDefaultOAuthRedirectUrl(event, defaultPath);\n}\n\n// ─── OAuth State ─────────────────────────────────────────────────────────────\n\nexport interface OAuthStatePayload {\n redirectUri: string;\n owner?: string;\n desktop?: boolean;\n addAccount?: boolean;\n app?: string;\n /**\n * Same-origin path to redirect to after a successful web-flow sign-in.\n * Threaded through the (HMAC-signed) state so it survives the round trip\n * to Google. Validated again on decode via safeReturnPath as defence in\n * depth. Has no effect on desktop / mobile / add-account flows, which\n * use their own deep-link / close-tab handling.\n */\n returnUrl?: string;\n flowId?: string;\n}\n\n/**\n * Ephemeral in-memory state-signing key for development. Generated lazily\n * on first read so dev sessions don't depend on filesystem writability or\n * env-var configuration. Sessions reset on each restart, which is fine\n * for dev — no real users / production data are involved.\n */\nlet _devStateSigningKey: string | undefined;\n\n/**\n * Derive a server-only signing key for HMAC verification of OAuth state.\n *\n * Uses a dedicated secret — never an OAuth client secret. Reusing a\n * client_secret (which is shared with Google / GitHub / Atlassian) as our\n * own HMAC key conflates two trust domains: rotating the client secret\n * silently invalidates every in-flight OAuth state, and any leak of the\n * client secret also lets an attacker forge our state envelopes.\n *\n * Resolution order:\n * 1. OAUTH_STATE_SECRET (preferred — dedicated to this purpose)\n * 2. BETTER_AUTH_SECRET (already used by Better Auth as a server secret)\n * 3. In dev only, an ephemeral random key (per-process)\n *\n * In production, throws if neither secret is set.\n */\nfunction getStateSigningKey(): string {\n const secret =\n process.env.OAUTH_STATE_SECRET || process.env.BETTER_AUTH_SECRET;\n if (secret) return secret;\n\n const isProd = process.env.NODE_ENV === \"production\";\n if (isProd) {\n throw new Error(\n \"OAuth state signing requires a server secret. \" +\n \"Set OAUTH_STATE_SECRET or BETTER_AUTH_SECRET in production.\",\n );\n }\n\n if (!_devStateSigningKey) {\n _devStateSigningKey = crypto.randomBytes(32).toString(\"hex\");\n }\n return _devStateSigningKey;\n}\n\n/**\n * Options for the named-argument form of {@link encodeOAuthState}.\n * Prefer this form — the positional overload is easy to misuse (the mail\n * and calendar templates historically passed `flowId` in the `returnUrl`\n * slot, smuggling state into a defence-in-depth path).\n */\nexport interface EncodeOAuthStateOptions {\n redirectUri: string;\n owner?: string;\n desktop?: boolean;\n addAccount?: boolean;\n app?: string;\n returnUrl?: string;\n flowId?: string;\n}\n\n/**\n * Encode OAuth state into a signed base64url string.\n * The state is HMAC-signed so the callback can verify it wasn't forged,\n * preventing CSRF attacks on the OAuth flow.\n *\n * Two call shapes are supported:\n * - Recommended: pass an options object — clear, mismatch-proof.\n * `encodeOAuthState({ redirectUri, owner, desktop, ... })`\n * - Legacy positional form (kept working for backward compatibility):\n * `encodeOAuthState(redirectUri, owner, desktop, addAccount, app, returnUrl, flowId)`.\n * Callers should migrate to the options form — see the audit on\n * templates/mail and templates/calendar where the positional shape\n * led to `flowId` being smuggled in via the `returnUrl` slot.\n */\nexport function encodeOAuthState(opts: EncodeOAuthStateOptions): string;\nexport function encodeOAuthState(\n redirectUri: string,\n owner?: string,\n desktop?: boolean,\n addAccount?: boolean,\n app?: string,\n returnUrl?: string,\n flowId?: string,\n): string;\nexport function encodeOAuthState(\n redirectUriOrOpts: string | EncodeOAuthStateOptions,\n owner?: string,\n desktop?: boolean,\n addAccount?: boolean,\n app?: string,\n returnUrl?: string,\n flowId?: string,\n): string {\n const opts: EncodeOAuthStateOptions =\n typeof redirectUriOrOpts === \"string\"\n ? {\n redirectUri: redirectUriOrOpts,\n owner,\n desktop,\n addAccount,\n app,\n returnUrl,\n flowId,\n }\n : redirectUriOrOpts;\n\n const nonce = crypto.randomBytes(8).toString(\"hex\");\n const payload: Record<string, string | boolean> = {\n n: nonce,\n r: opts.redirectUri,\n };\n if (opts.owner) payload.o = opts.owner;\n if (opts.desktop) payload.d = true;\n if (opts.addAccount) payload.a = true;\n if (opts.app) payload.app = opts.app;\n if (opts.returnUrl) payload.r2 = opts.returnUrl;\n if (opts.flowId) payload.f = opts.flowId;\n const data = Buffer.from(JSON.stringify(payload)).toString(\"base64url\");\n const sig = crypto\n .createHmac(\"sha256\", getStateSigningKey())\n .update(data)\n .digest(\"base64url\");\n return `${data}.${sig}`;\n}\n\n/**\n * Decode and verify OAuth state from the callback's state query parameter.\n * Rejects forged or tampered state by checking the HMAC signature.\n * Falls back to the provided URI if decoding or verification fails.\n */\nexport function decodeOAuthState(\n stateParam: string | undefined,\n fallbackUri: string,\n): OAuthStatePayload {\n if (stateParam) {\n try {\n const dotIdx = stateParam.lastIndexOf(\".\");\n if (dotIdx === -1) return { redirectUri: fallbackUri };\n\n const data = stateParam.slice(0, dotIdx);\n const sig = stateParam.slice(dotIdx + 1);\n const expected = crypto\n .createHmac(\"sha256\", getStateSigningKey())\n .update(data)\n .digest(\"base64url\");\n\n if (\n sig.length !== expected.length ||\n !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))\n ) {\n return { redirectUri: fallbackUri };\n }\n\n const parsed = JSON.parse(Buffer.from(data, \"base64url\").toString());\n return {\n redirectUri: parsed.r || fallbackUri,\n owner: parsed.o || undefined,\n desktop: !!parsed.d,\n addAccount: !!parsed.a,\n app: typeof parsed.app === \"string\" ? parsed.app : undefined,\n // Pass returnUrl through as-is — same-origin validation runs at the\n // consumer (oauthCallbackResponse → safeReturnPath). The state is\n // HMAC-signed, but we still validate at consumption as defence in\n // depth in case the signing key ever leaks.\n returnUrl: typeof parsed.r2 === \"string\" ? parsed.r2 : undefined,\n flowId: parsed.f || undefined,\n };\n } catch {}\n }\n return { redirectUri: fallbackUri };\n}\n\n// ─── Session Creation ────────────────────────────────────────────────────────\n\nexport interface OAuthOwnerResult {\n owner: string | undefined;\n isDevSession: boolean;\n hasProductionSession: boolean;\n}\n\n/**\n * Determine the token owner from the current session and OAuth state.\n * Call this BEFORE exchangeCode to get the owner parameter.\n */\nexport async function resolveOAuthOwner(\n event: H3Event,\n stateOwner?: string,\n): Promise<OAuthOwnerResult> {\n const existingSession = await getSession(event);\n const isDevSession = existingSession?.email === \"local@localhost\";\n const hasProductionSession = !!(existingSession?.email && !isDevSession);\n\n // Never use \"local@localhost\" as a token owner — it creates shared-ownership\n // bugs where multiple users can see the same tokens.\n const owner = hasProductionSession\n ? existingSession!.email\n : stateOwner || undefined;\n\n return { owner, isDevSession, hasProductionSession };\n}\n\nexport interface OAuthSessionResult {\n sessionToken: string | undefined;\n}\n\n/**\n * Create a session token after a successful OAuth exchange.\n *\n * Desktop and mobile apps have separate cookie jars from the system\n * browser, so they always get a fresh session token (even if the browser\n * already has one). The token is then passed via deep link so the native\n * app can inject it.\n */\nexport async function createOAuthSession(\n event: H3Event,\n email: string,\n opts: {\n hasProductionSession: boolean;\n desktop?: boolean;\n },\n): Promise<OAuthSessionResult> {\n const mobile = isMobile(event);\n const needsDeepLink = opts.desktop || mobile;\n const maxAge = getSessionMaxAge();\n\n let sessionToken: string | undefined;\n if (!opts.hasProductionSession || needsDeepLink) {\n sessionToken = crypto.randomBytes(32).toString(\"hex\");\n await addSession(sessionToken, email);\n setCookie(event, COOKIE_NAME, sessionToken, {\n httpOnly: true,\n secure: process.env.NODE_ENV === \"production\",\n sameSite: \"lax\",\n path: \"/\",\n maxAge,\n });\n // Desktop SSO: record this session in the home-dir broker file so\n // sibling templates (each with its own database) can resolve the\n // same token without a DB row of their own. Only the PRIMARY\n // sign-in writes the broker — if a production session already\n // exists, this is an add-account flow (connecting a secondary\n // Google account for scraping) and must never switch the active\n // user across sibling templates.\n if (opts.desktop && !opts.hasProductionSession) {\n await writeDesktopSso({\n email,\n token: sessionToken,\n expiresAt: Date.now() + maxAge * 1000,\n });\n }\n }\n\n return { sessionToken };\n}\n\n// ─── Callback Responses ──────────────────────────────────────────────────────\n\n/**\n * Return the appropriate response after a successful OAuth callback.\n *\n * Handles mobile deep links, desktop deep links, add-account close-tab\n * pages, and plain web redirects — so templates don't have to.\n */\nexport function oauthCallbackResponse(\n event: H3Event,\n email: string,\n opts: {\n sessionToken?: string;\n desktop?: boolean;\n addAccount?: boolean;\n /**\n * Same-origin path to return the viewer to after a successful web\n * sign-in. Validated via safeReturnPath; falls back to \"/\" for any\n * shape that escapes same-origin. Has no effect on desktop / mobile\n * / add-account flows — those use their own deep-link handling.\n */\n returnUrl?: string;\n flowId?: string;\n appName?: string;\n },\n): Response | string | unknown | Promise<Response | string | unknown> {\n const mobile = isMobile(event);\n const query = getQuery(event);\n const callbackState =\n typeof query.state === \"string\" && query.state.length > 0\n ? query.state\n : undefined;\n\n // Mobile: deep link back to native app\n if (mobile) {\n const deepLink = buildOAuthCompleteDeepLink(\n opts.sessionToken,\n callbackState,\n );\n return htmlResponse(\n `<!DOCTYPE html><html><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\"><title>Connected</title></head><body style=\"background:#111;color:#aaa;font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0\"><p>Connected! Returning to app…</p><script>window.location.href=${JSON.stringify(deepLink)};setTimeout(function(){window.location.href=\"/\"},1500)</script></body></html>`,\n );\n }\n\n // Desktop add-account: close-tab page (must come before general desktop check\n // to ensure no deep link fires and the existing session is never switched).\n if (opts.desktop && opts.addAccount) {\n const safeEmail = email ? escapeHtml(email) : \"\";\n const safeAppName = escapeHtml(resolveOAuthAppName(opts.appName));\n const msg = safeEmail ? `Connected ${safeEmail}!` : \"Connected!\";\n return htmlResponse(\n `<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Connected</title></head><body style=\"background:#111;color:#ccc;font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;flex-direction:column;gap:8px\"><p style=\"font-size:16px\">${msg}</p><p style=\"font-size:13px;color:#888\">You can close this tab and return to ${safeAppName}.</p></body></html>`,\n );\n }\n\n // Electron desktop exchange flow: mail/calendar still pass a flow id so the\n // renderer can poll as a fallback, but the main handoff should use the\n // protocol deep link so the popup returns focus to the desktop app.\n if (opts.desktop && opts.flowId && isElectron(event) && opts.sessionToken) {\n return desktopSuccessPage(event, email, opts.sessionToken, callbackState);\n }\n\n // Desktop exchange flow (non-Electron tray app): the tray app polls the\n // desktop-exchange endpoint for the token — no deep link needed.\n if (opts.desktop && opts.flowId) {\n const safeEmail = email ? escapeHtml(email) : \"\";\n const safeAppName = escapeHtml(resolveOAuthAppName(opts.appName));\n const msg = safeEmail ? `Signed in as ${safeEmail}!` : \"Signed in!\";\n return htmlResponse(\n `<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Connected</title></head><body style=\"background:#111;color:#ccc;font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;flex-direction:column;gap:8px\"><p style=\"font-size:16px\">${msg}</p><p style=\"font-size:13px;color:#888\">You can close this tab and return to ${safeAppName}.</p></body></html>`,\n );\n }\n\n // Desktop login: deep link back to Electron app\n if (opts.desktop) {\n return desktopSuccessPage(event, email, opts.sessionToken, callbackState);\n }\n\n // Add-account web flow: close-tab page. The email is rendered into the\n // page via DOM `textContent` (safe), but we still JSON-stringify so a\n // payload containing `</script>` can't break out of the script tag —\n // and explicitly assert it's a string so a callbacks like `null` or\n // an object won't end up serialised into the page.\n if (opts.addAccount) {\n const safeEmail = JSON.stringify(typeof email === \"string\" ? email : \"\");\n return htmlResponse(`<!DOCTYPE html><html><body><script>\n window.close();\n var p = document.createElement('p');\n p.style.cssText = 'font-family:system-ui;text-align:center;margin-top:40vh';\n p.textContent = 'Connected ' + ${safeEmail} + '! You can close this tab.';\n document.body.appendChild(p);\n </script></body></html>`);\n }\n\n // Web: redirect to the requested return path (validated same-origin) or\n // \"/\" if no return was supplied / the return failed validation. Returning\n // an empty string body keeps h3's `prepareResponseBody` → `FastResponse`\n // path, which merges the prepared event headers (Location + any cookies\n // set via `setCookie(event, ...)`).\n setResponseStatus(event, 302);\n setResponseHeader(event, \"Location\", safeReturnPath(opts.returnUrl));\n return \"\";\n}\n\n/** HTML error page for OAuth failures. The message is HTML-escaped — most\n * callers pass `error.message` from a token-exchange or userinfo failure,\n * which can echo upstream provider strings (and historically attacker-\n * controlled query params via the `error_description` field). */\nexport function oauthErrorPage(message: string): Response {\n const safe = escapeHtml(message);\n return htmlResponse(\n `<!DOCTYPE html><html><body>\n <div style=\"font-family:system-ui;max-width:420px;margin:30vh auto;text-align:center\">\n <p style=\"font-size:15px;color:#e55\">${safe}</p>\n <p style=\"margin-top:16px;font-size:13px;color:#888\"><a href=\"/\" style=\"color:#888\">Back to login</a></p>\n </div>\n </body></html>`,\n 400,\n );\n}\n\nexport function oauthDesktopExchangePage(\n message = \"Returning to the app...\",\n): Response {\n const safe = escapeHtml(message);\n return htmlResponse(\n `<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Returning</title></head><body style=\"background:#111;color:#aaa;font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0\"><p style=\"font-size:14px\">${safe}</p><script>window.close()</script></body></html>`,\n );\n}\n\n// ─── Internal ────────────────────────────────────────────────────────────────\n\nfunction resolveOAuthAppName(explicit?: string): string {\n const raw = explicit || getAppName() || \"Agent Native\";\n if (!/^[a-z0-9_-]+$/.test(raw)) return raw;\n return raw\n .split(/[-_]+/)\n .filter(Boolean)\n .map((word) => word[0].toUpperCase() + word.slice(1))\n .join(\" \");\n}\n\nfunction buildOAuthCompleteDeepLink(\n sessionToken?: string,\n state?: string,\n): string {\n const params = new URLSearchParams();\n if (sessionToken) params.set(\"token\", sessionToken);\n if (state) params.set(\"state\", state);\n const suffix = params.toString();\n return suffix\n ? `agentnative://oauth-complete?${suffix}`\n : \"agentnative://oauth-complete\";\n}\n\nfunction desktopSuccessPage(\n _event: H3Event,\n email?: string,\n sessionToken?: string,\n state?: string,\n): Response {\n const safeEmail = email ? escapeHtml(email) : \"\";\n const msg = safeEmail ? `Connected ${safeEmail}!` : \"Connected!\";\n if (sessionToken) {\n const deepLink = buildOAuthCompleteDeepLink(sessionToken, state);\n const deepLinkJson = JSON.stringify(deepLink);\n return htmlResponse(\n `<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Connected</title><style>@keyframes spin{to{transform:rotate(360deg)}}@keyframes fadeIn{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.spinner{width:28px;height:28px;border:2px solid #333;border-top-color:#fff;border-radius:50%;animation:spin .8s linear infinite}.fallback{display:none;flex-direction:column;align-items:center;gap:8px;animation:fadeIn .2s ease-out}.fallback.show{display:flex}</style></head><body style=\"background:#111;color:#ccc;font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;flex-direction:column;gap:16px\"><p style=\"font-size:16px;margin:0\">${msg}</p><div id=\"loading\" class=\"spinner\"></div><div id=\"fallback\" class=\"fallback\"><a href=${deepLinkJson} style=\"display:inline-block;padding:10px 24px;background:#fff;color:#000;border-radius:8px;text-decoration:none;font-size:14px;font-weight:500\">Open Agent Native</a><p style=\"font-size:12px;color:#666;margin:0\">If the app didn\\u2019t open automatically, click the button above.</p></div><script>window.location.href=${deepLinkJson};setTimeout(function(){document.getElementById(\"loading\").style.display=\"none\";document.getElementById(\"fallback\").classList.add(\"show\")},3000)</script></body></html>`,\n );\n }\n return htmlResponse(\n `<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Connected</title></head><body style=\"background:#111;color:#ccc;font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;flex-direction:column;gap:8px\"><p style=\"font-size:16px\">${msg}</p><p style=\"font-size:13px;color:#888\">You can close this tab and return to Agent Native.</p></body></html>`,\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"onboarding-html.d.ts","sourceRoot":"","sources":["../../src/server/onboarding-html.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAmBH,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,SAAS,CAAC,EAAE;QACV,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;CACH;AAED,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,qBAA0B,GAAG,MAAM,CAygC1E;AAED,kDAAkD;AAClD,eAAO,MAAM,eAAe,QAAsB,CAAC;AAEnD;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAwG7C"}
1
+ {"version":3,"file":"onboarding-html.d.ts","sourceRoot":"","sources":["../../src/server/onboarding-html.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAkCH,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,SAAS,CAAC,EAAE;QACV,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;CACH;AAED,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,qBAA0B,GAAG,MAAM,CAghC1E;AAED,kDAAkD;AAClD,eAAO,MAAM,eAAe,QAAsB,CAAC;AAEnD;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAwG7C"}
@@ -26,11 +26,25 @@ function getConnectionLabel() {
26
26
  return "Turso";
27
27
  return "SQL database";
28
28
  }
29
+ function normalizeAppBasePath(value) {
30
+ if (!value || value === "/")
31
+ return "";
32
+ const trimmed = value.trim();
33
+ if (!trimmed || trimmed === "/")
34
+ return "";
35
+ return `/${trimmed.replace(/^\/+/, "").replace(/\/+$/, "")}`;
36
+ }
37
+ function withAppBasePath(path) {
38
+ const cleanPath = path.startsWith("/") ? path : `/${path}`;
39
+ const basePath = normalizeAppBasePath(process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH);
40
+ return `${basePath}${cleanPath}`;
41
+ }
29
42
  export function getOnboardingHtml(opts = {}) {
30
43
  const showGoogle = hasGoogleOAuth();
31
44
  const googleOnly = !!opts.googleOnly;
32
45
  const marketing = opts.marketing;
33
46
  const hasMarketing = !!marketing;
47
+ const brandMarkSrc = withAppBasePath("/agent-native-icon-dark.svg");
34
48
  const esc = (s) => s
35
49
  .replace(/&/g, "&amp;")
36
50
  .replace(/</g, "&lt;")
@@ -156,7 +170,7 @@ export function getOnboardingHtml(opts = {}) {
156
170
  <div class="marketing-panel">
157
171
  <div class="marketing-content">
158
172
  <h2 class="app-name">
159
- <img class="brand-mark" src="/agent-native-icon-dark.svg" alt="" aria-hidden="true" />
173
+ <img class="brand-mark" src="${esc(brandMarkSrc)}" alt="" aria-hidden="true" />
160
174
  <span>${esc(marketing.appName)}</span>
161
175
  </h2>
162
176
  <p class="app-tagline">${esc(marketing.tagline)}</p>
@@ -810,10 +824,16 @@ ${googleOnly
810
824
  try {
811
825
  var params = new URLSearchParams(location.search);
812
826
  var qp = params.get('tab');
827
+ var path = location.pathname;
828
+ while (path.length > 1 && path.charAt(path.length - 1) === '/') path = path.slice(0, -1);
813
829
  if (qp === 'login' || qp === 'signup') {
814
830
  initial = qp;
815
831
  } else if (params.has('verified')) {
816
832
  initial = 'login';
833
+ } else if (path === '/login' || path.endsWith('/login')) {
834
+ initial = 'login';
835
+ } else if (path === '/signup' || path.endsWith('/signup')) {
836
+ initial = 'signup';
817
837
  } else {
818
838
  var stored = localStorage.getItem(TAB_STORAGE_KEY);
819
839
  if (stored === 'login' || stored === 'signup') initial = stored;