@agent-native/core 0.20.5 → 0.20.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"useBuilderStatus.d.ts","sourceRoot":"","sources":["../../../src/client/settings/useBuilderStatus.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,WAAW,GAAG,KAAK,CAAC;IACxD,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,YAAY,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C;;;;OAIG;IACH,SAAS,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C;AAED;;;GAGG;AACH,wBAAgB,gBAAgB;;;;EA4C/B;AAkBD,MAAM,WAAW,yBAAyB;IACxC,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3E;AAED,MAAM,WAAW,0BAA0B;IACzC,qDAAqD;IACrD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mDAAmD;IACnD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,UAAU,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB;;;;;;;OAOG;IACH,gBAAgB,EAAE,OAAO,CAAC;IAC1B,oFAAoF;IACpF,KAAK,EAAE,CAAC,OAAO,CAAC,EAAE,0BAA0B,KAAK,IAAI,CAAC;CACvD;AAyCD,wBAAgB,gCAAgC,CAC9C,GAAG,EAAE,MAAM,EACX,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/C,MAAM,CAwCR;AAuID,MAAM,WAAW,8BAA8B;IAC7C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,uBAAuB,CAAC,EACtC,GAAG,EACH,MAA0B,EAC1B,IAAI,EACJ,QAAgC,GACjC,GAAE,8BAAmC,GAAG,MAAM,GAAG,IAAI,CA2CrD;AAED,wBAAgB,qBAAqB,CACnC,IAAI,GAAE,yBAA8B,GACnC,kBAAkB,CAqdpB"}
1
+ {"version":3,"file":"useBuilderStatus.d.ts","sourceRoot":"","sources":["../../../src/client/settings/useBuilderStatus.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,WAAW,GAAG,KAAK,CAAC;IACxD,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,YAAY,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C;;;;OAIG;IACH,SAAS,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C;AAED;;;GAGG;AACH,wBAAgB,gBAAgB;;;;EA4C/B;AAkBD,MAAM,WAAW,yBAAyB;IACxC,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3E;AAED,MAAM,WAAW,0BAA0B;IACzC,qDAAqD;IACrD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mDAAmD;IACnD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,UAAU,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB;;;;;;;OAOG;IACH,gBAAgB,EAAE,OAAO,CAAC;IAC1B,oFAAoF;IACpF,KAAK,EAAE,CAAC,OAAO,CAAC,EAAE,0BAA0B,KAAK,IAAI,CAAC;CACvD;AAyCD,wBAAgB,gCAAgC,CAC9C,GAAG,EAAE,MAAM,EACX,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/C,MAAM,CAwCR;AAuID,MAAM,WAAW,8BAA8B;IAC7C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,uBAAuB,CAAC,EACtC,GAAG,EACH,MAA0B,EAC1B,IAAI,EACJ,QAAgC,GACjC,GAAE,8BAAmC,GAAG,MAAM,GAAG,IAAI,CA2CrD;AAED,wBAAgB,qBAAqB,CACnC,IAAI,GAAE,yBAA8B,GACnC,kBAAkB,CAydpB"}
@@ -488,7 +488,10 @@ export function useBuilderConnectFlow(opts = {}) {
488
488
  statusConnectUrlAtRef.current = nextConnectUrl ? Date.now() : null;
489
489
  setOrgName(s.orgName ?? null);
490
490
  }
491
- const freshUrl = s?.cliAuthUrl ?? s?.connectUrl ?? null;
491
+ // Prefer the click-time status response, but keep a recent signed
492
+ // URL from this hook as a fallback. This avoids closing the popup
493
+ // when the refresh hits a transient 401/HTML/error response.
494
+ const freshUrl = s?.cliAuthUrl ?? s?.connectUrl ?? cachedFreshUrl ?? null;
492
495
  if (!freshUrl) {
493
496
  try {
494
497
  opened.close();
@@ -1 +1 @@
1
- {"version":3,"file":"useBuilderStatus.js","sourceRoot":"","sources":["../../../src/client/settings/useBuilderStatus.ts"],"names":[],"mappings":"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","sourcesContent":["import { agentNativePath } from \"../api-path.js\";\nimport { useState, useEffect, useCallback, useRef } from \"react\";\nimport { getCallbackOrigin } from \"../frame.js\";\nimport { trackEvent } from \"../analytics.js\";\n\nexport interface BuilderStatus {\n configured: boolean;\n builderEnabled: boolean;\n /**\n * True when `BUILDER_PRIVATE_KEY` is set at the deploy level. This is a\n * fallback credential; per-user/org Builder connections are still allowed\n * and take precedence for that request.\n */\n envManaged?: boolean;\n credentialSource?: \"user\" | \"org\" | \"workspace\" | \"env\";\n connectUrl: string;\n cliAuthUrl?: string;\n appHost: string;\n apiHost: string;\n branchProjectIdConfigured?: boolean;\n branchProjectId?: string;\n publicKeyConfigured: boolean;\n privateKeyConfigured: boolean;\n userId?: string;\n orgName?: string;\n orgKind?: string;\n /**\n * Set when the OAuth callback ran but failed to persist credentials.\n * Surfaced as a one-shot row by the server so the connect-flow polling\n * can stop with a clear message instead of timing out at 5min.\n */\n connectError?: { message: string; at: number };\n /**\n * Set when the currently effective Builder credential was rejected by\n * Builder's API. Unlike connectError, this describes the old credential pair\n * and should not abort a new reconnect attempt while the popup is open.\n */\n authError?: { message: string; at: number };\n}\n\n/**\n * Fetches Builder connection status from /_agent-native/builder/status.\n * Re-fetches on window focus to detect post-redirect state changes.\n */\nexport function useBuilderStatus() {\n const [status, setStatus] = useState<BuilderStatus | null>(null);\n const [loading, setLoading] = useState(true);\n\n const fetchStatus = useCallback(async () => {\n try {\n const res = await fetch(agentNativePath(\"/_agent-native/builder/status\"));\n if (!res.ok) {\n setStatus(null);\n return;\n }\n setStatus(await res.json());\n } catch {\n setStatus(null);\n } finally {\n setLoading(false);\n }\n }, []);\n\n useEffect(() => {\n fetchStatus();\n\n function onFocus() {\n fetchStatus();\n }\n function onVisibility() {\n if (document.visibilityState === \"visible\") fetchStatus();\n }\n window.addEventListener(\"focus\", onFocus);\n document.addEventListener(\"visibilitychange\", onVisibility);\n // Engine connect/disconnect actions (e.g. the Builder disconnect button)\n // dispatch this event so dependent cards refresh without a full reload.\n window.addEventListener(\"agent-engine:configured-changed\", fetchStatus);\n return () => {\n window.removeEventListener(\"focus\", onFocus);\n document.removeEventListener(\"visibilitychange\", onVisibility);\n window.removeEventListener(\n \"agent-engine:configured-changed\",\n fetchStatus,\n );\n };\n }, [fetchStatus]);\n\n return { status, loading, refetch: fetchStatus };\n}\n\n// ─── useBuilderConnectFlow ──────────────────────────────────────────────────\n//\n// Shared state machine for the \"open Builder CLI-auth popup + poll\n// /builder/status until credentials land\" interaction. Replaces three\n// near-duplicate inline implementations: `BuilderCliAuthMethod` in\n// OnboardingPanel, `ConnectBuilderCard`, and `BuilderConnectCta` in\n// AssistantChat. Each consumer supplies its own popup URL / completion\n// behavior; the hook owns the polling + timeout + focus refresh.\n//\n// `popupUrl` is what we pass to `window.open`. The default\n// `/_agent-native/builder/connect` is a server-side 302 to the real\n// cli-auth URL — using it keeps the click handler synchronous so popup\n// blockers don't downgrade the open to same-tab navigation. Pass an\n// explicit `popupUrl` (e.g. the already-computed cli-auth URL) if your\n// caller already has it in hand.\n\nexport interface BuilderConnectFlowOptions {\n /** Skip server status polling for hosts that own provider routing. */\n enabled?: boolean;\n /** URL to synchronously open on start(). Defaults to the 302 shortcut. */\n popupUrl?: string;\n /** Low-cardinality label for the UI surface that opened Builder connect. */\n trackingSource?: string;\n /** Product flow that needed Builder connect, e.g. connect_llm. */\n trackingFlow?: string;\n /** Invoked after the status poll first sees `configured: true`. */\n onConnected?: (state: { orgName: string | null }) => void | Promise<void>;\n}\n\nexport interface BuilderConnectStartOptions {\n /** Override the hook-level source for this click. */\n trackingSource?: string;\n /** Override the hook-level flow for this click. */\n trackingFlow?: string;\n}\n\nexport interface BuilderConnectFlow {\n configured: boolean;\n /**\n * True when the deploy has BUILDER_PRIVATE_KEY set as a fallback. Connect\n * is still available so users can override the fallback with their own\n * Builder account.\n */\n envManaged: boolean;\n /**\n * True when the server has a Builder branch project configured for this\n * request. When false, the card surfaces a waitlist CTA instead of a Send\n * button.\n */\n builderEnabled: boolean;\n orgName: string | null;\n connecting: boolean;\n error: string | null;\n /**\n * True once the first `/builder/status` fetch has completed (successfully\n * or not). Consumers that accept an `initialConfigured` prop (e.g. agent\n * tool-call results rendered with server-side state) should treat\n * `configured`/`orgName` as authoritative only once this flips true —\n * otherwise the hook's starting `false` defaults would cause a flash\n * back to \"Connect Builder\" on first paint.\n */\n hasFetchedStatus: boolean;\n /** Open the popup and begin polling. Must be called from a user-gesture handler. */\n start: (options?: BuilderConnectStartOptions) => void;\n}\n\nconst POLL_INTERVAL_MS = 2000;\nconst POLL_TIMEOUT_MS = 5 * 60 * 1000;\nconst POPUP_CLOSED_CONFIRMATION_GRACE_MS = 5000;\nconst CALLBACK_SUCCESS_STATUS_RETRY_MS = 500;\nconst CALLBACK_SUCCESS_STATUS_RETRIES = 10;\nconst BUILDER_CONNECT_PARAM = \"_an_connect\";\nconst BUILDER_STATE_PARAM = \"_an_state\";\nconst BUILDER_SIGNUP_SOURCE_PARAM = \"signupSource\";\nconst BUILDER_AGENT_NATIVE_FLOW_PARAM = \"agentNativeFlow\";\nconst BUILDER_AGENT_NATIVE_CONNECT_SOURCE_PARAM = \"agentNativeConnectSource\";\nconst BUILDER_SIGNUP_SOURCE = \"agent-native\";\nconst STATUS_CONNECT_URL_TTL_MS = 9 * 60 * 1000;\n\nfunction cleanTrackingParam(value: string | null | undefined): string | null {\n const trimmed = value?.trim();\n return trimmed ? trimmed.slice(0, 120) : null;\n}\n\nfunction inferBuilderConnectTrackingFlow(source: string | undefined): string {\n const normalized = source?.toLowerCase() ?? \"\";\n if (normalized.includes(\"background_agent\")) return \"background_agent\";\n if (\n normalized.includes(\"code_required\") ||\n normalized.includes(\"code_access\") ||\n normalized.includes(\"connect_builder_card\")\n ) {\n return \"background_agent\";\n }\n if (normalized.includes(\"browser\")) return \"browser_automation\";\n if (normalized.includes(\"voice\") || normalized.includes(\"transcription\")) {\n return \"voice_transcription\";\n }\n if (normalized.includes(\"upload\")) return \"file_upload\";\n if (normalized.includes(\"hosting\")) return \"hosting\";\n if (normalized.includes(\"database\")) return \"database\";\n if (normalized.includes(\"auth_settings\")) return \"auth\";\n return \"connect_llm\";\n}\n\nexport function withBuilderConnectTrackingParams(\n url: string,\n options: { source?: string; flow?: string } = {},\n): string {\n const source = cleanTrackingParam(options.source);\n const flow =\n cleanTrackingParam(options.flow) ??\n inferBuilderConnectTrackingFlow(source ?? undefined);\n const origin =\n typeof window !== \"undefined\" ? window.location.origin : \"http://localhost\";\n\n try {\n const parsed = new URL(url, origin);\n parsed.searchParams.set(BUILDER_SIGNUP_SOURCE_PARAM, BUILDER_SIGNUP_SOURCE);\n parsed.searchParams.set(BUILDER_AGENT_NATIVE_FLOW_PARAM, flow);\n if (source) {\n parsed.searchParams.set(\n BUILDER_AGENT_NATIVE_CONNECT_SOURCE_PARAM,\n source,\n );\n }\n\n const redirectUrl = parsed.searchParams.get(\"redirect_url\");\n if (redirectUrl) {\n const parsedRedirect = new URL(redirectUrl);\n parsedRedirect.searchParams.set(\n BUILDER_SIGNUP_SOURCE_PARAM,\n BUILDER_SIGNUP_SOURCE,\n );\n parsedRedirect.searchParams.set(BUILDER_AGENT_NATIVE_FLOW_PARAM, flow);\n if (source) {\n parsedRedirect.searchParams.set(\n BUILDER_AGENT_NATIVE_CONNECT_SOURCE_PARAM,\n source,\n );\n }\n parsed.searchParams.set(\"redirect_url\", parsedRedirect.toString());\n }\n\n return parsed.toString();\n } catch {\n return url;\n }\n}\n\nfunction isAgentNativeDesktop() {\n if (typeof navigator === \"undefined\") return false;\n return /AgentNativeDesktop/i.test(navigator.userAgent || \"\");\n}\n\nfunction hasSignedConnectToken(url: string | null | undefined): boolean {\n if (!url || typeof window === \"undefined\") return false;\n try {\n return new URL(url, window.location.origin).searchParams.has(\n BUILDER_CONNECT_PARAM,\n );\n } catch {\n return false;\n }\n}\n\nfunction hasSignedCallbackState(url: string | null | undefined): boolean {\n if (!url || typeof window === \"undefined\") return false;\n try {\n const parsed = new URL(url, window.location.origin);\n const redirectUrl = parsed.searchParams.get(\"redirect_url\");\n if (!redirectUrl) return false;\n return new URL(redirectUrl).searchParams.has(BUILDER_STATE_PARAM);\n } catch {\n return false;\n }\n}\n\nfunction isFreshSignedConnectUrl(\n url: string | null,\n fetchedAt: number | null,\n): url is string {\n return (\n (hasSignedConnectToken(url) || hasSignedCallbackState(url)) &&\n typeof fetchedAt === \"number\" &&\n Date.now() - fetchedAt < STATUS_CONNECT_URL_TTL_MS\n );\n}\n\nfunction isCurrentConnectError(\n error: { message: string; at: number } | undefined,\n startedAt: number | null,\n): error is { message: string; at: number } {\n if (!error?.message) return false;\n if (!startedAt) return true;\n return typeof error.at !== \"number\" || error.at >= startedAt - 1000;\n}\n\nfunction showBuilderConnectPopupPlaceholder(opened: Window) {\n // Keep opener attached: the Builder callback uses postMessage to notify the\n // settings tab that the popup completed. We still hold the WindowProxy so the\n // parent can navigate the blank popup after refreshing the signed connect URL.\n try {\n opened.document.title = \"Opening Builder.io\";\n opened.document.body.style.margin = \"0\";\n opened.document.body.style.background = \"#111\";\n opened.document.body.style.color = \"#ddd\";\n opened.document.body.style.fontFamily =\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif';\n opened.document.body.style.display = \"flex\";\n opened.document.body.style.alignItems = \"center\";\n opened.document.body.style.justifyContent = \"center\";\n opened.document.body.style.height = \"100vh\";\n opened.document.body.textContent = \"Opening Builder.io...\";\n } catch {\n // Popup may already be cross-origin or browser may block document writes.\n }\n}\n\nfunction navigateBuilderConnectPopup(opened: Window, url: string): boolean {\n try {\n opened.location.href = url;\n return true;\n } catch {\n try {\n opened.close();\n } catch {\n // Ignore close failures.\n }\n return false;\n }\n}\n\nfunction notifyAgentEngineConfiguredChanged(source: string) {\n if (typeof window === \"undefined\") return;\n window.dispatchEvent(\n new CustomEvent(\"agent-engine:configured-changed\", {\n detail: { source },\n }),\n );\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction isPopupClosed(opened: Window | null): boolean {\n if (!opened) return false;\n try {\n return opened.closed === true;\n } catch {\n return false;\n }\n}\n\nfunction isTrustedBuilderConnectMessageOrigin(origin: string): boolean {\n if (typeof window !== \"undefined\" && origin === window.location.origin) {\n return true;\n }\n try {\n const hostname = new URL(origin).hostname.toLowerCase();\n return (\n hostname === \"localhost\" ||\n hostname === \"127.0.0.1\" ||\n hostname === \"::1\" ||\n hostname === \"builder.io\" ||\n hostname.endsWith(\".builder.io\") ||\n hostname === \"builder.my\" ||\n hostname.endsWith(\".builder.my\") ||\n hostname === \"builderio.xyz\" ||\n hostname.endsWith(\".builderio.xyz\") ||\n hostname === \"builderio.dev\" ||\n hostname.endsWith(\".builderio.dev\") ||\n hostname === \"builder.codes\" ||\n hostname.endsWith(\".builder.codes\") ||\n hostname === \"agent-native.com\" ||\n hostname.endsWith(\".agent-native.com\")\n );\n } catch {\n return false;\n }\n}\n\nexport interface OpenBuilderConnectPopupOptions {\n url?: string;\n source?: string;\n flow?: string;\n features?: string;\n}\n\nexport function openBuilderConnectPopup({\n url,\n source = \"builder_connect\",\n flow,\n features = \"noopener,noreferrer\",\n}: OpenBuilderConnectPopupOptions = {}): Window | null {\n if (typeof window === \"undefined\") return null;\n const origin = getCallbackOrigin() || window.location.origin;\n const href =\n url ??\n new URL(agentNativePath(\"/_agent-native/builder/connect\"), origin).href;\n const trackedHref =\n href === \"about:blank\"\n ? href\n : withBuilderConnectTrackingParams(href, { source, flow });\n const connectUrlKind = url ? \"provided\" : \"default\";\n const trackingFlow =\n cleanTrackingParam(flow) ?? inferBuilderConnectTrackingFlow(source);\n trackEvent(\"builder connect clicked\", {\n feature: \"builder\",\n stage: \"client\",\n source,\n flow: trackingFlow,\n connect_url_kind: connectUrlKind,\n });\n try {\n const opened = window.open(trackedHref, \"_blank\", features);\n if (!opened && !/AgentNativeDesktop/i.test(navigator.userAgent || \"\")) {\n trackEvent(\"builder connect popup blocked\", {\n feature: \"builder\",\n stage: \"client\",\n source,\n flow: trackingFlow,\n connect_url_kind: connectUrlKind,\n });\n }\n return opened;\n } catch {\n trackEvent(\"builder connect failed\", {\n feature: \"builder\",\n stage: \"client\",\n reason: \"popup_open_exception\",\n source,\n flow: trackingFlow,\n connect_url_kind: connectUrlKind,\n });\n return null;\n }\n}\n\nexport function useBuilderConnectFlow(\n opts: BuilderConnectFlowOptions = {},\n): BuilderConnectFlow {\n const {\n enabled = true,\n popupUrl,\n trackingSource = \"builder_connect_flow\",\n trackingFlow,\n onConnected,\n } = opts;\n const [configured, setConfigured] = useState(false);\n const [envManaged, setEnvManaged] = useState(false);\n const [builderEnabled, setBuilderEnabled] = useState(false);\n const [orgName, setOrgName] = useState<string | null>(null);\n const [connecting, setConnecting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [hasFetchedStatus, setHasFetchedStatus] = useState(false);\n const [statusConnectUrl, setStatusConnectUrl] = useState<string | null>(null);\n // When statusConnectUrl was last fetched. The server signs the embedded\n // _an_connect token with a 10-minute TTL; using an older URL fails the\n // cross-origin popup gate. Track freshness so start() can either use a\n // still-good direct URL (desktop) or refresh a new one inside the popup\n // gesture path (browser/editor embeds).\n const statusConnectUrlAtRef = useRef<number | null>(null);\n const pollRef = useRef<ReturnType<typeof setInterval> | null>(null);\n const connectStartedAtRef = useRef<number | null>(null);\n const mountedRef = useRef(true);\n const notifiedConnectedRef = useRef(false);\n // Keep onConnected in a ref so start() doesn't need to re-create when the\n // caller passes an inline arrow function.\n const onConnectedRef = useRef(onConnected);\n onConnectedRef.current = onConnected;\n\n const stopPoll = useCallback(() => {\n if (pollRef.current) {\n clearInterval(pollRef.current);\n pollRef.current = null;\n }\n }, []);\n\n const fetchStatus = useCallback(async () => {\n if (!enabled) return null;\n const origin = getCallbackOrigin() || window.location.origin;\n try {\n const r = await fetch(\n new URL(agentNativePath(\"/_agent-native/builder/status\"), origin).href,\n );\n if (!r.ok) return null;\n return (await r.json()) as {\n configured: boolean;\n envManaged?: boolean;\n builderEnabled?: boolean;\n orgName?: string | null;\n connectUrl?: string;\n cliAuthUrl?: string;\n credentialSource?: \"user\" | \"org\" | \"workspace\" | \"env\";\n connectError?: { message: string; at: number };\n authError?: { message: string; at: number };\n };\n } catch {\n return null;\n }\n }, [enabled]);\n\n // Initial fetch + focus/visibility refresh so if the user completed the\n // flow in another tab (or a downgraded same-tab nav) we notice it. Also\n // listen for `agent-engine:configured-changed` so a Disconnect click in\n // Settings propagates to any connect-CTA cards rendered elsewhere in\n // the app without waiting for the next focus event.\n useEffect(() => {\n if (!enabled) {\n setConfigured(false);\n setEnvManaged(false);\n setBuilderEnabled(false);\n setOrgName(null);\n setConnecting(false);\n setError(null);\n setHasFetchedStatus(false);\n setStatusConnectUrl(null);\n statusConnectUrlAtRef.current = null;\n stopPoll();\n return;\n }\n mountedRef.current = true;\n let cancelled = false;\n const refresh = async () => {\n const s = await fetchStatus();\n if (cancelled || !mountedRef.current) return;\n // Flip `hasFetchedStatus` even when the fetch failed — the caller's\n // \"use initial props until the hook has an answer\" pattern wants to\n // stop waiting after we've tried, regardless of network outcome.\n setHasFetchedStatus(true);\n if (!s) return;\n setConfigured(!!s.configured);\n setEnvManaged(!!s.envManaged);\n setBuilderEnabled(!!s.builderEnabled);\n const nextConnectUrl = s.cliAuthUrl ?? s.connectUrl ?? null;\n setStatusConnectUrl(nextConnectUrl);\n statusConnectUrlAtRef.current = nextConnectUrl ? Date.now() : null;\n const org = s.orgName ?? null;\n setOrgName(org);\n if (s.configured) {\n connectStartedAtRef.current = null;\n }\n if (s.configured && !notifiedConnectedRef.current) {\n notifiedConnectedRef.current = true;\n notifyAgentEngineConfiguredChanged(\"builder-status\");\n try {\n await onConnectedRef.current?.({ orgName: org });\n } catch {\n // The caller's callback is a UI convenience; status is already set.\n }\n } else if (!s.configured) {\n notifiedConnectedRef.current = false;\n }\n // Surface persisted auth-failure messages on idle refreshes, but don't\n // let an old rejected credential abort a new reconnect popup while the\n // user is still choosing a Builder space.\n const activeConnectStartedAt = connectStartedAtRef.current;\n if (isCurrentConnectError(s.connectError, activeConnectStartedAt)) {\n setError(s.connectError.message);\n } else if (!activeConnectStartedAt && s.authError?.message) {\n setError(s.authError.message);\n } else if (s.configured) {\n setError(null);\n }\n };\n refresh();\n const onVisible = () => {\n if (document.visibilityState === \"visible\") refresh();\n };\n window.addEventListener(\"focus\", refresh);\n document.addEventListener(\"visibilitychange\", onVisible);\n window.addEventListener(\"agent-engine:configured-changed\", refresh);\n return () => {\n cancelled = true;\n mountedRef.current = false;\n window.removeEventListener(\"focus\", refresh);\n document.removeEventListener(\"visibilitychange\", onVisible);\n window.removeEventListener(\"agent-engine:configured-changed\", refresh);\n stopPoll();\n };\n }, [enabled, fetchStatus, stopPoll]);\n\n const start = useCallback(\n (startOptions?: BuilderConnectStartOptions) => {\n if (!enabled) return;\n stopPoll();\n const started = Date.now();\n const clickTrackingSource =\n startOptions?.trackingSource ?? trackingSource;\n const clickTrackingFlow = startOptions?.trackingFlow ?? trackingFlow;\n let openedPopup: Window | null = null;\n let popupClosedAt: number | null = null;\n connectStartedAtRef.current = started;\n setConnecting(true);\n setError(null);\n\n // Open SYNCHRONOUSLY inside the caller's click handler — any await\n // before window.open lets the user-gesture token expire, which causes\n // popup blockers to block entirely or fall back to same-tab navigation.\n const origin = getCallbackOrigin() || window.location.origin;\n const cachedFreshUrl = isFreshSignedConnectUrl(\n statusConnectUrl,\n statusConnectUrlAtRef.current,\n )\n ? statusConnectUrl\n : null;\n // popupUrl props and statusConnectUrl are signed URLs minted before the\n // click. In web browsers, always refresh inside an about:blank popup so a\n // server/package restart cannot leave the user with a stale signed state.\n // Desktop keeps the direct path because the Electron shell owns the popup.\n const signedPropUrl = hasSignedConnectToken(popupUrl) ? popupUrl : null;\n const signedCliPropUrl = hasSignedCallbackState(popupUrl)\n ? popupUrl\n : null;\n const fallbackUrl = new URL(\n agentNativePath(\"/_agent-native/builder/connect\"),\n origin,\n ).href;\n const directUrl =\n cachedFreshUrl ?? signedCliPropUrl ?? signedPropUrl ?? fallbackUrl;\n\n if (isAgentNativeDesktop()) {\n const opened = openBuilderConnectPopup({\n url: directUrl,\n source: clickTrackingSource,\n flow: clickTrackingFlow,\n });\n openedPopup = opened;\n if (!opened) {\n // Agent Native Desktop handles the popup in Electron and reports\n // null to the embedded webview, so null is not a blocker here.\n }\n } else {\n const opened = openBuilderConnectPopup({\n url: \"about:blank\",\n source: clickTrackingSource,\n flow: clickTrackingFlow,\n features: \"width=600,height=700\",\n });\n if (!opened) {\n connectStartedAtRef.current = null;\n setConnecting(false);\n setError(\"Couldn't open Builder. Allow popups and try again.\");\n return;\n }\n openedPopup = opened;\n showBuilderConnectPopupPlaceholder(opened);\n void (async () => {\n const s = await fetchStatus();\n if (!mountedRef.current) {\n try {\n opened.close();\n } catch {\n // Ignore close failures.\n }\n return;\n }\n if (s) {\n setHasFetchedStatus(true);\n setConfigured(!!s.configured);\n setEnvManaged(!!s.envManaged);\n setBuilderEnabled(!!s.builderEnabled);\n const nextConnectUrl = s.cliAuthUrl ?? s.connectUrl ?? null;\n setStatusConnectUrl(nextConnectUrl);\n statusConnectUrlAtRef.current = nextConnectUrl ? Date.now() : null;\n setOrgName(s.orgName ?? null);\n }\n\n const freshUrl = s?.cliAuthUrl ?? s?.connectUrl ?? null;\n if (!freshUrl) {\n try {\n opened.close();\n } catch {\n // Ignore close failures.\n }\n stopPoll();\n connectStartedAtRef.current = null;\n setConnecting(false);\n setError(\n \"Couldn't start Builder connect. Refresh this page and try again.\",\n );\n return;\n }\n const trackedFreshUrl = withBuilderConnectTrackingParams(freshUrl, {\n source: clickTrackingSource,\n flow: clickTrackingFlow,\n });\n if (!navigateBuilderConnectPopup(opened, trackedFreshUrl)) {\n stopPoll();\n connectStartedAtRef.current = null;\n setConnecting(false);\n setError(\n \"Couldn't navigate the Builder popup. Allow popups and try again.\",\n );\n }\n })();\n }\n\n pollRef.current = setInterval(async () => {\n const s = await fetchStatus();\n if (!mountedRef.current) {\n stopPoll();\n return;\n }\n if (s?.configured) {\n stopPoll();\n setConfigured(true);\n setEnvManaged(!!s.envManaged);\n setBuilderEnabled(!!s.builderEnabled);\n const nextConnectUrl = s.cliAuthUrl ?? s.connectUrl ?? null;\n setStatusConnectUrl(nextConnectUrl);\n statusConnectUrlAtRef.current = nextConnectUrl ? Date.now() : null;\n const org = s.orgName ?? null;\n setOrgName(org);\n setConnecting(false);\n connectStartedAtRef.current = null;\n notifiedConnectedRef.current = true;\n notifyAgentEngineConfiguredChanged(\"builder-connect\");\n try {\n await onConnectedRef.current?.({ orgName: org });\n } catch {\n // Consumer's callback failed; we've already flipped the UI state\n // to connected. Swallow so we don't re-arm the flow.\n }\n } else if (isCurrentConnectError(s?.connectError, started)) {\n // OAuth callback ran but writeBuilderCredentials threw — surface the\n // real error instead of letting the user wait 5 minutes for timeout.\n stopPoll();\n connectStartedAtRef.current = null;\n setConnecting(false);\n setError(\n `Couldn't save Builder credentials: ${s.connectError.message}. Try again or contact support.`,\n );\n } else if (isPopupClosed(openedPopup)) {\n popupClosedAt ??= Date.now();\n if (Date.now() - popupClosedAt > POPUP_CLOSED_CONFIRMATION_GRACE_MS) {\n stopPoll();\n connectStartedAtRef.current = null;\n setConnecting(false);\n trackEvent(\"builder connect failed\", {\n feature: \"builder\",\n stage: \"client\",\n reason: \"popup_closed_without_status\",\n source: clickTrackingSource,\n flow:\n cleanTrackingParam(clickTrackingFlow) ??\n inferBuilderConnectTrackingFlow(clickTrackingSource),\n });\n setError(\n \"Builder finished, but this workspace couldn't confirm the saved credentials. Refresh this page or try Connect Builder.io again.\",\n );\n }\n } else if (Date.now() - started > POLL_TIMEOUT_MS) {\n stopPoll();\n connectStartedAtRef.current = null;\n setConnecting(false);\n trackEvent(\"builder connect failed\", {\n feature: \"builder\",\n stage: \"client\",\n reason: \"timeout\",\n source: clickTrackingSource,\n flow:\n cleanTrackingParam(clickTrackingFlow) ??\n inferBuilderConnectTrackingFlow(clickTrackingSource),\n });\n setError(\n \"Didn't hear back from Builder in 5 minutes. Allow popups and try again.\",\n );\n }\n }, POLL_INTERVAL_MS);\n },\n [\n enabled,\n fetchStatus,\n popupUrl,\n statusConnectUrl,\n stopPoll,\n trackingFlow,\n trackingSource,\n ],\n );\n\n // Popup-side fast path: the callback page broadcasts a message so we stop\n // polling immediately rather than waiting for the next 2s tick.\n //\n // We listen on BroadcastChannel (same-origin, works with noopener popups)\n // AND on window.message (legacy path for environments without BC or for\n // popups that still have opener access). Both paths are safe to have open\n // simultaneously \\u2014 the first one to fire wins and the error is deduplicated\n // by the stopPoll() call which is idempotent.\n useEffect(() => {\n let channel: BroadcastChannel | null = null;\n const handleError = (message: string) => {\n stopPoll();\n connectStartedAtRef.current = null;\n setConnecting(false);\n setError(`Couldn't save Builder credentials: ${message}.`);\n };\n const handleSuccess = async () => {\n let s: Awaited<ReturnType<typeof fetchStatus>> = null;\n for (let i = 0; i < CALLBACK_SUCCESS_STATUS_RETRIES; i += 1) {\n s = await fetchStatus();\n if (!mountedRef.current) return;\n if (\n s?.configured ||\n isCurrentConnectError(s?.connectError, connectStartedAtRef.current)\n ) {\n break;\n }\n if (i < CALLBACK_SUCCESS_STATUS_RETRIES - 1) {\n await delay(CALLBACK_SUCCESS_STATUS_RETRY_MS);\n }\n }\n if (!mountedRef.current) return;\n if (!s?.configured) {\n const connectError = isCurrentConnectError(\n s?.connectError,\n connectStartedAtRef.current,\n )\n ? s?.connectError\n : null;\n stopPoll();\n setHasFetchedStatus(true);\n if (s) {\n setConfigured(false);\n setEnvManaged(!!s.envManaged);\n setBuilderEnabled(!!s.builderEnabled);\n const nextConnectUrl = s.cliAuthUrl ?? s.connectUrl ?? null;\n setStatusConnectUrl(nextConnectUrl);\n statusConnectUrlAtRef.current = nextConnectUrl ? Date.now() : null;\n setOrgName(s.orgName ?? null);\n }\n connectStartedAtRef.current = null;\n setConnecting(false);\n setError(\n connectError\n ? `Couldn't save Builder credentials: ${connectError.message}. Try again or contact support.`\n : \"Builder finished, but this workspace couldn't confirm the saved credentials. Refresh this page or try Connect Builder.io again.\",\n );\n return;\n }\n stopPoll();\n setHasFetchedStatus(true);\n setConfigured(true);\n setEnvManaged(!!s.envManaged);\n setBuilderEnabled(!!s.builderEnabled);\n const nextConnectUrl = s.cliAuthUrl ?? s.connectUrl ?? null;\n setStatusConnectUrl(nextConnectUrl);\n statusConnectUrlAtRef.current = nextConnectUrl ? Date.now() : null;\n const org = s.orgName ?? null;\n setOrgName(org);\n setConnecting(false);\n connectStartedAtRef.current = null;\n notifiedConnectedRef.current = true;\n notifyAgentEngineConfiguredChanged(\"builder-connect-message\");\n try {\n await onConnectedRef.current?.({ orgName: org });\n } catch {\n // The caller's callback is a UI convenience; status is already set.\n }\n };\n\n try {\n channel = new BroadcastChannel(`builder-connect:${window.location.host}`);\n channel.onmessage = (e: MessageEvent) => {\n const data = e.data as { type?: string; message?: string } | undefined;\n if (data?.type === \"builder-connect-success\") {\n void handleSuccess();\n return;\n }\n if (data?.type === \"builder-connect-error\") {\n if (typeof data.message !== \"string\" || !data.message) return;\n handleError(data.message);\n }\n };\n } catch {\n // BroadcastChannel not available (rare) \\u2014 fall through to postMessage.\n }\n\n const handler = (e: MessageEvent) => {\n if (!isTrustedBuilderConnectMessageOrigin(e.origin)) return;\n const data = e.data as { type?: string; message?: string } | undefined;\n if (data?.type === \"builder-connect-success\") {\n void handleSuccess();\n return;\n }\n if (data?.type === \"builder-connect-error\") {\n if (typeof data.message !== \"string\" || !data.message) return;\n handleError(data.message);\n }\n };\n window.addEventListener(\"message\", handler);\n\n return () => {\n channel?.close();\n window.removeEventListener(\"message\", handler);\n };\n }, [fetchStatus, stopPoll]);\n\n return {\n configured,\n envManaged,\n builderEnabled,\n orgName,\n connecting,\n error,\n hasFetchedStatus,\n start,\n };\n}\n"]}
1
+ {"version":3,"file":"useBuilderStatus.js","sourceRoot":"","sources":["../../../src/client/settings/useBuilderStatus.ts"],"names":[],"mappings":"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","sourcesContent":["import { agentNativePath } from \"../api-path.js\";\nimport { useState, useEffect, useCallback, useRef } from \"react\";\nimport { getCallbackOrigin } from \"../frame.js\";\nimport { trackEvent } from \"../analytics.js\";\n\nexport interface BuilderStatus {\n configured: boolean;\n builderEnabled: boolean;\n /**\n * True when `BUILDER_PRIVATE_KEY` is set at the deploy level. This is a\n * fallback credential; per-user/org Builder connections are still allowed\n * and take precedence for that request.\n */\n envManaged?: boolean;\n credentialSource?: \"user\" | \"org\" | \"workspace\" | \"env\";\n connectUrl: string;\n cliAuthUrl?: string;\n appHost: string;\n apiHost: string;\n branchProjectIdConfigured?: boolean;\n branchProjectId?: string;\n publicKeyConfigured: boolean;\n privateKeyConfigured: boolean;\n userId?: string;\n orgName?: string;\n orgKind?: string;\n /**\n * Set when the OAuth callback ran but failed to persist credentials.\n * Surfaced as a one-shot row by the server so the connect-flow polling\n * can stop with a clear message instead of timing out at 5min.\n */\n connectError?: { message: string; at: number };\n /**\n * Set when the currently effective Builder credential was rejected by\n * Builder's API. Unlike connectError, this describes the old credential pair\n * and should not abort a new reconnect attempt while the popup is open.\n */\n authError?: { message: string; at: number };\n}\n\n/**\n * Fetches Builder connection status from /_agent-native/builder/status.\n * Re-fetches on window focus to detect post-redirect state changes.\n */\nexport function useBuilderStatus() {\n const [status, setStatus] = useState<BuilderStatus | null>(null);\n const [loading, setLoading] = useState(true);\n\n const fetchStatus = useCallback(async () => {\n try {\n const res = await fetch(agentNativePath(\"/_agent-native/builder/status\"));\n if (!res.ok) {\n setStatus(null);\n return;\n }\n setStatus(await res.json());\n } catch {\n setStatus(null);\n } finally {\n setLoading(false);\n }\n }, []);\n\n useEffect(() => {\n fetchStatus();\n\n function onFocus() {\n fetchStatus();\n }\n function onVisibility() {\n if (document.visibilityState === \"visible\") fetchStatus();\n }\n window.addEventListener(\"focus\", onFocus);\n document.addEventListener(\"visibilitychange\", onVisibility);\n // Engine connect/disconnect actions (e.g. the Builder disconnect button)\n // dispatch this event so dependent cards refresh without a full reload.\n window.addEventListener(\"agent-engine:configured-changed\", fetchStatus);\n return () => {\n window.removeEventListener(\"focus\", onFocus);\n document.removeEventListener(\"visibilitychange\", onVisibility);\n window.removeEventListener(\n \"agent-engine:configured-changed\",\n fetchStatus,\n );\n };\n }, [fetchStatus]);\n\n return { status, loading, refetch: fetchStatus };\n}\n\n// ─── useBuilderConnectFlow ──────────────────────────────────────────────────\n//\n// Shared state machine for the \"open Builder CLI-auth popup + poll\n// /builder/status until credentials land\" interaction. Replaces three\n// near-duplicate inline implementations: `BuilderCliAuthMethod` in\n// OnboardingPanel, `ConnectBuilderCard`, and `BuilderConnectCta` in\n// AssistantChat. Each consumer supplies its own popup URL / completion\n// behavior; the hook owns the polling + timeout + focus refresh.\n//\n// `popupUrl` is what we pass to `window.open`. The default\n// `/_agent-native/builder/connect` is a server-side 302 to the real\n// cli-auth URL — using it keeps the click handler synchronous so popup\n// blockers don't downgrade the open to same-tab navigation. Pass an\n// explicit `popupUrl` (e.g. the already-computed cli-auth URL) if your\n// caller already has it in hand.\n\nexport interface BuilderConnectFlowOptions {\n /** Skip server status polling for hosts that own provider routing. */\n enabled?: boolean;\n /** URL to synchronously open on start(). Defaults to the 302 shortcut. */\n popupUrl?: string;\n /** Low-cardinality label for the UI surface that opened Builder connect. */\n trackingSource?: string;\n /** Product flow that needed Builder connect, e.g. connect_llm. */\n trackingFlow?: string;\n /** Invoked after the status poll first sees `configured: true`. */\n onConnected?: (state: { orgName: string | null }) => void | Promise<void>;\n}\n\nexport interface BuilderConnectStartOptions {\n /** Override the hook-level source for this click. */\n trackingSource?: string;\n /** Override the hook-level flow for this click. */\n trackingFlow?: string;\n}\n\nexport interface BuilderConnectFlow {\n configured: boolean;\n /**\n * True when the deploy has BUILDER_PRIVATE_KEY set as a fallback. Connect\n * is still available so users can override the fallback with their own\n * Builder account.\n */\n envManaged: boolean;\n /**\n * True when the server has a Builder branch project configured for this\n * request. When false, the card surfaces a waitlist CTA instead of a Send\n * button.\n */\n builderEnabled: boolean;\n orgName: string | null;\n connecting: boolean;\n error: string | null;\n /**\n * True once the first `/builder/status` fetch has completed (successfully\n * or not). Consumers that accept an `initialConfigured` prop (e.g. agent\n * tool-call results rendered with server-side state) should treat\n * `configured`/`orgName` as authoritative only once this flips true —\n * otherwise the hook's starting `false` defaults would cause a flash\n * back to \"Connect Builder\" on first paint.\n */\n hasFetchedStatus: boolean;\n /** Open the popup and begin polling. Must be called from a user-gesture handler. */\n start: (options?: BuilderConnectStartOptions) => void;\n}\n\nconst POLL_INTERVAL_MS = 2000;\nconst POLL_TIMEOUT_MS = 5 * 60 * 1000;\nconst POPUP_CLOSED_CONFIRMATION_GRACE_MS = 5000;\nconst CALLBACK_SUCCESS_STATUS_RETRY_MS = 500;\nconst CALLBACK_SUCCESS_STATUS_RETRIES = 10;\nconst BUILDER_CONNECT_PARAM = \"_an_connect\";\nconst BUILDER_STATE_PARAM = \"_an_state\";\nconst BUILDER_SIGNUP_SOURCE_PARAM = \"signupSource\";\nconst BUILDER_AGENT_NATIVE_FLOW_PARAM = \"agentNativeFlow\";\nconst BUILDER_AGENT_NATIVE_CONNECT_SOURCE_PARAM = \"agentNativeConnectSource\";\nconst BUILDER_SIGNUP_SOURCE = \"agent-native\";\nconst STATUS_CONNECT_URL_TTL_MS = 9 * 60 * 1000;\n\nfunction cleanTrackingParam(value: string | null | undefined): string | null {\n const trimmed = value?.trim();\n return trimmed ? trimmed.slice(0, 120) : null;\n}\n\nfunction inferBuilderConnectTrackingFlow(source: string | undefined): string {\n const normalized = source?.toLowerCase() ?? \"\";\n if (normalized.includes(\"background_agent\")) return \"background_agent\";\n if (\n normalized.includes(\"code_required\") ||\n normalized.includes(\"code_access\") ||\n normalized.includes(\"connect_builder_card\")\n ) {\n return \"background_agent\";\n }\n if (normalized.includes(\"browser\")) return \"browser_automation\";\n if (normalized.includes(\"voice\") || normalized.includes(\"transcription\")) {\n return \"voice_transcription\";\n }\n if (normalized.includes(\"upload\")) return \"file_upload\";\n if (normalized.includes(\"hosting\")) return \"hosting\";\n if (normalized.includes(\"database\")) return \"database\";\n if (normalized.includes(\"auth_settings\")) return \"auth\";\n return \"connect_llm\";\n}\n\nexport function withBuilderConnectTrackingParams(\n url: string,\n options: { source?: string; flow?: string } = {},\n): string {\n const source = cleanTrackingParam(options.source);\n const flow =\n cleanTrackingParam(options.flow) ??\n inferBuilderConnectTrackingFlow(source ?? undefined);\n const origin =\n typeof window !== \"undefined\" ? window.location.origin : \"http://localhost\";\n\n try {\n const parsed = new URL(url, origin);\n parsed.searchParams.set(BUILDER_SIGNUP_SOURCE_PARAM, BUILDER_SIGNUP_SOURCE);\n parsed.searchParams.set(BUILDER_AGENT_NATIVE_FLOW_PARAM, flow);\n if (source) {\n parsed.searchParams.set(\n BUILDER_AGENT_NATIVE_CONNECT_SOURCE_PARAM,\n source,\n );\n }\n\n const redirectUrl = parsed.searchParams.get(\"redirect_url\");\n if (redirectUrl) {\n const parsedRedirect = new URL(redirectUrl);\n parsedRedirect.searchParams.set(\n BUILDER_SIGNUP_SOURCE_PARAM,\n BUILDER_SIGNUP_SOURCE,\n );\n parsedRedirect.searchParams.set(BUILDER_AGENT_NATIVE_FLOW_PARAM, flow);\n if (source) {\n parsedRedirect.searchParams.set(\n BUILDER_AGENT_NATIVE_CONNECT_SOURCE_PARAM,\n source,\n );\n }\n parsed.searchParams.set(\"redirect_url\", parsedRedirect.toString());\n }\n\n return parsed.toString();\n } catch {\n return url;\n }\n}\n\nfunction isAgentNativeDesktop() {\n if (typeof navigator === \"undefined\") return false;\n return /AgentNativeDesktop/i.test(navigator.userAgent || \"\");\n}\n\nfunction hasSignedConnectToken(url: string | null | undefined): boolean {\n if (!url || typeof window === \"undefined\") return false;\n try {\n return new URL(url, window.location.origin).searchParams.has(\n BUILDER_CONNECT_PARAM,\n );\n } catch {\n return false;\n }\n}\n\nfunction hasSignedCallbackState(url: string | null | undefined): boolean {\n if (!url || typeof window === \"undefined\") return false;\n try {\n const parsed = new URL(url, window.location.origin);\n const redirectUrl = parsed.searchParams.get(\"redirect_url\");\n if (!redirectUrl) return false;\n return new URL(redirectUrl).searchParams.has(BUILDER_STATE_PARAM);\n } catch {\n return false;\n }\n}\n\nfunction isFreshSignedConnectUrl(\n url: string | null,\n fetchedAt: number | null,\n): url is string {\n return (\n (hasSignedConnectToken(url) || hasSignedCallbackState(url)) &&\n typeof fetchedAt === \"number\" &&\n Date.now() - fetchedAt < STATUS_CONNECT_URL_TTL_MS\n );\n}\n\nfunction isCurrentConnectError(\n error: { message: string; at: number } | undefined,\n startedAt: number | null,\n): error is { message: string; at: number } {\n if (!error?.message) return false;\n if (!startedAt) return true;\n return typeof error.at !== \"number\" || error.at >= startedAt - 1000;\n}\n\nfunction showBuilderConnectPopupPlaceholder(opened: Window) {\n // Keep opener attached: the Builder callback uses postMessage to notify the\n // settings tab that the popup completed. We still hold the WindowProxy so the\n // parent can navigate the blank popup after refreshing the signed connect URL.\n try {\n opened.document.title = \"Opening Builder.io\";\n opened.document.body.style.margin = \"0\";\n opened.document.body.style.background = \"#111\";\n opened.document.body.style.color = \"#ddd\";\n opened.document.body.style.fontFamily =\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif';\n opened.document.body.style.display = \"flex\";\n opened.document.body.style.alignItems = \"center\";\n opened.document.body.style.justifyContent = \"center\";\n opened.document.body.style.height = \"100vh\";\n opened.document.body.textContent = \"Opening Builder.io...\";\n } catch {\n // Popup may already be cross-origin or browser may block document writes.\n }\n}\n\nfunction navigateBuilderConnectPopup(opened: Window, url: string): boolean {\n try {\n opened.location.href = url;\n return true;\n } catch {\n try {\n opened.close();\n } catch {\n // Ignore close failures.\n }\n return false;\n }\n}\n\nfunction notifyAgentEngineConfiguredChanged(source: string) {\n if (typeof window === \"undefined\") return;\n window.dispatchEvent(\n new CustomEvent(\"agent-engine:configured-changed\", {\n detail: { source },\n }),\n );\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction isPopupClosed(opened: Window | null): boolean {\n if (!opened) return false;\n try {\n return opened.closed === true;\n } catch {\n return false;\n }\n}\n\nfunction isTrustedBuilderConnectMessageOrigin(origin: string): boolean {\n if (typeof window !== \"undefined\" && origin === window.location.origin) {\n return true;\n }\n try {\n const hostname = new URL(origin).hostname.toLowerCase();\n return (\n hostname === \"localhost\" ||\n hostname === \"127.0.0.1\" ||\n hostname === \"::1\" ||\n hostname === \"builder.io\" ||\n hostname.endsWith(\".builder.io\") ||\n hostname === \"builder.my\" ||\n hostname.endsWith(\".builder.my\") ||\n hostname === \"builderio.xyz\" ||\n hostname.endsWith(\".builderio.xyz\") ||\n hostname === \"builderio.dev\" ||\n hostname.endsWith(\".builderio.dev\") ||\n hostname === \"builder.codes\" ||\n hostname.endsWith(\".builder.codes\") ||\n hostname === \"agent-native.com\" ||\n hostname.endsWith(\".agent-native.com\")\n );\n } catch {\n return false;\n }\n}\n\nexport interface OpenBuilderConnectPopupOptions {\n url?: string;\n source?: string;\n flow?: string;\n features?: string;\n}\n\nexport function openBuilderConnectPopup({\n url,\n source = \"builder_connect\",\n flow,\n features = \"noopener,noreferrer\",\n}: OpenBuilderConnectPopupOptions = {}): Window | null {\n if (typeof window === \"undefined\") return null;\n const origin = getCallbackOrigin() || window.location.origin;\n const href =\n url ??\n new URL(agentNativePath(\"/_agent-native/builder/connect\"), origin).href;\n const trackedHref =\n href === \"about:blank\"\n ? href\n : withBuilderConnectTrackingParams(href, { source, flow });\n const connectUrlKind = url ? \"provided\" : \"default\";\n const trackingFlow =\n cleanTrackingParam(flow) ?? inferBuilderConnectTrackingFlow(source);\n trackEvent(\"builder connect clicked\", {\n feature: \"builder\",\n stage: \"client\",\n source,\n flow: trackingFlow,\n connect_url_kind: connectUrlKind,\n });\n try {\n const opened = window.open(trackedHref, \"_blank\", features);\n if (!opened && !/AgentNativeDesktop/i.test(navigator.userAgent || \"\")) {\n trackEvent(\"builder connect popup blocked\", {\n feature: \"builder\",\n stage: \"client\",\n source,\n flow: trackingFlow,\n connect_url_kind: connectUrlKind,\n });\n }\n return opened;\n } catch {\n trackEvent(\"builder connect failed\", {\n feature: \"builder\",\n stage: \"client\",\n reason: \"popup_open_exception\",\n source,\n flow: trackingFlow,\n connect_url_kind: connectUrlKind,\n });\n return null;\n }\n}\n\nexport function useBuilderConnectFlow(\n opts: BuilderConnectFlowOptions = {},\n): BuilderConnectFlow {\n const {\n enabled = true,\n popupUrl,\n trackingSource = \"builder_connect_flow\",\n trackingFlow,\n onConnected,\n } = opts;\n const [configured, setConfigured] = useState(false);\n const [envManaged, setEnvManaged] = useState(false);\n const [builderEnabled, setBuilderEnabled] = useState(false);\n const [orgName, setOrgName] = useState<string | null>(null);\n const [connecting, setConnecting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [hasFetchedStatus, setHasFetchedStatus] = useState(false);\n const [statusConnectUrl, setStatusConnectUrl] = useState<string | null>(null);\n // When statusConnectUrl was last fetched. The server signs the embedded\n // _an_connect token with a 10-minute TTL; using an older URL fails the\n // cross-origin popup gate. Track freshness so start() can either use a\n // still-good direct URL (desktop) or refresh a new one inside the popup\n // gesture path (browser/editor embeds).\n const statusConnectUrlAtRef = useRef<number | null>(null);\n const pollRef = useRef<ReturnType<typeof setInterval> | null>(null);\n const connectStartedAtRef = useRef<number | null>(null);\n const mountedRef = useRef(true);\n const notifiedConnectedRef = useRef(false);\n // Keep onConnected in a ref so start() doesn't need to re-create when the\n // caller passes an inline arrow function.\n const onConnectedRef = useRef(onConnected);\n onConnectedRef.current = onConnected;\n\n const stopPoll = useCallback(() => {\n if (pollRef.current) {\n clearInterval(pollRef.current);\n pollRef.current = null;\n }\n }, []);\n\n const fetchStatus = useCallback(async () => {\n if (!enabled) return null;\n const origin = getCallbackOrigin() || window.location.origin;\n try {\n const r = await fetch(\n new URL(agentNativePath(\"/_agent-native/builder/status\"), origin).href,\n );\n if (!r.ok) return null;\n return (await r.json()) as {\n configured: boolean;\n envManaged?: boolean;\n builderEnabled?: boolean;\n orgName?: string | null;\n connectUrl?: string;\n cliAuthUrl?: string;\n credentialSource?: \"user\" | \"org\" | \"workspace\" | \"env\";\n connectError?: { message: string; at: number };\n authError?: { message: string; at: number };\n };\n } catch {\n return null;\n }\n }, [enabled]);\n\n // Initial fetch + focus/visibility refresh so if the user completed the\n // flow in another tab (or a downgraded same-tab nav) we notice it. Also\n // listen for `agent-engine:configured-changed` so a Disconnect click in\n // Settings propagates to any connect-CTA cards rendered elsewhere in\n // the app without waiting for the next focus event.\n useEffect(() => {\n if (!enabled) {\n setConfigured(false);\n setEnvManaged(false);\n setBuilderEnabled(false);\n setOrgName(null);\n setConnecting(false);\n setError(null);\n setHasFetchedStatus(false);\n setStatusConnectUrl(null);\n statusConnectUrlAtRef.current = null;\n stopPoll();\n return;\n }\n mountedRef.current = true;\n let cancelled = false;\n const refresh = async () => {\n const s = await fetchStatus();\n if (cancelled || !mountedRef.current) return;\n // Flip `hasFetchedStatus` even when the fetch failed — the caller's\n // \"use initial props until the hook has an answer\" pattern wants to\n // stop waiting after we've tried, regardless of network outcome.\n setHasFetchedStatus(true);\n if (!s) return;\n setConfigured(!!s.configured);\n setEnvManaged(!!s.envManaged);\n setBuilderEnabled(!!s.builderEnabled);\n const nextConnectUrl = s.cliAuthUrl ?? s.connectUrl ?? null;\n setStatusConnectUrl(nextConnectUrl);\n statusConnectUrlAtRef.current = nextConnectUrl ? Date.now() : null;\n const org = s.orgName ?? null;\n setOrgName(org);\n if (s.configured) {\n connectStartedAtRef.current = null;\n }\n if (s.configured && !notifiedConnectedRef.current) {\n notifiedConnectedRef.current = true;\n notifyAgentEngineConfiguredChanged(\"builder-status\");\n try {\n await onConnectedRef.current?.({ orgName: org });\n } catch {\n // The caller's callback is a UI convenience; status is already set.\n }\n } else if (!s.configured) {\n notifiedConnectedRef.current = false;\n }\n // Surface persisted auth-failure messages on idle refreshes, but don't\n // let an old rejected credential abort a new reconnect popup while the\n // user is still choosing a Builder space.\n const activeConnectStartedAt = connectStartedAtRef.current;\n if (isCurrentConnectError(s.connectError, activeConnectStartedAt)) {\n setError(s.connectError.message);\n } else if (!activeConnectStartedAt && s.authError?.message) {\n setError(s.authError.message);\n } else if (s.configured) {\n setError(null);\n }\n };\n refresh();\n const onVisible = () => {\n if (document.visibilityState === \"visible\") refresh();\n };\n window.addEventListener(\"focus\", refresh);\n document.addEventListener(\"visibilitychange\", onVisible);\n window.addEventListener(\"agent-engine:configured-changed\", refresh);\n return () => {\n cancelled = true;\n mountedRef.current = false;\n window.removeEventListener(\"focus\", refresh);\n document.removeEventListener(\"visibilitychange\", onVisible);\n window.removeEventListener(\"agent-engine:configured-changed\", refresh);\n stopPoll();\n };\n }, [enabled, fetchStatus, stopPoll]);\n\n const start = useCallback(\n (startOptions?: BuilderConnectStartOptions) => {\n if (!enabled) return;\n stopPoll();\n const started = Date.now();\n const clickTrackingSource =\n startOptions?.trackingSource ?? trackingSource;\n const clickTrackingFlow = startOptions?.trackingFlow ?? trackingFlow;\n let openedPopup: Window | null = null;\n let popupClosedAt: number | null = null;\n connectStartedAtRef.current = started;\n setConnecting(true);\n setError(null);\n\n // Open SYNCHRONOUSLY inside the caller's click handler — any await\n // before window.open lets the user-gesture token expire, which causes\n // popup blockers to block entirely or fall back to same-tab navigation.\n const origin = getCallbackOrigin() || window.location.origin;\n const cachedFreshUrl = isFreshSignedConnectUrl(\n statusConnectUrl,\n statusConnectUrlAtRef.current,\n )\n ? statusConnectUrl\n : null;\n // popupUrl props and statusConnectUrl are signed URLs minted before the\n // click. In web browsers, always refresh inside an about:blank popup so a\n // server/package restart cannot leave the user with a stale signed state.\n // Desktop keeps the direct path because the Electron shell owns the popup.\n const signedPropUrl = hasSignedConnectToken(popupUrl) ? popupUrl : null;\n const signedCliPropUrl = hasSignedCallbackState(popupUrl)\n ? popupUrl\n : null;\n const fallbackUrl = new URL(\n agentNativePath(\"/_agent-native/builder/connect\"),\n origin,\n ).href;\n const directUrl =\n cachedFreshUrl ?? signedCliPropUrl ?? signedPropUrl ?? fallbackUrl;\n\n if (isAgentNativeDesktop()) {\n const opened = openBuilderConnectPopup({\n url: directUrl,\n source: clickTrackingSource,\n flow: clickTrackingFlow,\n });\n openedPopup = opened;\n if (!opened) {\n // Agent Native Desktop handles the popup in Electron and reports\n // null to the embedded webview, so null is not a blocker here.\n }\n } else {\n const opened = openBuilderConnectPopup({\n url: \"about:blank\",\n source: clickTrackingSource,\n flow: clickTrackingFlow,\n features: \"width=600,height=700\",\n });\n if (!opened) {\n connectStartedAtRef.current = null;\n setConnecting(false);\n setError(\"Couldn't open Builder. Allow popups and try again.\");\n return;\n }\n openedPopup = opened;\n showBuilderConnectPopupPlaceholder(opened);\n void (async () => {\n const s = await fetchStatus();\n if (!mountedRef.current) {\n try {\n opened.close();\n } catch {\n // Ignore close failures.\n }\n return;\n }\n if (s) {\n setHasFetchedStatus(true);\n setConfigured(!!s.configured);\n setEnvManaged(!!s.envManaged);\n setBuilderEnabled(!!s.builderEnabled);\n const nextConnectUrl = s.cliAuthUrl ?? s.connectUrl ?? null;\n setStatusConnectUrl(nextConnectUrl);\n statusConnectUrlAtRef.current = nextConnectUrl ? Date.now() : null;\n setOrgName(s.orgName ?? null);\n }\n\n // Prefer the click-time status response, but keep a recent signed\n // URL from this hook as a fallback. This avoids closing the popup\n // when the refresh hits a transient 401/HTML/error response.\n const freshUrl =\n s?.cliAuthUrl ?? s?.connectUrl ?? cachedFreshUrl ?? null;\n if (!freshUrl) {\n try {\n opened.close();\n } catch {\n // Ignore close failures.\n }\n stopPoll();\n connectStartedAtRef.current = null;\n setConnecting(false);\n setError(\n \"Couldn't start Builder connect. Refresh this page and try again.\",\n );\n return;\n }\n const trackedFreshUrl = withBuilderConnectTrackingParams(freshUrl, {\n source: clickTrackingSource,\n flow: clickTrackingFlow,\n });\n if (!navigateBuilderConnectPopup(opened, trackedFreshUrl)) {\n stopPoll();\n connectStartedAtRef.current = null;\n setConnecting(false);\n setError(\n \"Couldn't navigate the Builder popup. Allow popups and try again.\",\n );\n }\n })();\n }\n\n pollRef.current = setInterval(async () => {\n const s = await fetchStatus();\n if (!mountedRef.current) {\n stopPoll();\n return;\n }\n if (s?.configured) {\n stopPoll();\n setConfigured(true);\n setEnvManaged(!!s.envManaged);\n setBuilderEnabled(!!s.builderEnabled);\n const nextConnectUrl = s.cliAuthUrl ?? s.connectUrl ?? null;\n setStatusConnectUrl(nextConnectUrl);\n statusConnectUrlAtRef.current = nextConnectUrl ? Date.now() : null;\n const org = s.orgName ?? null;\n setOrgName(org);\n setConnecting(false);\n connectStartedAtRef.current = null;\n notifiedConnectedRef.current = true;\n notifyAgentEngineConfiguredChanged(\"builder-connect\");\n try {\n await onConnectedRef.current?.({ orgName: org });\n } catch {\n // Consumer's callback failed; we've already flipped the UI state\n // to connected. Swallow so we don't re-arm the flow.\n }\n } else if (isCurrentConnectError(s?.connectError, started)) {\n // OAuth callback ran but writeBuilderCredentials threw — surface the\n // real error instead of letting the user wait 5 minutes for timeout.\n stopPoll();\n connectStartedAtRef.current = null;\n setConnecting(false);\n setError(\n `Couldn't save Builder credentials: ${s.connectError.message}. Try again or contact support.`,\n );\n } else if (isPopupClosed(openedPopup)) {\n popupClosedAt ??= Date.now();\n if (Date.now() - popupClosedAt > POPUP_CLOSED_CONFIRMATION_GRACE_MS) {\n stopPoll();\n connectStartedAtRef.current = null;\n setConnecting(false);\n trackEvent(\"builder connect failed\", {\n feature: \"builder\",\n stage: \"client\",\n reason: \"popup_closed_without_status\",\n source: clickTrackingSource,\n flow:\n cleanTrackingParam(clickTrackingFlow) ??\n inferBuilderConnectTrackingFlow(clickTrackingSource),\n });\n setError(\n \"Builder finished, but this workspace couldn't confirm the saved credentials. Refresh this page or try Connect Builder.io again.\",\n );\n }\n } else if (Date.now() - started > POLL_TIMEOUT_MS) {\n stopPoll();\n connectStartedAtRef.current = null;\n setConnecting(false);\n trackEvent(\"builder connect failed\", {\n feature: \"builder\",\n stage: \"client\",\n reason: \"timeout\",\n source: clickTrackingSource,\n flow:\n cleanTrackingParam(clickTrackingFlow) ??\n inferBuilderConnectTrackingFlow(clickTrackingSource),\n });\n setError(\n \"Didn't hear back from Builder in 5 minutes. Allow popups and try again.\",\n );\n }\n }, POLL_INTERVAL_MS);\n },\n [\n enabled,\n fetchStatus,\n popupUrl,\n statusConnectUrl,\n stopPoll,\n trackingFlow,\n trackingSource,\n ],\n );\n\n // Popup-side fast path: the callback page broadcasts a message so we stop\n // polling immediately rather than waiting for the next 2s tick.\n //\n // We listen on BroadcastChannel (same-origin, works with noopener popups)\n // AND on window.message (legacy path for environments without BC or for\n // popups that still have opener access). Both paths are safe to have open\n // simultaneously \\u2014 the first one to fire wins and the error is deduplicated\n // by the stopPoll() call which is idempotent.\n useEffect(() => {\n let channel: BroadcastChannel | null = null;\n const handleError = (message: string) => {\n stopPoll();\n connectStartedAtRef.current = null;\n setConnecting(false);\n setError(`Couldn't save Builder credentials: ${message}.`);\n };\n const handleSuccess = async () => {\n let s: Awaited<ReturnType<typeof fetchStatus>> = null;\n for (let i = 0; i < CALLBACK_SUCCESS_STATUS_RETRIES; i += 1) {\n s = await fetchStatus();\n if (!mountedRef.current) return;\n if (\n s?.configured ||\n isCurrentConnectError(s?.connectError, connectStartedAtRef.current)\n ) {\n break;\n }\n if (i < CALLBACK_SUCCESS_STATUS_RETRIES - 1) {\n await delay(CALLBACK_SUCCESS_STATUS_RETRY_MS);\n }\n }\n if (!mountedRef.current) return;\n if (!s?.configured) {\n const connectError = isCurrentConnectError(\n s?.connectError,\n connectStartedAtRef.current,\n )\n ? s?.connectError\n : null;\n stopPoll();\n setHasFetchedStatus(true);\n if (s) {\n setConfigured(false);\n setEnvManaged(!!s.envManaged);\n setBuilderEnabled(!!s.builderEnabled);\n const nextConnectUrl = s.cliAuthUrl ?? s.connectUrl ?? null;\n setStatusConnectUrl(nextConnectUrl);\n statusConnectUrlAtRef.current = nextConnectUrl ? Date.now() : null;\n setOrgName(s.orgName ?? null);\n }\n connectStartedAtRef.current = null;\n setConnecting(false);\n setError(\n connectError\n ? `Couldn't save Builder credentials: ${connectError.message}. Try again or contact support.`\n : \"Builder finished, but this workspace couldn't confirm the saved credentials. Refresh this page or try Connect Builder.io again.\",\n );\n return;\n }\n stopPoll();\n setHasFetchedStatus(true);\n setConfigured(true);\n setEnvManaged(!!s.envManaged);\n setBuilderEnabled(!!s.builderEnabled);\n const nextConnectUrl = s.cliAuthUrl ?? s.connectUrl ?? null;\n setStatusConnectUrl(nextConnectUrl);\n statusConnectUrlAtRef.current = nextConnectUrl ? Date.now() : null;\n const org = s.orgName ?? null;\n setOrgName(org);\n setConnecting(false);\n connectStartedAtRef.current = null;\n notifiedConnectedRef.current = true;\n notifyAgentEngineConfiguredChanged(\"builder-connect-message\");\n try {\n await onConnectedRef.current?.({ orgName: org });\n } catch {\n // The caller's callback is a UI convenience; status is already set.\n }\n };\n\n try {\n channel = new BroadcastChannel(`builder-connect:${window.location.host}`);\n channel.onmessage = (e: MessageEvent) => {\n const data = e.data as { type?: string; message?: string } | undefined;\n if (data?.type === \"builder-connect-success\") {\n void handleSuccess();\n return;\n }\n if (data?.type === \"builder-connect-error\") {\n if (typeof data.message !== \"string\" || !data.message) return;\n handleError(data.message);\n }\n };\n } catch {\n // BroadcastChannel not available (rare) \\u2014 fall through to postMessage.\n }\n\n const handler = (e: MessageEvent) => {\n if (!isTrustedBuilderConnectMessageOrigin(e.origin)) return;\n const data = e.data as { type?: string; message?: string } | undefined;\n if (data?.type === \"builder-connect-success\") {\n void handleSuccess();\n return;\n }\n if (data?.type === \"builder-connect-error\") {\n if (typeof data.message !== \"string\" || !data.message) return;\n handleError(data.message);\n }\n };\n window.addEventListener(\"message\", handler);\n\n return () => {\n channel?.close();\n window.removeEventListener(\"message\", handler);\n };\n }, [fetchStatus, stopPoll]);\n\n return {\n configured,\n envManaged,\n builderEnabled,\n orgName,\n connecting,\n error,\n hasFetchedStatus,\n start,\n };\n}\n"]}
@@ -87,6 +87,39 @@ describe("useBuilderConnectFlow", () => {
87
87
  expect(popup.location.href).toBe(expectedConnectUrl(signedCliAuthUrl));
88
88
  expect(container.textContent).not.toContain("Popup blocked");
89
89
  });
90
+ it("falls back to the cached signed URL when the click-time status refresh fails", async () => {
91
+ setUserAgent("Mozilla/5.0 Chrome/140.0");
92
+ const popup = createPopupStub();
93
+ openSpy.mockReturnValue(popup);
94
+ vi.mocked(fetch).mockReset();
95
+ vi.mocked(fetch)
96
+ .mockResolvedValueOnce(jsonResponse({
97
+ configured: false,
98
+ envManaged: false,
99
+ builderEnabled: true,
100
+ orgName: null,
101
+ cliAuthUrl: signedCliAuthUrl,
102
+ connectUrl: "http://localhost:3000/_agent-native/builder/connect?_an_connect=signed",
103
+ appHost: "https://builder.io",
104
+ apiHost: "https://api.builder.io",
105
+ publicKeyConfigured: false,
106
+ privateKeyConfigured: false,
107
+ }))
108
+ .mockResolvedValueOnce(new Response("Unauthorized", { status: 401 }));
109
+ await act(async () => {
110
+ root.render(_jsx(BuilderConnectProbe, {}));
111
+ await Promise.resolve();
112
+ await Promise.resolve();
113
+ });
114
+ await act(async () => {
115
+ container.querySelector("button")?.click();
116
+ await Promise.resolve();
117
+ await Promise.resolve();
118
+ });
119
+ expect(openSpy).toHaveBeenCalledWith("about:blank", "_blank", "width=600,height=700");
120
+ expect(popup.location.href).toBe(expectedConnectUrl(signedCliAuthUrl));
121
+ expect(container.textContent).not.toContain("Couldn't start Builder connect");
122
+ });
90
123
  it("does not probe Builder status when disabled", async () => {
91
124
  await act(async () => {
92
125
  root.render(_jsx(BuilderConnectProbe, { enabled: false }));
@@ -1 +1 @@
1
- {"version":3,"file":"useBuilderStatus.spec.js","sourceRoot":"","sources":["../../../src/client/settings/useBuilderStatus.spec.tsx"],"names":[],"mappings":"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","sourcesContent":["// @vitest-environment happy-dom\nimport React, { act } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport {\n useBuilderConnectFlow,\n withBuilderConnectTrackingParams,\n} from \"./useBuilderStatus.js\";\n\nfunction jsonResponse(data: unknown): Response {\n return new Response(JSON.stringify(data), {\n headers: { \"Content-Type\": \"application/json\" },\n });\n}\n\nfunction setUserAgent(userAgent: string) {\n Object.defineProperty(window.navigator, \"userAgent\", {\n value: userAgent,\n configurable: true,\n });\n}\n\nfunction BuilderConnectProbe({\n enabled = true,\n popupUrl,\n}: {\n enabled?: boolean;\n popupUrl?: string;\n}) {\n const flow = useBuilderConnectFlow({ enabled, popupUrl });\n return (\n <div>\n <button type=\"button\" onClick={() => flow.start()}>\n Connect\n </button>\n <output data-testid=\"status\">\n {flow.configured ? \"configured\" : \"not-configured\"}{\" \"}\n {flow.connecting ? \"connecting\" : \"idle\"}\n </output>\n <output>{flow.error ?? \"\"}</output>\n </div>\n );\n}\n\nfunction createPopupStub() {\n const doc = document.implementation.createHTMLDocument(\"popup\");\n return {\n closed: false,\n close: vi.fn(),\n document: doc,\n location: { href: \"\" },\n opener: window,\n } as unknown as Window;\n}\n\nconst signedCliAuthUrl =\n \"https://builder.io/cli-auth?response_type=code&host=agent-native-browser&client_id=Agent%20Native%20Browser&redirect_url=https%3A%2F%2Fagent-workspace.builder.io%2Fdispatch%2F_agent-native%2Fbuilder%2Fcallback%3F_an_state%3Dsigned&preview_url=https%3A%2F%2Fagent-workspace.builder.io%2Fdispatch&framework=agent-native\";\nconst staleCliAuthUrl = signedCliAuthUrl.replace(\n \"_an_state%3Dsigned\",\n \"_an_state%3Dstale\",\n);\nconst refreshedCliAuthUrl = signedCliAuthUrl.replace(\n \"_an_state%3Dsigned\",\n \"_an_state%3Drefreshed\",\n);\n\nfunction expectedConnectUrl(url: string): string {\n return withBuilderConnectTrackingParams(url, {\n source: \"builder_connect_flow\",\n flow: \"connect_llm\",\n });\n}\n\ndescribe(\"useBuilderConnectFlow\", () => {\n let container: HTMLDivElement;\n let root: Root;\n let openSpy: ReturnType<typeof vi.fn>;\n\n beforeEach(() => {\n vi.stubGlobal(\"IS_REACT_ACT_ENVIRONMENT\", true);\n window.history.replaceState({}, \"\", \"http://localhost:3000/settings\");\n vi.stubGlobal(\n \"fetch\",\n vi.fn(async () =>\n jsonResponse({\n configured: false,\n envManaged: false,\n builderEnabled: true,\n orgName: null,\n cliAuthUrl: signedCliAuthUrl,\n connectUrl:\n \"http://localhost:3000/_agent-native/builder/connect?_an_connect=signed\",\n appHost: \"https://builder.io\",\n apiHost: \"https://api.builder.io\",\n publicKeyConfigured: false,\n privateKeyConfigured: false,\n }),\n ),\n );\n openSpy = vi.fn(() => null);\n vi.stubGlobal(\"open\", openSpy);\n container = document.createElement(\"div\");\n document.body.appendChild(container);\n root = createRoot(container);\n });\n\n afterEach(() => {\n act(() => root.unmount());\n container.remove();\n vi.useRealTimers();\n vi.unstubAllGlobals();\n });\n\n it(\"opens a blank web popup and navigates to a freshly fetched cli-auth URL\", async () => {\n setUserAgent(\"Mozilla/5.0 Chrome/140.0\");\n const popup = createPopupStub();\n openSpy.mockReturnValue(popup);\n\n await act(async () => {\n root.render(<BuilderConnectProbe />);\n await Promise.resolve();\n await Promise.resolve();\n });\n\n await act(async () => {\n container.querySelector(\"button\")?.click();\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(openSpy).toHaveBeenCalledWith(\n \"about:blank\",\n \"_blank\",\n \"width=600,height=700\",\n );\n expect(popup.location.href).toBe(expectedConnectUrl(signedCliAuthUrl));\n expect(container.textContent).not.toContain(\"Popup blocked\");\n });\n\n it(\"does not probe Builder status when disabled\", async () => {\n await act(async () => {\n root.render(<BuilderConnectProbe enabled={false} />);\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(fetch).not.toHaveBeenCalled();\n\n await act(async () => {\n container.querySelector(\"button\")?.click();\n await Promise.resolve();\n });\n\n expect(openSpy).not.toHaveBeenCalled();\n expect(fetch).not.toHaveBeenCalled();\n });\n\n it(\"refreshes an un-timestamped signed prop URL before navigating web popups\", async () => {\n setUserAgent(\"Mozilla/5.0 Chrome/140.0\");\n const popup = createPopupStub();\n openSpy.mockReturnValue(popup);\n\n let resolveInitialFetch!: (response: Response) => void;\n const initialFetch = new Promise<Response>((resolve) => {\n resolveInitialFetch = resolve;\n });\n vi.mocked(fetch)\n .mockReturnValueOnce(initialFetch)\n .mockResolvedValue(\n jsonResponse({\n configured: false,\n envManaged: false,\n builderEnabled: true,\n orgName: null,\n cliAuthUrl: refreshedCliAuthUrl,\n connectUrl:\n \"http://localhost:3000/_agent-native/builder/connect?_an_connect=signed\",\n appHost: \"https://builder.io\",\n apiHost: \"https://api.builder.io\",\n publicKeyConfigured: false,\n privateKeyConfigured: false,\n }),\n );\n\n await act(async () => {\n root.render(<BuilderConnectProbe popupUrl={staleCliAuthUrl} />);\n });\n\n await act(async () => {\n container.querySelector(\"button\")?.click();\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(openSpy).toHaveBeenCalledWith(\n \"about:blank\",\n \"_blank\",\n \"width=600,height=700\",\n );\n expect(popup.location.href).toBe(expectedConnectUrl(refreshedCliAuthUrl));\n\n resolveInitialFetch(jsonResponse({ configured: false }));\n });\n\n it(\"refreshes status when a Builder preview callback posts success\", async () => {\n setUserAgent(\"Mozilla/5.0 Chrome/140.0\");\n vi.mocked(fetch)\n .mockResolvedValueOnce(\n jsonResponse({\n configured: false,\n envManaged: false,\n builderEnabled: true,\n orgName: null,\n cliAuthUrl: signedCliAuthUrl,\n connectUrl:\n \"http://localhost:3000/_agent-native/builder/connect?_an_connect=signed\",\n appHost: \"https://builder.io\",\n apiHost: \"https://api.builder.io\",\n publicKeyConfigured: false,\n privateKeyConfigured: false,\n }),\n )\n .mockResolvedValueOnce(\n jsonResponse({\n configured: true,\n envManaged: false,\n builderEnabled: true,\n orgName: \"Builder space\",\n cliAuthUrl: signedCliAuthUrl,\n connectUrl:\n \"http://localhost:3000/_agent-native/builder/connect?_an_connect=signed\",\n appHost: \"https://builder.io\",\n apiHost: \"https://api.builder.io\",\n publicKeyConfigured: true,\n privateKeyConfigured: true,\n }),\n );\n\n await act(async () => {\n root.render(<BuilderConnectProbe />);\n await Promise.resolve();\n });\n\n expect(container.textContent).toContain(\"not-configured\");\n\n await act(async () => {\n window.dispatchEvent(\n new MessageEvent(\"message\", {\n origin:\n \"https://940ebc5a83164aa6a37dde445e494f3a-fluid-crack-ctnhvsyb.builderio.xyz\",\n data: { type: \"builder-connect-success\" },\n }),\n );\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(container.textContent).toContain(\"configured\");\n });\n\n it(\"clears the spinner when the callback succeeds but status never confirms credentials\", async () => {\n vi.useFakeTimers();\n vi.setSystemTime(new Date(\"2026-05-14T12:00:00.000Z\"));\n setUserAgent(\"Mozilla/5.0 Chrome/140.0\");\n const popup = createPopupStub();\n openSpy.mockReturnValue(popup);\n vi.mocked(fetch).mockImplementation(async () =>\n jsonResponse({\n configured: false,\n envManaged: false,\n builderEnabled: true,\n orgName: null,\n cliAuthUrl: signedCliAuthUrl,\n connectUrl:\n \"http://localhost:3000/_agent-native/builder/connect?_an_connect=signed\",\n appHost: \"https://builder.io\",\n apiHost: \"https://api.builder.io\",\n publicKeyConfigured: false,\n privateKeyConfigured: false,\n }),\n );\n\n await act(async () => {\n root.render(<BuilderConnectProbe />);\n await Promise.resolve();\n });\n\n await act(async () => {\n container.querySelector(\"button\")?.click();\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(container.textContent).toContain(\"not-configured connecting\");\n\n await act(async () => {\n window.dispatchEvent(\n new MessageEvent(\"message\", {\n origin: \"https://agent-workspace.builder.io\",\n data: { type: \"builder-connect-success\" },\n }),\n );\n await vi.advanceTimersByTimeAsync(5000);\n });\n\n expect(container.textContent).toContain(\"not-configured idle\");\n expect(container.textContent).toContain(\"couldn't confirm\");\n });\n\n it(\"clears the spinner when the popup closes before status confirms credentials\", async () => {\n vi.useFakeTimers();\n vi.setSystemTime(new Date(\"2026-05-14T12:00:00.000Z\"));\n setUserAgent(\"Mozilla/5.0 Chrome/140.0\");\n const popup = createPopupStub();\n openSpy.mockReturnValue(popup);\n vi.mocked(fetch).mockImplementation(async () =>\n jsonResponse({\n configured: false,\n envManaged: false,\n builderEnabled: true,\n orgName: null,\n cliAuthUrl: signedCliAuthUrl,\n connectUrl:\n \"http://localhost:3000/_agent-native/builder/connect?_an_connect=signed\",\n appHost: \"https://builder.io\",\n apiHost: \"https://api.builder.io\",\n publicKeyConfigured: false,\n privateKeyConfigured: false,\n }),\n );\n\n await act(async () => {\n root.render(<BuilderConnectProbe />);\n await Promise.resolve();\n });\n\n await act(async () => {\n container.querySelector(\"button\")?.click();\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(container.textContent).toContain(\"not-configured connecting\");\n\n (popup as unknown as { closed: boolean }).closed = true;\n await act(async () => {\n await vi.advanceTimersByTimeAsync(8000);\n });\n\n expect(container.textContent).toContain(\"not-configured idle\");\n expect(container.textContent).toContain(\"couldn't confirm\");\n });\n\n it(\"does not replace the desktop webview when Electron reports a handled popup as null\", async () => {\n setUserAgent(\"Mozilla/5.0 Electron/41.2.2 AgentNativeDesktop/0.1.7\");\n\n await act(async () => {\n root.render(<BuilderConnectProbe />);\n });\n\n await act(async () => {\n container.querySelector(\"button\")?.click();\n });\n\n expect(openSpy).toHaveBeenCalledWith(\n expectedConnectUrl(signedCliAuthUrl),\n \"_blank\",\n \"noopener,noreferrer\",\n );\n expect(window.location.href).toBe(\"http://localhost:3000/settings\");\n expect(container.textContent).not.toContain(\"Popup blocked\");\n });\n\n it(\"does not abort a reconnect popup because the old credential was rejected\", async () => {\n vi.useFakeTimers();\n vi.setSystemTime(new Date(\"2026-05-14T12:00:00.000Z\"));\n setUserAgent(\"Mozilla/5.0 Chrome/140.0\");\n const popup = createPopupStub();\n openSpy.mockReturnValue(popup);\n const signedConnectUrl =\n \"http://localhost:3000/_agent-native/builder/connect?_an_connect=signed\";\n vi.mocked(fetch).mockImplementation(async () =>\n jsonResponse({\n configured: false,\n envManaged: true,\n builderEnabled: true,\n orgName: null,\n connectUrl: signedConnectUrl,\n appHost: \"https://builder.io\",\n apiHost: \"https://api.builder.io\",\n publicKeyConfigured: false,\n privateKeyConfigured: false,\n authError: {\n message: \"Private key does not match spaceId\",\n at: Date.now() - 60_000,\n },\n }),\n );\n\n await act(async () => {\n root.render(<BuilderConnectProbe />);\n await Promise.resolve();\n });\n\n expect(container.textContent).toContain(\n \"Private key does not match spaceId\",\n );\n\n await act(async () => {\n container.querySelector(\"button\")?.click();\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(openSpy).toHaveBeenCalledWith(\n \"about:blank\",\n \"_blank\",\n \"width=600,height=700\",\n );\n expect(popup.location.href).toBe(expectedConnectUrl(signedConnectUrl));\n expect(container.textContent).toContain(\"not-configured connecting\");\n expect(container.textContent).not.toContain(\n \"Private key does not match spaceId\",\n );\n\n await act(async () => {\n await vi.advanceTimersByTimeAsync(2000);\n });\n\n expect(container.textContent).toContain(\"not-configured connecting\");\n expect(container.textContent).not.toContain(\n \"Private key does not match spaceId\",\n );\n });\n\n it(\"ignores stale connect callback errors after starting a fresh reconnect\", async () => {\n vi.useFakeTimers();\n vi.setSystemTime(new Date(\"2026-05-14T12:00:00.000Z\"));\n setUserAgent(\"Mozilla/5.0 Chrome/140.0\");\n const popup = createPopupStub();\n openSpy.mockReturnValue(popup);\n const signedConnectUrl =\n \"http://localhost:3000/_agent-native/builder/connect?_an_connect=signed\";\n vi.mocked(fetch).mockImplementation(async () =>\n jsonResponse({\n configured: false,\n envManaged: false,\n builderEnabled: true,\n orgName: null,\n connectUrl: signedConnectUrl,\n appHost: \"https://builder.io\",\n apiHost: \"https://api.builder.io\",\n publicKeyConfigured: false,\n privateKeyConfigured: false,\n connectError: {\n message: \"No active connect flow found\",\n at: Date.now() - 60_000,\n },\n }),\n );\n\n await act(async () => {\n root.render(<BuilderConnectProbe />);\n await Promise.resolve();\n });\n\n expect(container.textContent).toContain(\"No active connect flow found\");\n\n await act(async () => {\n container.querySelector(\"button\")?.click();\n });\n\n await act(async () => {\n await vi.advanceTimersByTimeAsync(2000);\n });\n\n expect(container.textContent).toContain(\"not-configured connecting\");\n expect(container.textContent).not.toContain(\"No active connect flow found\");\n });\n});\n"]}
1
+ {"version":3,"file":"useBuilderStatus.spec.js","sourceRoot":"","sources":["../../../src/client/settings/useBuilderStatus.spec.tsx"],"names":[],"mappings":"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","sourcesContent":["// @vitest-environment happy-dom\nimport React, { act } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport {\n useBuilderConnectFlow,\n withBuilderConnectTrackingParams,\n} from \"./useBuilderStatus.js\";\n\nfunction jsonResponse(data: unknown): Response {\n return new Response(JSON.stringify(data), {\n headers: { \"Content-Type\": \"application/json\" },\n });\n}\n\nfunction setUserAgent(userAgent: string) {\n Object.defineProperty(window.navigator, \"userAgent\", {\n value: userAgent,\n configurable: true,\n });\n}\n\nfunction BuilderConnectProbe({\n enabled = true,\n popupUrl,\n}: {\n enabled?: boolean;\n popupUrl?: string;\n}) {\n const flow = useBuilderConnectFlow({ enabled, popupUrl });\n return (\n <div>\n <button type=\"button\" onClick={() => flow.start()}>\n Connect\n </button>\n <output data-testid=\"status\">\n {flow.configured ? \"configured\" : \"not-configured\"}{\" \"}\n {flow.connecting ? \"connecting\" : \"idle\"}\n </output>\n <output>{flow.error ?? \"\"}</output>\n </div>\n );\n}\n\nfunction createPopupStub() {\n const doc = document.implementation.createHTMLDocument(\"popup\");\n return {\n closed: false,\n close: vi.fn(),\n document: doc,\n location: { href: \"\" },\n opener: window,\n } as unknown as Window;\n}\n\nconst signedCliAuthUrl =\n \"https://builder.io/cli-auth?response_type=code&host=agent-native-browser&client_id=Agent%20Native%20Browser&redirect_url=https%3A%2F%2Fagent-workspace.builder.io%2Fdispatch%2F_agent-native%2Fbuilder%2Fcallback%3F_an_state%3Dsigned&preview_url=https%3A%2F%2Fagent-workspace.builder.io%2Fdispatch&framework=agent-native\";\nconst staleCliAuthUrl = signedCliAuthUrl.replace(\n \"_an_state%3Dsigned\",\n \"_an_state%3Dstale\",\n);\nconst refreshedCliAuthUrl = signedCliAuthUrl.replace(\n \"_an_state%3Dsigned\",\n \"_an_state%3Drefreshed\",\n);\n\nfunction expectedConnectUrl(url: string): string {\n return withBuilderConnectTrackingParams(url, {\n source: \"builder_connect_flow\",\n flow: \"connect_llm\",\n });\n}\n\ndescribe(\"useBuilderConnectFlow\", () => {\n let container: HTMLDivElement;\n let root: Root;\n let openSpy: ReturnType<typeof vi.fn>;\n\n beforeEach(() => {\n vi.stubGlobal(\"IS_REACT_ACT_ENVIRONMENT\", true);\n window.history.replaceState({}, \"\", \"http://localhost:3000/settings\");\n vi.stubGlobal(\n \"fetch\",\n vi.fn(async () =>\n jsonResponse({\n configured: false,\n envManaged: false,\n builderEnabled: true,\n orgName: null,\n cliAuthUrl: signedCliAuthUrl,\n connectUrl:\n \"http://localhost:3000/_agent-native/builder/connect?_an_connect=signed\",\n appHost: \"https://builder.io\",\n apiHost: \"https://api.builder.io\",\n publicKeyConfigured: false,\n privateKeyConfigured: false,\n }),\n ),\n );\n openSpy = vi.fn(() => null);\n vi.stubGlobal(\"open\", openSpy);\n container = document.createElement(\"div\");\n document.body.appendChild(container);\n root = createRoot(container);\n });\n\n afterEach(() => {\n act(() => root.unmount());\n container.remove();\n vi.useRealTimers();\n vi.unstubAllGlobals();\n });\n\n it(\"opens a blank web popup and navigates to a freshly fetched cli-auth URL\", async () => {\n setUserAgent(\"Mozilla/5.0 Chrome/140.0\");\n const popup = createPopupStub();\n openSpy.mockReturnValue(popup);\n\n await act(async () => {\n root.render(<BuilderConnectProbe />);\n await Promise.resolve();\n await Promise.resolve();\n });\n\n await act(async () => {\n container.querySelector(\"button\")?.click();\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(openSpy).toHaveBeenCalledWith(\n \"about:blank\",\n \"_blank\",\n \"width=600,height=700\",\n );\n expect(popup.location.href).toBe(expectedConnectUrl(signedCliAuthUrl));\n expect(container.textContent).not.toContain(\"Popup blocked\");\n });\n\n it(\"falls back to the cached signed URL when the click-time status refresh fails\", async () => {\n setUserAgent(\"Mozilla/5.0 Chrome/140.0\");\n const popup = createPopupStub();\n openSpy.mockReturnValue(popup);\n vi.mocked(fetch).mockReset();\n vi.mocked(fetch)\n .mockResolvedValueOnce(\n jsonResponse({\n configured: false,\n envManaged: false,\n builderEnabled: true,\n orgName: null,\n cliAuthUrl: signedCliAuthUrl,\n connectUrl:\n \"http://localhost:3000/_agent-native/builder/connect?_an_connect=signed\",\n appHost: \"https://builder.io\",\n apiHost: \"https://api.builder.io\",\n publicKeyConfigured: false,\n privateKeyConfigured: false,\n }),\n )\n .mockResolvedValueOnce(new Response(\"Unauthorized\", { status: 401 }));\n\n await act(async () => {\n root.render(<BuilderConnectProbe />);\n await Promise.resolve();\n await Promise.resolve();\n });\n\n await act(async () => {\n container.querySelector(\"button\")?.click();\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(openSpy).toHaveBeenCalledWith(\n \"about:blank\",\n \"_blank\",\n \"width=600,height=700\",\n );\n expect(popup.location.href).toBe(expectedConnectUrl(signedCliAuthUrl));\n expect(container.textContent).not.toContain(\n \"Couldn't start Builder connect\",\n );\n });\n\n it(\"does not probe Builder status when disabled\", async () => {\n await act(async () => {\n root.render(<BuilderConnectProbe enabled={false} />);\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(fetch).not.toHaveBeenCalled();\n\n await act(async () => {\n container.querySelector(\"button\")?.click();\n await Promise.resolve();\n });\n\n expect(openSpy).not.toHaveBeenCalled();\n expect(fetch).not.toHaveBeenCalled();\n });\n\n it(\"refreshes an un-timestamped signed prop URL before navigating web popups\", async () => {\n setUserAgent(\"Mozilla/5.0 Chrome/140.0\");\n const popup = createPopupStub();\n openSpy.mockReturnValue(popup);\n\n let resolveInitialFetch!: (response: Response) => void;\n const initialFetch = new Promise<Response>((resolve) => {\n resolveInitialFetch = resolve;\n });\n vi.mocked(fetch)\n .mockReturnValueOnce(initialFetch)\n .mockResolvedValue(\n jsonResponse({\n configured: false,\n envManaged: false,\n builderEnabled: true,\n orgName: null,\n cliAuthUrl: refreshedCliAuthUrl,\n connectUrl:\n \"http://localhost:3000/_agent-native/builder/connect?_an_connect=signed\",\n appHost: \"https://builder.io\",\n apiHost: \"https://api.builder.io\",\n publicKeyConfigured: false,\n privateKeyConfigured: false,\n }),\n );\n\n await act(async () => {\n root.render(<BuilderConnectProbe popupUrl={staleCliAuthUrl} />);\n });\n\n await act(async () => {\n container.querySelector(\"button\")?.click();\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(openSpy).toHaveBeenCalledWith(\n \"about:blank\",\n \"_blank\",\n \"width=600,height=700\",\n );\n expect(popup.location.href).toBe(expectedConnectUrl(refreshedCliAuthUrl));\n\n resolveInitialFetch(jsonResponse({ configured: false }));\n });\n\n it(\"refreshes status when a Builder preview callback posts success\", async () => {\n setUserAgent(\"Mozilla/5.0 Chrome/140.0\");\n vi.mocked(fetch)\n .mockResolvedValueOnce(\n jsonResponse({\n configured: false,\n envManaged: false,\n builderEnabled: true,\n orgName: null,\n cliAuthUrl: signedCliAuthUrl,\n connectUrl:\n \"http://localhost:3000/_agent-native/builder/connect?_an_connect=signed\",\n appHost: \"https://builder.io\",\n apiHost: \"https://api.builder.io\",\n publicKeyConfigured: false,\n privateKeyConfigured: false,\n }),\n )\n .mockResolvedValueOnce(\n jsonResponse({\n configured: true,\n envManaged: false,\n builderEnabled: true,\n orgName: \"Builder space\",\n cliAuthUrl: signedCliAuthUrl,\n connectUrl:\n \"http://localhost:3000/_agent-native/builder/connect?_an_connect=signed\",\n appHost: \"https://builder.io\",\n apiHost: \"https://api.builder.io\",\n publicKeyConfigured: true,\n privateKeyConfigured: true,\n }),\n );\n\n await act(async () => {\n root.render(<BuilderConnectProbe />);\n await Promise.resolve();\n });\n\n expect(container.textContent).toContain(\"not-configured\");\n\n await act(async () => {\n window.dispatchEvent(\n new MessageEvent(\"message\", {\n origin:\n \"https://940ebc5a83164aa6a37dde445e494f3a-fluid-crack-ctnhvsyb.builderio.xyz\",\n data: { type: \"builder-connect-success\" },\n }),\n );\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(container.textContent).toContain(\"configured\");\n });\n\n it(\"clears the spinner when the callback succeeds but status never confirms credentials\", async () => {\n vi.useFakeTimers();\n vi.setSystemTime(new Date(\"2026-05-14T12:00:00.000Z\"));\n setUserAgent(\"Mozilla/5.0 Chrome/140.0\");\n const popup = createPopupStub();\n openSpy.mockReturnValue(popup);\n vi.mocked(fetch).mockImplementation(async () =>\n jsonResponse({\n configured: false,\n envManaged: false,\n builderEnabled: true,\n orgName: null,\n cliAuthUrl: signedCliAuthUrl,\n connectUrl:\n \"http://localhost:3000/_agent-native/builder/connect?_an_connect=signed\",\n appHost: \"https://builder.io\",\n apiHost: \"https://api.builder.io\",\n publicKeyConfigured: false,\n privateKeyConfigured: false,\n }),\n );\n\n await act(async () => {\n root.render(<BuilderConnectProbe />);\n await Promise.resolve();\n });\n\n await act(async () => {\n container.querySelector(\"button\")?.click();\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(container.textContent).toContain(\"not-configured connecting\");\n\n await act(async () => {\n window.dispatchEvent(\n new MessageEvent(\"message\", {\n origin: \"https://agent-workspace.builder.io\",\n data: { type: \"builder-connect-success\" },\n }),\n );\n await vi.advanceTimersByTimeAsync(5000);\n });\n\n expect(container.textContent).toContain(\"not-configured idle\");\n expect(container.textContent).toContain(\"couldn't confirm\");\n });\n\n it(\"clears the spinner when the popup closes before status confirms credentials\", async () => {\n vi.useFakeTimers();\n vi.setSystemTime(new Date(\"2026-05-14T12:00:00.000Z\"));\n setUserAgent(\"Mozilla/5.0 Chrome/140.0\");\n const popup = createPopupStub();\n openSpy.mockReturnValue(popup);\n vi.mocked(fetch).mockImplementation(async () =>\n jsonResponse({\n configured: false,\n envManaged: false,\n builderEnabled: true,\n orgName: null,\n cliAuthUrl: signedCliAuthUrl,\n connectUrl:\n \"http://localhost:3000/_agent-native/builder/connect?_an_connect=signed\",\n appHost: \"https://builder.io\",\n apiHost: \"https://api.builder.io\",\n publicKeyConfigured: false,\n privateKeyConfigured: false,\n }),\n );\n\n await act(async () => {\n root.render(<BuilderConnectProbe />);\n await Promise.resolve();\n });\n\n await act(async () => {\n container.querySelector(\"button\")?.click();\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(container.textContent).toContain(\"not-configured connecting\");\n\n (popup as unknown as { closed: boolean }).closed = true;\n await act(async () => {\n await vi.advanceTimersByTimeAsync(8000);\n });\n\n expect(container.textContent).toContain(\"not-configured idle\");\n expect(container.textContent).toContain(\"couldn't confirm\");\n });\n\n it(\"does not replace the desktop webview when Electron reports a handled popup as null\", async () => {\n setUserAgent(\"Mozilla/5.0 Electron/41.2.2 AgentNativeDesktop/0.1.7\");\n\n await act(async () => {\n root.render(<BuilderConnectProbe />);\n });\n\n await act(async () => {\n container.querySelector(\"button\")?.click();\n });\n\n expect(openSpy).toHaveBeenCalledWith(\n expectedConnectUrl(signedCliAuthUrl),\n \"_blank\",\n \"noopener,noreferrer\",\n );\n expect(window.location.href).toBe(\"http://localhost:3000/settings\");\n expect(container.textContent).not.toContain(\"Popup blocked\");\n });\n\n it(\"does not abort a reconnect popup because the old credential was rejected\", async () => {\n vi.useFakeTimers();\n vi.setSystemTime(new Date(\"2026-05-14T12:00:00.000Z\"));\n setUserAgent(\"Mozilla/5.0 Chrome/140.0\");\n const popup = createPopupStub();\n openSpy.mockReturnValue(popup);\n const signedConnectUrl =\n \"http://localhost:3000/_agent-native/builder/connect?_an_connect=signed\";\n vi.mocked(fetch).mockImplementation(async () =>\n jsonResponse({\n configured: false,\n envManaged: true,\n builderEnabled: true,\n orgName: null,\n connectUrl: signedConnectUrl,\n appHost: \"https://builder.io\",\n apiHost: \"https://api.builder.io\",\n publicKeyConfigured: false,\n privateKeyConfigured: false,\n authError: {\n message: \"Private key does not match spaceId\",\n at: Date.now() - 60_000,\n },\n }),\n );\n\n await act(async () => {\n root.render(<BuilderConnectProbe />);\n await Promise.resolve();\n });\n\n expect(container.textContent).toContain(\n \"Private key does not match spaceId\",\n );\n\n await act(async () => {\n container.querySelector(\"button\")?.click();\n await Promise.resolve();\n await Promise.resolve();\n });\n\n expect(openSpy).toHaveBeenCalledWith(\n \"about:blank\",\n \"_blank\",\n \"width=600,height=700\",\n );\n expect(popup.location.href).toBe(expectedConnectUrl(signedConnectUrl));\n expect(container.textContent).toContain(\"not-configured connecting\");\n expect(container.textContent).not.toContain(\n \"Private key does not match spaceId\",\n );\n\n await act(async () => {\n await vi.advanceTimersByTimeAsync(2000);\n });\n\n expect(container.textContent).toContain(\"not-configured connecting\");\n expect(container.textContent).not.toContain(\n \"Private key does not match spaceId\",\n );\n });\n\n it(\"ignores stale connect callback errors after starting a fresh reconnect\", async () => {\n vi.useFakeTimers();\n vi.setSystemTime(new Date(\"2026-05-14T12:00:00.000Z\"));\n setUserAgent(\"Mozilla/5.0 Chrome/140.0\");\n const popup = createPopupStub();\n openSpy.mockReturnValue(popup);\n const signedConnectUrl =\n \"http://localhost:3000/_agent-native/builder/connect?_an_connect=signed\";\n vi.mocked(fetch).mockImplementation(async () =>\n jsonResponse({\n configured: false,\n envManaged: false,\n builderEnabled: true,\n orgName: null,\n connectUrl: signedConnectUrl,\n appHost: \"https://builder.io\",\n apiHost: \"https://api.builder.io\",\n publicKeyConfigured: false,\n privateKeyConfigured: false,\n connectError: {\n message: \"No active connect flow found\",\n at: Date.now() - 60_000,\n },\n }),\n );\n\n await act(async () => {\n root.render(<BuilderConnectProbe />);\n await Promise.resolve();\n });\n\n expect(container.textContent).toContain(\"No active connect flow found\");\n\n await act(async () => {\n container.querySelector(\"button\")?.click();\n });\n\n await act(async () => {\n await vi.advanceTimersByTimeAsync(2000);\n });\n\n expect(container.textContent).toContain(\"not-configured connecting\");\n expect(container.textContent).not.toContain(\"No active connect flow found\");\n });\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"google-auth-plugin.d.ts","sourceRoot":"","sources":["../../src/server/google-auth-plugin.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,cAAc,EACpB,MAAM,uBAAuB,CAAC;AAE/B,KAAK,cAAc,GAAG,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9D,MAAM,WAAW,uBAAuB;IACtC,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAmbD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,CAAC,EAAE,uBAAuB,GAChC,cAAc,CAYhB"}
1
+ {"version":3,"file":"google-auth-plugin.d.ts","sourceRoot":"","sources":["../../src/server/google-auth-plugin.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,cAAc,EACpB,MAAM,uBAAuB,CAAC;AAE/B,KAAK,cAAc,GAAG,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9D,MAAM,WAAW,uBAAuB;IACtC,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AA2bD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,CAAC,EAAE,uBAAuB,GAChC,cAAc,CAYhB"}
@@ -300,6 +300,13 @@ function getGoogleLoginHtml(googleAuthMode) {
300
300
  err.classList.add('show');
301
301
  btn.disabled = false;
302
302
  }
303
+ function __anHandlePopupOAuthFailure(ret, btn, err, flowId, redirectReason, builderFrameMessage) {
304
+ if (__anIsBuilderPreview() && __anIsInFrame()) {
305
+ __anShowOAuthError(err, btn, builderFrameMessage + ' Allow popups for this site and try again (flow ' + __anFlowDebugId(flowId) + ').');
306
+ return;
307
+ }
308
+ __anStartRedirectOAuth(ret, btn, err, flowId, redirectReason);
309
+ }
303
310
  function __anStartRedirectOAuth(ret, btn, err, flowId, reason) {
304
311
  var params = new URLSearchParams();
305
312
  var oauthReturn = __anIsBuilderPreview() ? __anOAuthReturnTarget(ret) : ret;
@@ -362,7 +369,7 @@ function getGoogleLoginHtml(googleAuthMode) {
362
369
  try {
363
370
  var popup = window.open('', '_blank', 'width=640,height=760');
364
371
  if (!popup) {
365
- __anStartRedirectOAuth(ret, btn, err, flowId, 'Google popup was blocked; falling back to redirect');
372
+ __anHandlePopupOAuthFailure(ret, btn, err, flowId, 'Google popup was blocked; falling back to redirect', 'Google popup was blocked.');
366
373
  return;
367
374
  }
368
375
  try { popup.opener = null; } catch(e) {}
@@ -370,12 +377,12 @@ function getGoogleLoginHtml(googleAuthMode) {
370
377
  popup.location.href = url;
371
378
  } catch(e) {
372
379
  try { popup.close(); } catch(closeErr) {}
373
- __anStartRedirectOAuth(ret, btn, err, flowId, 'Could not navigate Google popup; falling back to redirect');
380
+ __anHandlePopupOAuthFailure(ret, btn, err, flowId, 'Could not navigate Google popup; falling back to redirect', 'Could not navigate Google popup.');
374
381
  return;
375
382
  }
376
383
  __anSetOAuthDebug('Google popup opened; waiting for callback', flowId);
377
384
  } catch(e) {
378
- __anStartRedirectOAuth(ret, btn, err, flowId, 'Could not open Google popup; falling back to redirect');
385
+ __anHandlePopupOAuthFailure(ret, btn, err, flowId, 'Could not open Google popup; falling back to redirect', 'Could not open Google popup.');
379
386
  return;
380
387
  }
381
388
  __anWaitForOAuthExchange(flowId, ret, btn, err);
@@ -411,7 +418,8 @@ function getGoogleLoginHtml(googleAuthMode) {
411
418
  return;
412
419
  }
413
420
  if (__anIsBuilderPreview()) {
414
- __anStartRedirectOAuth(ret, btn, err);
421
+ var flowId = __anNewOAuthFlowId();
422
+ __anStartRedirectOAuth(ret, btn, err, flowId, 'Opening Google sign-in redirect from Builder preview');
415
423
  return;
416
424
  }
417
425
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"google-auth-plugin.js","sourceRoot":"","sources":["../../src/server/google-auth-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,+BAA+B,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EACL,qBAAqB,GAEtB,MAAM,uBAAuB,CAAC;AAgB/B,SAAS,kBAAkB,CAAC,cAA8B;IACxD,MAAM,iBAAiB,GAAG,oBAAoB,EAAE,CAAC;IACjD,MAAM,4BAA4B,GAAG,+BAA+B,EAAE,CAAC;IACvE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mCA+E0B,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC;+CACrB,IAAI,CAAC,SAAS,CAAC,4BAA4B,CAAC;gCAC3D,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA0VtD,CAAC;AACT,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAAiC;IAEjC,OAAO,gBAAgB,CAAC;QACtB,WAAW,EAAE;YACX,gCAAgC;YAChC,gCAAgC;YAChC,wBAAwB;YACxB,GAAG,CAAC,OAAO,EAAE,WAAW,IAAI,EAAE,CAAC;SAChC;QACD,SAAS,EAAE,kBAAkB,CAC3B,qBAAqB,CAAC,OAAO,EAAE,cAAc,CAAC,CAC/C;KACF,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { createAuthPlugin } from \"./auth-plugin.js\";\nimport { getPublicOAuthOrigin } from \"./oauth-public-origin.js\";\nimport { getWorkspaceGatewayReturnOrigin } from \"./oauth-return-url.js\";\nimport {\n resolveGoogleAuthMode,\n type GoogleAuthMode,\n} from \"./google-auth-mode.js\";\n\ntype NitroPluginDef = (nitroApp: any) => void | Promise<void>;\n\nexport interface GoogleAuthPluginOptions {\n /** Additional paths accessible without authentication */\n publicPaths?: string[];\n /**\n * Google sign-in flow: `'popup'`, `'redirect'`, or `'auto'` (default).\n * Falls back to `GOOGLE_AUTH_MODE` env var, then `'auto'`. Builder\n * iframes use popup; top-level Builder preview/editor surfaces use\n * redirect.\n */\n googleAuthMode?: GoogleAuthMode;\n}\n\nfunction getGoogleLoginHtml(googleAuthMode: GoogleAuthMode): string {\n const publicOAuthOrigin = getPublicOAuthOrigin();\n const workspaceGatewayReturnOrigin = getWorkspaceGatewayReturnOrigin();\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\">\n<title>Sign in</title>\n<style>\n *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n background: #0a0a0a;\n color: #e5e5e5;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n }\n .card {\n width: 100%;\n max-width: 360px;\n padding: 2rem;\n background: #141414;\n border: 1px solid rgba(255,255,255,0.08);\n border-radius: 12px;\n text-align: center;\n }\n h1 { font-size: 1.125rem; font-weight: 600; margin-bottom: 0.5rem; color: #fff; }\n .subtitle { font-size: 0.8125rem; color: #888; margin-bottom: 1.5rem; }\n button {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.625rem;\n padding: 0.625rem;\n background: #fff;\n color: #000;\n border: none;\n border-radius: 8px;\n font-size: 0.9375rem;\n font-weight: 500;\n cursor: pointer;\n }\n button:hover { opacity: 0.85; }\n button:disabled { opacity: 0.5; cursor: wait; }\n .error { margin-top: 0.75rem; font-size: 0.8125rem; color: #f87171; display: none; }\n .error.show { display: block; }\n .debug {\n display: none;\n margin-top: 0.625rem;\n font-size: 0.6875rem;\n line-height: 1.45;\n color: #777;\n word-break: break-word;\n }\n .debug.show { display: block; }\n svg { width: 18px; height: 18px; }\n</style>\n</head>\n<body>\n<div class=\"card\">\n <h1>Sign in</h1>\n <p class=\"subtitle\">Continue with your Google account</p>\n <button id=\"btn\" onclick=\"signIn()\">\n <svg viewBox=\"0 0 24 24\"><path fill=\"#4285F4\" d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 0 1-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z\"/><path fill=\"#34A853\" d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"/><path fill=\"#FBBC05\" d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"/><path fill=\"#EA4335\" d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"/></svg>\n Sign in with Google\n </button>\n <p class=\"error\" id=\"err\"></p>\n <p class=\"debug\" id=\"debug\"></p>\n</div>\n<script>\n function __anBasePath() {\n var marker = '/_agent-native';\n var idx = window.location.pathname.indexOf(marker);\n return idx > 0 ? window.location.pathname.slice(0, idx) : '';\n }\n function __anPath(path) {\n return __anBasePath() + path;\n }\n var __AN_PUBLIC_OAUTH_ORIGIN = ${JSON.stringify(publicOAuthOrigin)};\n var __AN_WORKSPACE_GATEWAY_RETURN_ORIGIN = ${JSON.stringify(workspaceGatewayReturnOrigin)};\n var __AN_GOOGLE_AUTH_MODE = ${JSON.stringify(googleAuthMode)};\n function __anConfiguredOAuthOrigin() {\n if (!__AN_PUBLIC_OAUTH_ORIGIN) return '';\n try {\n var origin = new URL(__AN_PUBLIC_OAUTH_ORIGIN).origin;\n return origin && origin !== window.location.origin ? origin : '';\n } catch(e) {\n return '';\n }\n }\n function __anAuthPath(path) {\n var origin = __anIsBuilderPreview() ? __anConfiguredOAuthOrigin() : '';\n return origin ? origin + path : __anPath(path);\n }\n function __anGoogleAuthUrlPath() {\n return __anIsBuilderPreview()\n ? __anAuthPath('/_agent-native/google/auth-url')\n : __anPath('/_agent-native/google/auth-url');\n }\n function __anBuilderPreviewReturnOrigin() {\n var candidates = [window.location.href, document.referrer || ''];\n try {\n if (window.location.ancestorOrigins) {\n for (var j = 0; j < window.location.ancestorOrigins.length; j++) {\n candidates.push(window.location.ancestorOrigins[j]);\n }\n }\n } catch(e) {}\n for (var i = 0; i < candidates.length; i++) {\n try {\n var url = new URL(candidates[i]);\n var host = url.hostname.toLowerCase();\n var isPreviewHost =\n host === 'builderio.xyz' || host.slice(-14) === '.builderio.xyz' ||\n host === 'builderio.dev' || host.slice(-14) === '.builderio.dev' ||\n host === 'builder.codes' || host.slice(-14) === '.builder.codes' ||\n host === 'builder.my' || host.slice(-11) === '.builder.my';\n if (url.protocol === 'https:' && isPreviewHost) return url.origin;\n } catch(e) {}\n }\n return '';\n }\n function __anWorkspaceGatewayReturnOrigin() {\n var previewOrigin = __anBuilderPreviewReturnOrigin();\n if (previewOrigin) return previewOrigin;\n if (__AN_WORKSPACE_GATEWAY_RETURN_ORIGIN) return __AN_WORKSPACE_GATEWAY_RETURN_ORIGIN;\n return __anIsBuilderDesktop() ? 'http://127.0.0.1:8080' : '';\n }\n function __anNormalizeWorkspaceReturnPath(ret) {\n try {\n var url = new URL(ret || '/', window.location.origin);\n var path = url.pathname || '/';\n if (path === '/dispatch/dispatch') {\n path = '/dispatch';\n } else if (path.indexOf('/dispatch/') === 0) {\n var rest = path.slice('/dispatch/'.length);\n var first = rest.split('/')[0];\n var dispatchRoutes = {\n overview: true, apps: true, metrics: true, vault: true,\n integrations: true, messaging: true, workspace: true,\n agents: true, destinations: true, identities: true,\n approvals: true, audit: true, team: true, 'thread-debug': true,\n 'new-app': true\n };\n if (first === 'dispatch') {\n path = '/dispatch' + rest.slice(first.length);\n } else if (first && !dispatchRoutes[first]) {\n path = '/' + rest;\n }\n }\n return path + url.search + url.hash;\n } catch(e) {\n return ret || '/';\n }\n }\n function __anOAuthReturnTarget(ret) {\n var path = __anNormalizeWorkspaceReturnPath(ret);\n var origin = __anWorkspaceGatewayReturnOrigin();\n return origin ? origin + path : path;\n }\n function __anSessionBridgeUrl(ret, sessionToken) {\n try {\n var url = new URL(ret || window.location.pathname + window.location.search, window.location.origin);\n url.searchParams.set('_session', sessionToken);\n return url.pathname + url.search + url.hash;\n } catch(e) {\n var sep = (ret || '/').indexOf('?') === -1 ? '?' : '&';\n return (ret || '/') + sep + '_session=' + encodeURIComponent(sessionToken);\n }\n }\n function __anFinishOAuthExchange(ret, flowId, sessionToken) {\n if (__anIsBuilderPreview()) {\n if (sessionToken) {\n __anSetOAuthDebug('OAuth exchange redeemed; applying session bridge to embedded app', flowId);\n window.location.replace(__anSessionBridgeUrl(ret, sessionToken));\n return;\n }\n __anSetOAuthDebug('OAuth exchange redeemed; reloading the embedded app', flowId);\n window.location.reload();\n return;\n }\n __anSetOAuthDebug('OAuth exchange redeemed; returning to the app', flowId);\n window.location.href = ret || '/';\n }\n var __anBuilderPreviewSeen = false;\n function __anRememberBuilderPreview() {\n __anBuilderPreviewSeen = true;\n try { sessionStorage.setItem('__an_builder_preview_seen', '1'); } catch(e) {}\n }\n function __anHasBuilderPreviewSignal() {\n try {\n var params = new URLSearchParams(window.location.search);\n if (params.has('builder.preview') || params.has('builder.frameEditing') || params.has('__builder_editing__')) return true;\n } catch(e) {}\n return false;\n }\n function __anIsBuilderPreview() {\n if (__anBuilderPreviewSeen) return true;\n if (__anHasBuilderPreviewSignal()) {\n __anRememberBuilderPreview();\n return true;\n }\n try {\n if (sessionStorage.getItem('__an_builder_preview_seen') === '1') {\n __anBuilderPreviewSeen = true;\n return true;\n }\n } catch(e) {}\n try {\n var ref = document.referrer || '';\n var fromBuilder = ref.indexOf('builder.io') !== -1 || ref.indexOf('builder.my') !== -1 || ref.indexOf('builderio.xyz') !== -1 || ref.indexOf('builderio.dev') !== -1 || ref.indexOf('builder.codes') !== -1;\n if (fromBuilder) __anRememberBuilderPreview();\n return fromBuilder;\n } catch(e) {\n return false;\n }\n }\n __anIsBuilderPreview();\n function __anIsBuilderDesktop() {\n try {\n var ua = navigator.userAgent || '';\n return ua.indexOf('Electron') !== -1 && ua.indexOf('AgentNativeDesktop') === -1;\n } catch(e) {\n return false;\n }\n }\n function __anIsAgentNativeDesktop() {\n try {\n return (navigator.userAgent || '').indexOf('AgentNativeDesktop') !== -1;\n } catch(e) {\n return false;\n }\n }\n function __anIsInFrame() {\n try {\n return window.self !== window.top;\n } catch(e) {\n return true;\n }\n }\n function __anIsElectron() {\n try {\n return (navigator.userAgent || '').indexOf('Electron') !== -1;\n } catch(e) {\n return false;\n }\n }\n function __anResolveAuthFlow() {\n if (__anIsBuilderPreview()) return __anIsInFrame() ? 'popup' : 'redirect';\n var mode = __AN_GOOGLE_AUTH_MODE || 'auto';\n if (mode === 'popup') return 'popup';\n if (mode === 'redirect') return 'redirect';\n return __anIsAgentNativeDesktop() ? 'redirect' : 'popup';\n }\n var __anOAuthPollTimer = null;\n var __anOAuthPollCount = 0;\n function __anNewOAuthFlowId() {\n try {\n if (window.crypto && typeof window.crypto.randomUUID === 'function') {\n return window.crypto.randomUUID();\n }\n } catch(e) {}\n return 'builder-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2);\n }\n function __anFlowDebugId(flowId) {\n return flowId ? String(flowId).slice(-10) : '';\n }\n function __anShouldShowOAuthDebug() {\n try {\n var loc = window.location || {};\n return (typeof loc.hash === 'string' && loc.hash.indexOf('oauth-debug') !== -1) ||\n (typeof loc.search === 'string' && loc.search.indexOf('oauth_debug=1') !== -1);\n } catch(e) { return false; }\n }\n function __anSetOAuthDebug(message, flowId) {\n var text = message + (flowId ? ' (flow ' + __anFlowDebugId(flowId) + ')' : '');\n try {\n console.info('[agent-native][google-oauth] ' + text);\n } catch(e) {}\n var debug = document.getElementById('debug');\n if (debug) {\n debug.textContent = text;\n if (__anShouldShowOAuthDebug()) debug.classList.add('show');\n }\n }\n function __anShowOAuthError(err, btn, message) {\n if (__anOAuthPollTimer) {\n clearInterval(__anOAuthPollTimer);\n __anOAuthPollTimer = null;\n }\n err.textContent = message;\n err.classList.add('show');\n btn.disabled = false;\n }\n function __anStartRedirectOAuth(ret, btn, err, flowId, reason) {\n var params = new URLSearchParams();\n var oauthReturn = __anIsBuilderPreview() ? __anOAuthReturnTarget(ret) : ret;\n if (oauthReturn) params.set('return', oauthReturn);\n params.set('redirect', '1');\n __anSetOAuthDebug(reason || 'Opening Google sign-in redirect', flowId);\n try {\n __anOpenOAuthUrl(__anGoogleAuthUrlPath() + '?' + params.toString());\n } catch(e) {\n __anShowOAuthError(err, btn, 'Could not start Google sign-in redirect' + (flowId ? ' for flow ' + __anFlowDebugId(flowId) : '') + ': ' + (e && e.message ? e.message : 'unknown error'));\n }\n }\n function __anWaitForOAuthExchange(flowId, ret, btn, err) {\n var started = Date.now();\n var timeoutMs = 5 * 60 * 1000;\n __anOAuthPollCount = 0;\n async function check() {\n __anOAuthPollCount++;\n try {\n var res = await fetch(__anPath('/_agent-native/auth/desktop-exchange') + '?flow_id=' + encodeURIComponent(flowId), { credentials: 'include' });\n var data = await res.json().catch(function() { return {}; });\n if (data && (data.email || data.token)) {\n if (__anOAuthPollTimer) clearInterval(__anOAuthPollTimer);\n __anOAuthPollTimer = null;\n __anFinishOAuthExchange(ret, flowId, data.token);\n return;\n }\n if (data && data.error) {\n __anSetOAuthDebug('OAuth exchange returned an error: ' + (data.message || data.error), flowId);\n __anShowOAuthError(err, btn, data.message || data.error);\n return;\n }\n if (data && data.pending && (__anOAuthPollCount === 1 || __anOAuthPollCount % 5 === 0)) {\n __anSetOAuthDebug('Waiting for the Google callback; polling attempt ' + __anOAuthPollCount, flowId);\n }\n } catch(e) {\n if (__anOAuthPollCount === 1 || __anOAuthPollCount % 5 === 0) {\n __anSetOAuthDebug('Could not reach the OAuth exchange endpoint: ' + (e && e.message ? e.message : 'network error'), flowId);\n }\n }\n if (Date.now() - started > timeoutMs) {\n __anShowOAuthError(err, btn, 'Google sign-in did not finish. Flow ' + __anFlowDebugId(flowId) + ' never reached this app. Check the Google OAuth redirect URI and server logs for [agent-native][google-oauth].');\n }\n }\n if (__anOAuthPollTimer) clearInterval(__anOAuthPollTimer);\n __anOAuthPollTimer = setInterval(check, 1000);\n setTimeout(check, 500);\n }\n function __anStartPopupOAuth(ret, btn, err) {\n var flowId = __anNewOAuthFlowId();\n var oauthReturn = __anIsBuilderPreview() ? __anOAuthReturnTarget(ret) : ret;\n var params = new URLSearchParams();\n if (oauthReturn) params.set('return', oauthReturn);\n params.set('desktop', '1');\n params.set('flow_id', flowId);\n params.set('redirect', '1');\n var url = __anGoogleAuthUrlPath() + '?' + params.toString();\n try { sessionStorage.setItem('__an_signin', '1'); } catch(e) {}\n __anSetOAuthDebug('Opening Google sign-in popup', flowId);\n try {\n var popup = window.open('', '_blank', 'width=640,height=760');\n if (!popup) {\n __anStartRedirectOAuth(ret, btn, err, flowId, 'Google popup was blocked; falling back to redirect');\n return;\n }\n try { popup.opener = null; } catch(e) {}\n try {\n popup.location.href = url;\n } catch(e) {\n try { popup.close(); } catch(closeErr) {}\n __anStartRedirectOAuth(ret, btn, err, flowId, 'Could not navigate Google popup; falling back to redirect');\n return;\n }\n __anSetOAuthDebug('Google popup opened; waiting for callback', flowId);\n } catch(e) {\n __anStartRedirectOAuth(ret, btn, err, flowId, 'Could not open Google popup; falling back to redirect');\n return;\n }\n __anWaitForOAuthExchange(flowId, ret, btn, err);\n }\n function __anStartNativeDesktopOAuth(ret, btn, err) {\n var flowId = __anNewOAuthFlowId();\n var params = new URLSearchParams();\n if (ret) params.set('return', ret);\n params.set('desktop', '1');\n params.set('flow_id', flowId);\n params.set('redirect', '1');\n var url = __anGoogleAuthUrlPath() + '?' + params.toString();\n __anSetOAuthDebug('Opening Google sign-in in system browser', flowId);\n __anOpenOAuthUrl(url);\n __anWaitForOAuthExchange(flowId, ret, btn, err);\n }\n function __anOpenOAuthUrl(url) {\n try { sessionStorage.setItem('__an_signin', '1'); } catch(e) {}\n window.location.href = url;\n }\n async function signIn() {\n var btn = document.getElementById('btn');\n var err = document.getElementById('err');\n var ret = window.location.pathname + window.location.search;\n btn.disabled = true;\n err.classList.remove('show');\n if (__anResolveAuthFlow() === 'popup') {\n __anStartPopupOAuth(ret, btn, err);\n return;\n }\n if (__anIsAgentNativeDesktop()) {\n __anStartNativeDesktopOAuth(ret, btn, err);\n return;\n }\n if (__anIsBuilderPreview()) {\n __anStartRedirectOAuth(ret, btn, err);\n return;\n }\n try {\n var res = await fetch(__anGoogleAuthUrlPath() + '?return=' + encodeURIComponent(ret));\n var data = await res.json();\n if (data.url) {\n __anOpenOAuthUrl(data.url);\n } else {\n err.textContent = data.message || 'Google OAuth is not configured. Set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET.';\n err.classList.add('show');\n btn.disabled = false;\n }\n } catch (e) {\n err.textContent = 'Failed to connect. Please try again.';\n err.classList.add('show');\n btn.disabled = false;\n }\n }\n</script>\n</body>\n</html>`;\n}\n\n/**\n * Create an auth plugin that uses Google OAuth for authentication.\n *\n * When a user visits the app unauthenticated, they see a \"Sign in with Google\"\n * page. The Google OAuth callback (handled by the template) creates a session\n * tied to the user's Google email. `getSession()` then returns `{ email }` for\n * all subsequent requests.\n *\n * Better Auth handles Google OAuth internally when GOOGLE_CLIENT_ID and\n * GOOGLE_CLIENT_SECRET are set. The template's callback route at\n * /_agent-native/google/callback handles mobile deep linking.\n *\n * Usage in a template's `server/plugins/auth.ts`:\n * ```ts\n * import { createGoogleAuthPlugin } from \"@agent-native/core/server\";\n * export default createGoogleAuthPlugin();\n * ```\n */\nexport function createGoogleAuthPlugin(\n options?: GoogleAuthPluginOptions,\n): NitroPluginDef {\n return createAuthPlugin({\n publicPaths: [\n \"/_agent-native/google/callback\",\n \"/_agent-native/google/auth-url\",\n \"/_agent-native/auth/ba\",\n ...(options?.publicPaths ?? []),\n ],\n loginHtml: getGoogleLoginHtml(\n resolveGoogleAuthMode(options?.googleAuthMode),\n ),\n });\n}\n"]}
1
+ {"version":3,"file":"google-auth-plugin.js","sourceRoot":"","sources":["../../src/server/google-auth-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,+BAA+B,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EACL,qBAAqB,GAEtB,MAAM,uBAAuB,CAAC;AAgB/B,SAAS,kBAAkB,CAAC,cAA8B;IACxD,MAAM,iBAAiB,GAAG,oBAAoB,EAAE,CAAC;IACjD,MAAM,4BAA4B,GAAG,+BAA+B,EAAE,CAAC;IACvE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mCA+E0B,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC;+CACrB,IAAI,CAAC,SAAS,CAAC,4BAA4B,CAAC;gCAC3D,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAkWtD,CAAC;AACT,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAAiC;IAEjC,OAAO,gBAAgB,CAAC;QACtB,WAAW,EAAE;YACX,gCAAgC;YAChC,gCAAgC;YAChC,wBAAwB;YACxB,GAAG,CAAC,OAAO,EAAE,WAAW,IAAI,EAAE,CAAC;SAChC;QACD,SAAS,EAAE,kBAAkB,CAC3B,qBAAqB,CAAC,OAAO,EAAE,cAAc,CAAC,CAC/C;KACF,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { createAuthPlugin } from \"./auth-plugin.js\";\nimport { getPublicOAuthOrigin } from \"./oauth-public-origin.js\";\nimport { getWorkspaceGatewayReturnOrigin } from \"./oauth-return-url.js\";\nimport {\n resolveGoogleAuthMode,\n type GoogleAuthMode,\n} from \"./google-auth-mode.js\";\n\ntype NitroPluginDef = (nitroApp: any) => void | Promise<void>;\n\nexport interface GoogleAuthPluginOptions {\n /** Additional paths accessible without authentication */\n publicPaths?: string[];\n /**\n * Google sign-in flow: `'popup'`, `'redirect'`, or `'auto'` (default).\n * Falls back to `GOOGLE_AUTH_MODE` env var, then `'auto'`. Builder\n * iframes use popup; top-level Builder preview/editor surfaces use\n * redirect.\n */\n googleAuthMode?: GoogleAuthMode;\n}\n\nfunction getGoogleLoginHtml(googleAuthMode: GoogleAuthMode): string {\n const publicOAuthOrigin = getPublicOAuthOrigin();\n const workspaceGatewayReturnOrigin = getWorkspaceGatewayReturnOrigin();\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\">\n<title>Sign in</title>\n<style>\n *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n background: #0a0a0a;\n color: #e5e5e5;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n }\n .card {\n width: 100%;\n max-width: 360px;\n padding: 2rem;\n background: #141414;\n border: 1px solid rgba(255,255,255,0.08);\n border-radius: 12px;\n text-align: center;\n }\n h1 { font-size: 1.125rem; font-weight: 600; margin-bottom: 0.5rem; color: #fff; }\n .subtitle { font-size: 0.8125rem; color: #888; margin-bottom: 1.5rem; }\n button {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.625rem;\n padding: 0.625rem;\n background: #fff;\n color: #000;\n border: none;\n border-radius: 8px;\n font-size: 0.9375rem;\n font-weight: 500;\n cursor: pointer;\n }\n button:hover { opacity: 0.85; }\n button:disabled { opacity: 0.5; cursor: wait; }\n .error { margin-top: 0.75rem; font-size: 0.8125rem; color: #f87171; display: none; }\n .error.show { display: block; }\n .debug {\n display: none;\n margin-top: 0.625rem;\n font-size: 0.6875rem;\n line-height: 1.45;\n color: #777;\n word-break: break-word;\n }\n .debug.show { display: block; }\n svg { width: 18px; height: 18px; }\n</style>\n</head>\n<body>\n<div class=\"card\">\n <h1>Sign in</h1>\n <p class=\"subtitle\">Continue with your Google account</p>\n <button id=\"btn\" onclick=\"signIn()\">\n <svg viewBox=\"0 0 24 24\"><path fill=\"#4285F4\" d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 0 1-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z\"/><path fill=\"#34A853\" d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"/><path fill=\"#FBBC05\" d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"/><path fill=\"#EA4335\" d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"/></svg>\n Sign in with Google\n </button>\n <p class=\"error\" id=\"err\"></p>\n <p class=\"debug\" id=\"debug\"></p>\n</div>\n<script>\n function __anBasePath() {\n var marker = '/_agent-native';\n var idx = window.location.pathname.indexOf(marker);\n return idx > 0 ? window.location.pathname.slice(0, idx) : '';\n }\n function __anPath(path) {\n return __anBasePath() + path;\n }\n var __AN_PUBLIC_OAUTH_ORIGIN = ${JSON.stringify(publicOAuthOrigin)};\n var __AN_WORKSPACE_GATEWAY_RETURN_ORIGIN = ${JSON.stringify(workspaceGatewayReturnOrigin)};\n var __AN_GOOGLE_AUTH_MODE = ${JSON.stringify(googleAuthMode)};\n function __anConfiguredOAuthOrigin() {\n if (!__AN_PUBLIC_OAUTH_ORIGIN) return '';\n try {\n var origin = new URL(__AN_PUBLIC_OAUTH_ORIGIN).origin;\n return origin && origin !== window.location.origin ? origin : '';\n } catch(e) {\n return '';\n }\n }\n function __anAuthPath(path) {\n var origin = __anIsBuilderPreview() ? __anConfiguredOAuthOrigin() : '';\n return origin ? origin + path : __anPath(path);\n }\n function __anGoogleAuthUrlPath() {\n return __anIsBuilderPreview()\n ? __anAuthPath('/_agent-native/google/auth-url')\n : __anPath('/_agent-native/google/auth-url');\n }\n function __anBuilderPreviewReturnOrigin() {\n var candidates = [window.location.href, document.referrer || ''];\n try {\n if (window.location.ancestorOrigins) {\n for (var j = 0; j < window.location.ancestorOrigins.length; j++) {\n candidates.push(window.location.ancestorOrigins[j]);\n }\n }\n } catch(e) {}\n for (var i = 0; i < candidates.length; i++) {\n try {\n var url = new URL(candidates[i]);\n var host = url.hostname.toLowerCase();\n var isPreviewHost =\n host === 'builderio.xyz' || host.slice(-14) === '.builderio.xyz' ||\n host === 'builderio.dev' || host.slice(-14) === '.builderio.dev' ||\n host === 'builder.codes' || host.slice(-14) === '.builder.codes' ||\n host === 'builder.my' || host.slice(-11) === '.builder.my';\n if (url.protocol === 'https:' && isPreviewHost) return url.origin;\n } catch(e) {}\n }\n return '';\n }\n function __anWorkspaceGatewayReturnOrigin() {\n var previewOrigin = __anBuilderPreviewReturnOrigin();\n if (previewOrigin) return previewOrigin;\n if (__AN_WORKSPACE_GATEWAY_RETURN_ORIGIN) return __AN_WORKSPACE_GATEWAY_RETURN_ORIGIN;\n return __anIsBuilderDesktop() ? 'http://127.0.0.1:8080' : '';\n }\n function __anNormalizeWorkspaceReturnPath(ret) {\n try {\n var url = new URL(ret || '/', window.location.origin);\n var path = url.pathname || '/';\n if (path === '/dispatch/dispatch') {\n path = '/dispatch';\n } else if (path.indexOf('/dispatch/') === 0) {\n var rest = path.slice('/dispatch/'.length);\n var first = rest.split('/')[0];\n var dispatchRoutes = {\n overview: true, apps: true, metrics: true, vault: true,\n integrations: true, messaging: true, workspace: true,\n agents: true, destinations: true, identities: true,\n approvals: true, audit: true, team: true, 'thread-debug': true,\n 'new-app': true\n };\n if (first === 'dispatch') {\n path = '/dispatch' + rest.slice(first.length);\n } else if (first && !dispatchRoutes[first]) {\n path = '/' + rest;\n }\n }\n return path + url.search + url.hash;\n } catch(e) {\n return ret || '/';\n }\n }\n function __anOAuthReturnTarget(ret) {\n var path = __anNormalizeWorkspaceReturnPath(ret);\n var origin = __anWorkspaceGatewayReturnOrigin();\n return origin ? origin + path : path;\n }\n function __anSessionBridgeUrl(ret, sessionToken) {\n try {\n var url = new URL(ret || window.location.pathname + window.location.search, window.location.origin);\n url.searchParams.set('_session', sessionToken);\n return url.pathname + url.search + url.hash;\n } catch(e) {\n var sep = (ret || '/').indexOf('?') === -1 ? '?' : '&';\n return (ret || '/') + sep + '_session=' + encodeURIComponent(sessionToken);\n }\n }\n function __anFinishOAuthExchange(ret, flowId, sessionToken) {\n if (__anIsBuilderPreview()) {\n if (sessionToken) {\n __anSetOAuthDebug('OAuth exchange redeemed; applying session bridge to embedded app', flowId);\n window.location.replace(__anSessionBridgeUrl(ret, sessionToken));\n return;\n }\n __anSetOAuthDebug('OAuth exchange redeemed; reloading the embedded app', flowId);\n window.location.reload();\n return;\n }\n __anSetOAuthDebug('OAuth exchange redeemed; returning to the app', flowId);\n window.location.href = ret || '/';\n }\n var __anBuilderPreviewSeen = false;\n function __anRememberBuilderPreview() {\n __anBuilderPreviewSeen = true;\n try { sessionStorage.setItem('__an_builder_preview_seen', '1'); } catch(e) {}\n }\n function __anHasBuilderPreviewSignal() {\n try {\n var params = new URLSearchParams(window.location.search);\n if (params.has('builder.preview') || params.has('builder.frameEditing') || params.has('__builder_editing__')) return true;\n } catch(e) {}\n return false;\n }\n function __anIsBuilderPreview() {\n if (__anBuilderPreviewSeen) return true;\n if (__anHasBuilderPreviewSignal()) {\n __anRememberBuilderPreview();\n return true;\n }\n try {\n if (sessionStorage.getItem('__an_builder_preview_seen') === '1') {\n __anBuilderPreviewSeen = true;\n return true;\n }\n } catch(e) {}\n try {\n var ref = document.referrer || '';\n var fromBuilder = ref.indexOf('builder.io') !== -1 || ref.indexOf('builder.my') !== -1 || ref.indexOf('builderio.xyz') !== -1 || ref.indexOf('builderio.dev') !== -1 || ref.indexOf('builder.codes') !== -1;\n if (fromBuilder) __anRememberBuilderPreview();\n return fromBuilder;\n } catch(e) {\n return false;\n }\n }\n __anIsBuilderPreview();\n function __anIsBuilderDesktop() {\n try {\n var ua = navigator.userAgent || '';\n return ua.indexOf('Electron') !== -1 && ua.indexOf('AgentNativeDesktop') === -1;\n } catch(e) {\n return false;\n }\n }\n function __anIsAgentNativeDesktop() {\n try {\n return (navigator.userAgent || '').indexOf('AgentNativeDesktop') !== -1;\n } catch(e) {\n return false;\n }\n }\n function __anIsInFrame() {\n try {\n return window.self !== window.top;\n } catch(e) {\n return true;\n }\n }\n function __anIsElectron() {\n try {\n return (navigator.userAgent || '').indexOf('Electron') !== -1;\n } catch(e) {\n return false;\n }\n }\n function __anResolveAuthFlow() {\n if (__anIsBuilderPreview()) return __anIsInFrame() ? 'popup' : 'redirect';\n var mode = __AN_GOOGLE_AUTH_MODE || 'auto';\n if (mode === 'popup') return 'popup';\n if (mode === 'redirect') return 'redirect';\n return __anIsAgentNativeDesktop() ? 'redirect' : 'popup';\n }\n var __anOAuthPollTimer = null;\n var __anOAuthPollCount = 0;\n function __anNewOAuthFlowId() {\n try {\n if (window.crypto && typeof window.crypto.randomUUID === 'function') {\n return window.crypto.randomUUID();\n }\n } catch(e) {}\n return 'builder-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2);\n }\n function __anFlowDebugId(flowId) {\n return flowId ? String(flowId).slice(-10) : '';\n }\n function __anShouldShowOAuthDebug() {\n try {\n var loc = window.location || {};\n return (typeof loc.hash === 'string' && loc.hash.indexOf('oauth-debug') !== -1) ||\n (typeof loc.search === 'string' && loc.search.indexOf('oauth_debug=1') !== -1);\n } catch(e) { return false; }\n }\n function __anSetOAuthDebug(message, flowId) {\n var text = message + (flowId ? ' (flow ' + __anFlowDebugId(flowId) + ')' : '');\n try {\n console.info('[agent-native][google-oauth] ' + text);\n } catch(e) {}\n var debug = document.getElementById('debug');\n if (debug) {\n debug.textContent = text;\n if (__anShouldShowOAuthDebug()) debug.classList.add('show');\n }\n }\n function __anShowOAuthError(err, btn, message) {\n if (__anOAuthPollTimer) {\n clearInterval(__anOAuthPollTimer);\n __anOAuthPollTimer = null;\n }\n err.textContent = message;\n err.classList.add('show');\n btn.disabled = false;\n }\n function __anHandlePopupOAuthFailure(ret, btn, err, flowId, redirectReason, builderFrameMessage) {\n if (__anIsBuilderPreview() && __anIsInFrame()) {\n __anShowOAuthError(err, btn, builderFrameMessage + ' Allow popups for this site and try again (flow ' + __anFlowDebugId(flowId) + ').');\n return;\n }\n __anStartRedirectOAuth(ret, btn, err, flowId, redirectReason);\n }\n function __anStartRedirectOAuth(ret, btn, err, flowId, reason) {\n var params = new URLSearchParams();\n var oauthReturn = __anIsBuilderPreview() ? __anOAuthReturnTarget(ret) : ret;\n if (oauthReturn) params.set('return', oauthReturn);\n params.set('redirect', '1');\n __anSetOAuthDebug(reason || 'Opening Google sign-in redirect', flowId);\n try {\n __anOpenOAuthUrl(__anGoogleAuthUrlPath() + '?' + params.toString());\n } catch(e) {\n __anShowOAuthError(err, btn, 'Could not start Google sign-in redirect' + (flowId ? ' for flow ' + __anFlowDebugId(flowId) : '') + ': ' + (e && e.message ? e.message : 'unknown error'));\n }\n }\n function __anWaitForOAuthExchange(flowId, ret, btn, err) {\n var started = Date.now();\n var timeoutMs = 5 * 60 * 1000;\n __anOAuthPollCount = 0;\n async function check() {\n __anOAuthPollCount++;\n try {\n var res = await fetch(__anPath('/_agent-native/auth/desktop-exchange') + '?flow_id=' + encodeURIComponent(flowId), { credentials: 'include' });\n var data = await res.json().catch(function() { return {}; });\n if (data && (data.email || data.token)) {\n if (__anOAuthPollTimer) clearInterval(__anOAuthPollTimer);\n __anOAuthPollTimer = null;\n __anFinishOAuthExchange(ret, flowId, data.token);\n return;\n }\n if (data && data.error) {\n __anSetOAuthDebug('OAuth exchange returned an error: ' + (data.message || data.error), flowId);\n __anShowOAuthError(err, btn, data.message || data.error);\n return;\n }\n if (data && data.pending && (__anOAuthPollCount === 1 || __anOAuthPollCount % 5 === 0)) {\n __anSetOAuthDebug('Waiting for the Google callback; polling attempt ' + __anOAuthPollCount, flowId);\n }\n } catch(e) {\n if (__anOAuthPollCount === 1 || __anOAuthPollCount % 5 === 0) {\n __anSetOAuthDebug('Could not reach the OAuth exchange endpoint: ' + (e && e.message ? e.message : 'network error'), flowId);\n }\n }\n if (Date.now() - started > timeoutMs) {\n __anShowOAuthError(err, btn, 'Google sign-in did not finish. Flow ' + __anFlowDebugId(flowId) + ' never reached this app. Check the Google OAuth redirect URI and server logs for [agent-native][google-oauth].');\n }\n }\n if (__anOAuthPollTimer) clearInterval(__anOAuthPollTimer);\n __anOAuthPollTimer = setInterval(check, 1000);\n setTimeout(check, 500);\n }\n function __anStartPopupOAuth(ret, btn, err) {\n var flowId = __anNewOAuthFlowId();\n var oauthReturn = __anIsBuilderPreview() ? __anOAuthReturnTarget(ret) : ret;\n var params = new URLSearchParams();\n if (oauthReturn) params.set('return', oauthReturn);\n params.set('desktop', '1');\n params.set('flow_id', flowId);\n params.set('redirect', '1');\n var url = __anGoogleAuthUrlPath() + '?' + params.toString();\n try { sessionStorage.setItem('__an_signin', '1'); } catch(e) {}\n __anSetOAuthDebug('Opening Google sign-in popup', flowId);\n try {\n var popup = window.open('', '_blank', 'width=640,height=760');\n if (!popup) {\n __anHandlePopupOAuthFailure(ret, btn, err, flowId, 'Google popup was blocked; falling back to redirect', 'Google popup was blocked.');\n return;\n }\n try { popup.opener = null; } catch(e) {}\n try {\n popup.location.href = url;\n } catch(e) {\n try { popup.close(); } catch(closeErr) {}\n __anHandlePopupOAuthFailure(ret, btn, err, flowId, 'Could not navigate Google popup; falling back to redirect', 'Could not navigate Google popup.');\n return;\n }\n __anSetOAuthDebug('Google popup opened; waiting for callback', flowId);\n } catch(e) {\n __anHandlePopupOAuthFailure(ret, btn, err, flowId, 'Could not open Google popup; falling back to redirect', 'Could not open Google popup.');\n return;\n }\n __anWaitForOAuthExchange(flowId, ret, btn, err);\n }\n function __anStartNativeDesktopOAuth(ret, btn, err) {\n var flowId = __anNewOAuthFlowId();\n var params = new URLSearchParams();\n if (ret) params.set('return', ret);\n params.set('desktop', '1');\n params.set('flow_id', flowId);\n params.set('redirect', '1');\n var url = __anGoogleAuthUrlPath() + '?' + params.toString();\n __anSetOAuthDebug('Opening Google sign-in in system browser', flowId);\n __anOpenOAuthUrl(url);\n __anWaitForOAuthExchange(flowId, ret, btn, err);\n }\n function __anOpenOAuthUrl(url) {\n try { sessionStorage.setItem('__an_signin', '1'); } catch(e) {}\n window.location.href = url;\n }\n async function signIn() {\n var btn = document.getElementById('btn');\n var err = document.getElementById('err');\n var ret = window.location.pathname + window.location.search;\n btn.disabled = true;\n err.classList.remove('show');\n if (__anResolveAuthFlow() === 'popup') {\n __anStartPopupOAuth(ret, btn, err);\n return;\n }\n if (__anIsAgentNativeDesktop()) {\n __anStartNativeDesktopOAuth(ret, btn, err);\n return;\n }\n if (__anIsBuilderPreview()) {\n var flowId = __anNewOAuthFlowId();\n __anStartRedirectOAuth(ret, btn, err, flowId, 'Opening Google sign-in redirect from Builder preview');\n return;\n }\n try {\n var res = await fetch(__anGoogleAuthUrlPath() + '?return=' + encodeURIComponent(ret));\n var data = await res.json();\n if (data.url) {\n __anOpenOAuthUrl(data.url);\n } else {\n err.textContent = data.message || 'Google OAuth is not configured. Set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET.';\n err.classList.add('show');\n btn.disabled = false;\n }\n } catch (e) {\n err.textContent = 'Failed to connect. Please try again.';\n err.classList.add('show');\n btn.disabled = false;\n }\n }\n</script>\n</body>\n</html>`;\n}\n\n/**\n * Create an auth plugin that uses Google OAuth for authentication.\n *\n * When a user visits the app unauthenticated, they see a \"Sign in with Google\"\n * page. The Google OAuth callback (handled by the template) creates a session\n * tied to the user's Google email. `getSession()` then returns `{ email }` for\n * all subsequent requests.\n *\n * Better Auth handles Google OAuth internally when GOOGLE_CLIENT_ID and\n * GOOGLE_CLIENT_SECRET are set. The template's callback route at\n * /_agent-native/google/callback handles mobile deep linking.\n *\n * Usage in a template's `server/plugins/auth.ts`:\n * ```ts\n * import { createGoogleAuthPlugin } from \"@agent-native/core/server\";\n * export default createGoogleAuthPlugin();\n * ```\n */\nexport function createGoogleAuthPlugin(\n options?: GoogleAuthPluginOptions,\n): NitroPluginDef {\n return createAuthPlugin({\n publicPaths: [\n \"/_agent-native/google/callback\",\n \"/_agent-native/google/auth-url\",\n \"/_agent-native/auth/ba\",\n ...(options?.publicPaths ?? []),\n ],\n loginHtml: getGoogleLoginHtml(\n resolveGoogleAuthMode(options?.googleAuthMode),\n ),\n });\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"onboarding-html.d.ts","sourceRoot":"","sources":["../../src/server/onboarding-html.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAEL,KAAK,cAAc,EACpB,MAAM,uBAAuB,CAAC;AAoC/B,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;QACpB,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF;;;;OAIG;IACH,kBAAkB,CAAC,EAAE;QACnB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QACxB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF;;;;OAIG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,qBAA0B,GAAG,MAAM,CAurD1E;AAED,kDAAkD;AAClD,eAAO,MAAM,eAAe,QAAsB,CAAC;AAEnD;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CA0G7C"}
1
+ {"version":3,"file":"onboarding-html.d.ts","sourceRoot":"","sources":["../../src/server/onboarding-html.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAEL,KAAK,cAAc,EACpB,MAAM,uBAAuB,CAAC;AAoC/B,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;QACpB,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF;;;;OAIG;IACH,kBAAkB,CAAC,EAAE;QACnB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QACxB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF;;;;OAIG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,qBAA0B,GAAG,MAAM,CA+rD1E;AAED,kDAAkD;AAClD,eAAO,MAAM,eAAe,QAAsB,CAAC;AAEnD;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CA0G7C"}
@@ -1073,6 +1073,13 @@ ${googleOnly
1073
1073
  err.classList.add('show');
1074
1074
  btn.disabled = false;
1075
1075
  }
1076
+ function __anHandlePopupOAuthFailure(ret, btn, err, flowId, redirectReason, builderFrameMessage) {
1077
+ if (__anIsBuilderPreview() && __anIsInFrame()) {
1078
+ __anShowOAuthError(err, btn, builderFrameMessage + ' Allow popups for this site and try again (flow ' + __anFlowDebugId(flowId) + ').');
1079
+ return;
1080
+ }
1081
+ __anStartRedirectOAuth(ret, btn, err, flowId, redirectReason);
1082
+ }
1076
1083
  function __anStartRedirectOAuth(ret, btn, err, flowId, reason) {
1077
1084
  var params = new URLSearchParams();
1078
1085
  var oauthReturn = __anIsBuilderPreview() ? __anOAuthReturnTarget(ret) : ret;
@@ -1135,7 +1142,7 @@ ${googleOnly
1135
1142
  try {
1136
1143
  var popup = window.open('', '_blank', 'width=640,height=760');
1137
1144
  if (!popup) {
1138
- __anStartRedirectOAuth(ret, btn, err, flowId, 'Google popup was blocked; falling back to redirect');
1145
+ __anHandlePopupOAuthFailure(ret, btn, err, flowId, 'Google popup was blocked; falling back to redirect', 'Google popup was blocked.');
1139
1146
  return;
1140
1147
  }
1141
1148
  try { popup.opener = null; } catch(e) {}
@@ -1143,12 +1150,12 @@ ${googleOnly
1143
1150
  popup.location.href = url;
1144
1151
  } catch(e) {
1145
1152
  try { popup.close(); } catch(closeErr) {}
1146
- __anStartRedirectOAuth(ret, btn, err, flowId, 'Could not navigate Google popup; falling back to redirect');
1153
+ __anHandlePopupOAuthFailure(ret, btn, err, flowId, 'Could not navigate Google popup; falling back to redirect', 'Could not navigate Google popup.');
1147
1154
  return;
1148
1155
  }
1149
1156
  __anSetOAuthDebug('Google popup opened; waiting for callback', flowId);
1150
1157
  } catch(e) {
1151
- __anStartRedirectOAuth(ret, btn, err, flowId, 'Could not open Google popup; falling back to redirect');
1158
+ __anHandlePopupOAuthFailure(ret, btn, err, flowId, 'Could not open Google popup; falling back to redirect', 'Could not open Google popup.');
1152
1159
  return;
1153
1160
  }
1154
1161
  __anWaitForOAuthExchange(flowId, ret, btn, err);
@@ -1649,7 +1656,8 @@ ${showGoogle
1649
1656
  return;
1650
1657
  }
1651
1658
  if (__anIsBuilderPreview()) {
1652
- __anStartRedirectOAuth(ret, btn, err);
1659
+ var flowId = __anNewOAuthFlowId();
1660
+ __anStartRedirectOAuth(ret, btn, err, flowId, 'Opening Google sign-in redirect from Builder preview');
1653
1661
  return;
1654
1662
  }
1655
1663
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"onboarding-html.js","sourceRoot":"","sources":["../../src/server/onboarding-html.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * First-run onboarding page for agent-native apps.\n *\n * Shown when Better Auth is active and the user isn't signed in.\n * Provides a path to create or sign into an account from day one.\n *\n * After first account exists, this page acts as a normal login page.\n */\n\nimport { getPublicOAuthOrigin } from \"./oauth-public-origin.js\";\nimport {\n resolveGoogleAuthMode,\n type GoogleAuthMode,\n} from \"./google-auth-mode.js\";\nimport { getWorkspaceGatewayReturnOrigin } from \"./oauth-return-url.js\";\nimport { identitySsoLoginButtonHtml } from \"./identity-sso-store.js\";\n\nfunction hasGoogleOAuth(): boolean {\n return !!(process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET);\n}\n\nfunction getConnectionLabel(): string {\n const url = process.env.DATABASE_URL || \"\";\n if (!url) return \"SQLite (local file)\";\n if (url.startsWith(\"postgres://\") || url.startsWith(\"postgresql://\")) {\n if (url.includes(\"neon.tech\")) return \"Neon Postgres\";\n if (url.includes(\"supabase\")) return \"Supabase Postgres\";\n return \"Postgres\";\n }\n if (url.startsWith(\"file:\")) return \"SQLite (local file)\";\n if (url.startsWith(\"libsql://\") || url.includes(\"turso.io\")) return \"Turso\";\n return \"SQL database\";\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\nfunction withAppBasePath(path: string): string {\n const cleanPath = path.startsWith(\"/\") ? path : `/${path}`;\n const basePath = normalizeAppBasePath(\n process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH,\n );\n return `${basePath}${cleanPath}`;\n}\n\nexport interface OnboardingHtmlOptions {\n /**\n * Hide email/password forms and show ONLY the Google sign-in button.\n * Useful for templates (mail, calendar) where Google is required anyway.\n * If Google OAuth env vars are not configured, an error message is shown.\n */\n googleOnly?: boolean;\n /**\n * Product marketing content shown alongside the sign-in form.\n * When provided, the page uses a split layout: marketing on the left,\n * sign-in form on the right (stacked on mobile).\n */\n marketing?: {\n appName: string;\n tagline: string;\n description?: string;\n features?: string[];\n runLocalCommand?: string;\n };\n /**\n * Optional preflight copy shown before redirecting through Google sign-in.\n * Use this when a hosted app needs to warn about provider-specific consent\n * screens while leaving self-hosted deployments untouched.\n */\n googleSignInNotice?: {\n host?: string;\n title: string;\n body: string | string[];\n continueLabel?: string;\n cancelLabel?: string;\n };\n /**\n * Google sign-in flow: `'popup'`, `'redirect'`, or `'auto'` (default).\n * Falls back to `GOOGLE_AUTH_MODE` env var, then `'auto'`. Builder web\n * iframes use popup; Builder desktop preview/editor surfaces use redirect.\n */\n googleAuthMode?: GoogleAuthMode;\n}\n\nexport function getOnboardingHtml(opts: OnboardingHtmlOptions = {}): string {\n const showGoogle = hasGoogleOAuth();\n const googleOnly = !!opts.googleOnly;\n const appBasePath = normalizeAppBasePath(\n process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH,\n );\n const publicOAuthOrigin = getPublicOAuthOrigin();\n const workspaceGatewayReturnOrigin = getWorkspaceGatewayReturnOrigin();\n const googleAuthMode = resolveGoogleAuthMode(opts.googleAuthMode);\n\n const marketing = opts.marketing;\n const hasMarketing = !!marketing;\n const runLocalCommand = marketing?.runLocalCommand?.trim();\n const brandMarkSrc = withAppBasePath(\"/agent-native-icon-dark.svg\");\n const esc = (s: string) =>\n s\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\");\n const googleSignInNotice = opts.googleSignInNotice;\n const googleNoticeBodyHtml = googleSignInNotice\n ? (Array.isArray(googleSignInNotice.body)\n ? googleSignInNotice.body\n : [googleSignInNotice.body]\n )\n .filter((body) => body.trim().length > 0)\n .map(\n (body, index) =>\n `<p class=\"google-preflight-copy\"${index === 0 ? ' id=\"google-preflight-copy\"' : \"\"}>${esc(body)}</p>`,\n )\n .join(\"\\n\")\n : \"\";\n const googleNoticeHtml =\n showGoogle && googleSignInNotice\n ? `\n <div\n class=\"google-preflight\"\n id=\"google-preflight\"\n data-host=\"${esc(googleSignInNotice.host ?? \"\")}\"\n role=\"dialog\"\n aria-labelledby=\"google-preflight-title\"\n aria-describedby=\"google-preflight-copy\"\n >\n <p class=\"google-preflight-title\" id=\"google-preflight-title\">${esc(googleSignInNotice.title)}</p>\n${googleNoticeBodyHtml}\n <div class=\"google-preflight-actions\">\n <button type=\"button\" class=\"btn-primary\" id=\"google-preflight-continue\" onclick=\"__anAcceptGoogleNotice()\">${esc(googleSignInNotice.continueLabel ?? \"Continue\")}</button>\n <button type=\"button\" class=\"btn-secondary\" onclick=\"__anHideGoogleNotice()\">${esc(googleSignInNotice.cancelLabel ?? \"Cancel\")}</button>\n </div>\n </div>`\n : \"\";\n\n const marketingStyles = hasMarketing\n ? `\n body.has-marketing { padding: 0; position: relative; overflow-x: hidden; }\n #starfield {\n position: fixed;\n inset: 0;\n width: 100%;\n height: 100%;\n opacity: 0.35;\n pointer-events: none;\n z-index: 0;\n }\n @media (prefers-reduced-motion: reduce) {\n #starfield { opacity: 0.18; }\n }\n .split {\n position: relative;\n z-index: 1;\n display: flex;\n min-height: 100vh;\n width: 100%;\n max-width: 1100px;\n margin: 0 auto;\n }\n .marketing-panel {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n padding: 3rem 3.5rem;\n }\n .marketing-content { max-width: 480px; }\n .app-name {\n display: flex;\n align-items: center;\n gap: 0.625rem;\n font-size: 2rem;\n font-weight: 700;\n color: #fff;\n margin-bottom: 0.625rem;\n letter-spacing: -0.02em;\n }\n .app-name img.brand-mark {\n height: 2.21375rem;\n width: auto;\n display: block;\n flex-shrink: 0;\n }\n .app-tagline {\n font-size: 1.25rem;\n color: #a1a1aa;\n line-height: 1.6;\n margin-bottom: 2rem;\n }\n .app-desc {\n font-size: 1rem;\n color: #71717a;\n line-height: 1.6;\n margin-bottom: 2rem;\n }\n .feature-list {\n list-style: none;\n display: flex;\n flex-direction: column;\n gap: 0.875rem;\n }\n .feature-list li {\n display: flex;\n align-items: flex-start;\n gap: 0.625rem;\n font-size: 1rem;\n color: #a1a1aa;\n line-height: 1.5;\n }\n .feature-list li::before {\n content: '';\n flex-shrink: 0;\n width: 8px;\n height: 8px;\n margin-top: 6px;\n border-radius: 50%;\n background: #3f3f46;\n border: 1px solid #52525b;\n }\n .oss-link {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n font-size: 0.8125rem;\n color: #71717a;\n text-decoration: none;\n }\n .oss-link:hover { color: #a1a1aa; }\n .oss-link svg { width: 15px; height: 15px; flex-shrink: 0; }\n .marketing-actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.75rem;\n margin-top: 2rem;\n }\n .run-local-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-height: 2.25rem;\n padding: 0.5rem 0.875rem;\n background: rgba(255,255,255,0.08);\n color: #fff;\n border: 1px solid rgba(255,255,255,0.14);\n border-radius: 8px;\n font-size: 0.8125rem;\n font-weight: 500;\n cursor: pointer;\n }\n .run-local-button:hover {\n background: rgba(255,255,255,0.12);\n border-color: rgba(255,255,255,0.24);\n }\n .run-local-panel {\n max-width: 480px;\n margin-top: 0.75rem;\n padding: 0.75rem;\n background: rgba(20,20,20,0.86);\n border: 1px solid rgba(255,255,255,0.1);\n border-radius: 10px;\n box-shadow: 0 14px 36px rgba(0,0,0,0.28);\n }\n .run-local-panel[hidden] { display: none; }\n .run-local-panel code {\n display: block;\n overflow-x: auto;\n padding-bottom: 0.125rem;\n color: #e5e5e5;\n font-family: \"SFMono-Regular\", Consolas, \"Liberation Mono\", monospace;\n font-size: 0.75rem;\n line-height: 1.5;\n white-space: nowrap;\n }\n .copy-run-local {\n margin-top: 0.625rem;\n padding: 0.375rem 0.625rem;\n background: transparent;\n color: #a1a1aa;\n border: 1px solid rgba(255,255,255,0.12);\n border-radius: 6px;\n font-size: 0.75rem;\n cursor: pointer;\n }\n .copy-run-local:hover { color: #fff; border-color: rgba(255,255,255,0.22); }\n .form-panel {\n flex: 0 0 440px;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 2rem;\n }\n .form-panel .card { max-width: 400px; }\n .form-panel .local-note { max-width: 400px; }\n @media (max-width: 900px) {\n .split { flex-direction: column; min-height: auto; }\n .marketing-panel { padding: 2rem 1.5rem 1.5rem; }\n .app-name { font-size: 1.375rem; }\n .app-name img.brand-mark { height: 1.58125rem; }\n .app-tagline { font-size: 1rem; margin-bottom: 1rem; }\n .app-desc { margin-bottom: 1rem; }\n .feature-list { gap: 0.5rem; }\n .form-panel { flex: none; padding: 1.5rem 1rem; }\n }\n`\n : \"\";\n\n const marketingPanelHtml = hasMarketing\n ? `<canvas id=\"starfield\"></canvas>\n<div class=\"split\">\n <div class=\"marketing-panel\">\n <div class=\"marketing-content\">\n <h2 class=\"app-name\">\n <img class=\"brand-mark\" src=\"${esc(brandMarkSrc)}\" alt=\"\" aria-hidden=\"true\" />\n <span>${esc(marketing!.appName)}</span>\n </h2>\n <p class=\"app-tagline\">${esc(marketing!.tagline)}</p>\n${marketing!.description ? ` <p class=\"app-desc\">${esc(marketing!.description)}</p>\\n` : \"\"}${\n marketing!.features?.length\n ? ` <ul class=\"feature-list\">\\n${marketing!.features.map((f) => ` <li>${esc(f)}</li>`).join(\"\\n\")}\\n </ul>\\n`\n : \"\"\n } <div class=\"marketing-actions\">\n${runLocalCommand ? ` <button type=\"button\" class=\"run-local-button\" id=\"run-local-button\" aria-expanded=\"false\" aria-controls=\"run-local-panel\" onclick=\"__anToggleRunLocalCommand()\">Run Locally</button>\\n` : \"\"} <a class=\"oss-link\" href=\"https://github.com/BuilderIO/agent-native\" target=\"_blank\" rel=\"noreferrer\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 19c-4.3 1.4-4.3-2.5-6-3m12 5v-3.5c0-1 .1-1.4-.5-2 2.8-.3 5.5-1.4 5.5-6a4.6 4.6 0 00-1.3-3.2 4.2 4.2 0 00-.1-3.2s-1.1-.3-3.5 1.3a12.3 12.3 0 00-6.2 0C6.5 2.8 5.4 3.1 5.4 3.1a4.2 4.2 0 00-.1 3.2A4.6 4.6 0 004 9.5c0 4.6 2.7 5.7 5.5 6-.6.6-.6 1.2-.5 2V21\"/></svg>\n Open source\n </a>\n </div>\n${\n runLocalCommand\n ? ` <div class=\"run-local-panel\" id=\"run-local-panel\" hidden data-command=\"${esc(runLocalCommand)}\">\n <code>${esc(runLocalCommand)}</code>\n <button type=\"button\" class=\"copy-run-local\" id=\"copy-run-local\" onclick=\"__anCopyRunLocalCommand()\">Copy command</button>\n </div>\\n`\n : \"\"\n}\n </div>\n </div>\n <div class=\"form-panel\">`\n : \"\";\n\n const marketingCloseHtml = hasMarketing ? `\\n </div>\\n</div>` : \"\";\n\n const starfieldScript = hasMarketing\n ? `\n (function initStarfield() {\n var canvas = document.getElementById('starfield');\n if (!canvas) return;\n var gl = canvas.getContext('webgl', { alpha: false, antialias: false });\n if (!gl) return;\n\n var vs = gl.createShader(gl.VERTEX_SHADER);\n gl.shaderSource(vs, 'attribute vec2 position;void main(){gl_Position=vec4(position,0.0,1.0);}');\n gl.compileShader(vs);\n\n var fs = gl.createShader(gl.FRAGMENT_SHADER);\n gl.shaderSource(fs, [\n 'precision highp float;',\n 'uniform float iTime;uniform vec2 iResolution;',\n '#define S(a,b,t) smoothstep(a,b,t)',\n '#define NUM_LAYERS 4.',\n 'float N21(vec2 p){vec3 a=fract(vec3(p.xyx)*vec3(213.897,653.453,253.098));a+=dot(a,a.yzx+79.76);return fract((a.x+a.y)*a.z);}',\n 'vec2 GetPos(vec2 id,vec2 offs,float t){float n=N21(id+offs);float n1=fract(n*10.);float n2=fract(n*100.);float a=t+n;return offs+vec2(sin(a*n1),cos(a*n2))*.4;}',\n 'float df_line(vec2 a,vec2 b,vec2 p){vec2 pa=p-a,ba=b-a;float h=clamp(dot(pa,ba)/dot(ba,ba),0.,1.);return length(pa-ba*h);}',\n 'float line(vec2 a,vec2 b,vec2 uv){float r1=.025;float r2=.006;float d=df_line(a,b,uv);float d2=length(a-b);float fade=S(1.5,.5,d2);fade+=S(.05,.02,abs(d2-.75));return S(r1,r2,d)*fade;}',\n 'float NetLayer(vec2 st,float n,float t){',\n ' vec2 id=floor(st)+n;st=fract(st)-.5;',\n ' vec2 p0=GetPos(id,vec2(-1,-1),t);vec2 p1=GetPos(id,vec2(0,-1),t);vec2 p2=GetPos(id,vec2(1,-1),t);',\n ' vec2 p3=GetPos(id,vec2(-1,0),t);vec2 p4=GetPos(id,vec2(0,0),t);vec2 p5=GetPos(id,vec2(1,0),t);',\n ' vec2 p6=GetPos(id,vec2(-1,1),t);vec2 p7=GetPos(id,vec2(0,1),t);vec2 p8=GetPos(id,vec2(1,1),t);',\n ' float m=0.;float sparkle=0.;float d;float s;float pulse;',\n ' m+=line(p4,p0,st);d=length(st-p0);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p0.x)+fract(p0.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',\n ' m+=line(p4,p1,st);d=length(st-p1);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p1.x)+fract(p1.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',\n ' m+=line(p4,p2,st);d=length(st-p2);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p2.x)+fract(p2.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',\n ' m+=line(p4,p3,st);d=length(st-p3);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p3.x)+fract(p3.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',\n ' m+=line(p4,p4,st);d=length(st-p4);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p4.x)+fract(p4.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',\n ' m+=line(p4,p5,st);d=length(st-p5);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p5.x)+fract(p5.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',\n ' m+=line(p4,p6,st);d=length(st-p6);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p6.x)+fract(p6.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',\n ' m+=line(p4,p7,st);d=length(st-p7);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p7.x)+fract(p7.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',\n ' m+=line(p4,p8,st);d=length(st-p8);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p8.x)+fract(p8.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',\n ' m+=line(p1,p3,st);m+=line(p1,p5,st);m+=line(p7,p5,st);m+=line(p7,p3,st);',\n ' float sPhase=(sin(t+n)+sin(t*.1))*.25+.5;sPhase+=pow(sin(t*.1)*.5+.5,50.)*5.;m+=sparkle*sPhase;',\n ' return m;',\n '}',\n 'void mainImage(out vec4 fragColor,in vec2 fragCoord){',\n ' vec2 uv=(fragCoord-iResolution.xy*.5)/iResolution.y;',\n ' float t=iTime*.03;float s=sin(t);float c=cos(t);mat2 rot=mat2(c,-s,s,c);vec2 st=uv*rot;',\n ' float m=0.;',\n ' for(float i=0.;i<1.;i+=1./NUM_LAYERS){float z=fract(t+i);float size=mix(15.,1.,z);float fade=S(0.,.6,z)*S(1.,.8,z);m+=fade*NetLayer(st*size,i,iTime*0.3);}',\n ' vec3 col=vec3(0.35)*m;col*=1.-dot(uv,uv);',\n ' float tt=min(iTime,5.0);col*=S(0.,20.,tt);',\n ' col=clamp(col,0.,1.);fragColor=vec4(col,1.);',\n '}',\n 'void main(){mainImage(gl_FragColor,gl_FragCoord.xy);}'\n ].join('\\\\n'));\n gl.compileShader(fs);\n\n var prog = gl.createProgram();\n gl.attachShader(prog, vs);\n gl.attachShader(prog, fs);\n gl.linkProgram(prog);\n gl.useProgram(prog);\n\n var buf = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, buf);\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]), gl.STATIC_DRAW);\n var pos = gl.getAttribLocation(prog, 'position');\n gl.enableVertexAttribArray(pos);\n gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 0, 0);\n\n var uTime = gl.getUniformLocation(prog, 'iTime');\n var uRes = gl.getUniformLocation(prog, 'iResolution');\n var reducedMotionQuery = window.matchMedia ? window.matchMedia('(prefers-reduced-motion: reduce)') : null;\n var reducedMotion = reducedMotionQuery ? reducedMotionQuery.matches : false;\n\n function resize() {\n var w = window.innerWidth, h = window.innerHeight;\n var dpr = Math.min(window.devicePixelRatio, 1.5);\n canvas.width = w * dpr; canvas.height = h * dpr;\n gl.viewport(0, 0, canvas.width, canvas.height);\n }\n resize();\n window.addEventListener('resize', resize);\n\n var start = performance.now(), last = 0, raf = 0, reducedMotionStaticTime = 20;\n function draw(timeSeconds) {\n gl.uniform1f(uTime, timeSeconds);\n gl.uniform2f(uRes, canvas.width, canvas.height);\n gl.drawArrays(gl.TRIANGLES, 0, 6);\n }\n function render(now) {\n if (reducedMotion) {\n raf = 0;\n return;\n }\n raf = requestAnimationFrame(render);\n if (now - last < 33) return;\n last = now;\n draw((now - start) * 0.001);\n }\n function startAnimation() {\n if (!raf) raf = requestAnimationFrame(render);\n }\n function stopAnimation() {\n if (raf) {\n cancelAnimationFrame(raf);\n raf = 0;\n }\n }\n function onReducedMotionChange() {\n reducedMotion = reducedMotionQuery ? reducedMotionQuery.matches : false;\n if (reducedMotion) {\n stopAnimation();\n last = 0;\n draw(reducedMotionStaticTime);\n } else {\n startAnimation();\n }\n }\n draw(reducedMotion ? reducedMotionStaticTime : 0);\n if (reducedMotionQuery) {\n if (reducedMotionQuery.addEventListener) {\n reducedMotionQuery.addEventListener('change', onReducedMotionChange);\n } else {\n reducedMotionQuery.addListener(onReducedMotionChange);\n }\n }\n if (!reducedMotion) startAnimation();\n })();`\n : \"\";\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\">\n<title>${hasMarketing ? esc(marketing!.appName) + \" — Sign in\" : \"Welcome\"}</title>\n<link rel=\"icon\" type=\"image/svg+xml\" href=\"${withAppBasePath(\"/favicon.svg\")}\">\n<link rel=\"apple-touch-icon\" href=\"${withAppBasePath(\"/icon-180.svg\")}\">\n${\n hasMarketing\n ? `<meta name=\"description\" content=\"${esc(marketing!.tagline)}\">\n<meta property=\"og:title\" content=\"${esc(marketing!.appName)}\">\n<meta property=\"og:description\" content=\"${esc(marketing!.tagline)}\">`\n : \"\"\n}\n<style>\n *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n background: #0a0a0a;\n color: #e5e5e5;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n padding: 1rem;\n }\n .card {\n width: 100%;\n max-width: 400px;\n padding: 2rem;\n background: #141414;\n border: 1px solid rgba(255,255,255,0.08);\n border-radius: 12px;\n }\n h1 { font-size: 1.25rem; font-weight: 600; margin-bottom: 0.25rem; color: #fff; }\n .subtitle { font-size: 0.8125rem; color: #888; margin-bottom: 1.5rem; }\n .tabs {\n display: inline-flex;\n width: 100%;\n padding: 4px;\n margin-bottom: 1.5rem;\n background: rgba(255,255,255,0.06);\n border-radius: 8px;\n }\n .tab {\n flex: 1;\n padding: 0.5rem 0.75rem;\n background: none;\n border: none;\n color: #888;\n font-size: 0.8125rem;\n font-weight: 500;\n cursor: pointer;\n border-radius: 6px;\n }\n .tab.active {\n background: #1e1e1e;\n color: #fff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.3);\n }\n .tab:hover:not(.active) { color: #bbb; }\n .form { display: none; }\n .form.active { display: block; }\n .card.verifying .tabs,\n .card.verifying #google-btn,\n .card.verifying #google-err,\n .card.verifying #auth-divider,\n .card.verifying #upgrade-note {\n display: none;\n }\n label { display: block; font-size: 0.8125rem; color: #888; margin-bottom: 0.375rem; }\n input {\n width: 100%;\n padding: 0.5rem 0.75rem;\n background: transparent;\n border: 1px solid rgba(255,255,255,0.12);\n border-radius: 6px;\n color: #e5e5e5;\n font-size: 0.875rem;\n outline: none;\n margin-bottom: 0.875rem;\n }\n input:focus { border-color: rgba(255,255,255,0.3); box-shadow: 0 0 0 1px rgba(255,255,255,0.1); }\n input::placeholder { color: #555; }\n button[type=\"submit\"], .btn-primary {\n width: 100%;\n margin-top: 0.25rem;\n padding: 0.5rem;\n background: #fff;\n color: #000;\n border: none;\n border-radius: 6px;\n font-size: 0.875rem;\n font-weight: 500;\n cursor: pointer;\n }\n button[type=\"submit\"]:hover, .btn-primary:hover { background: #e5e5e5; }\n button[type=\"submit\"]:disabled { opacity: 0.5; cursor: not-allowed; }\n .btn-secondary {\n width: 100%;\n margin-top: 0.75rem;\n padding: 0.5rem;\n background: transparent;\n color: #888;\n border: 1px solid rgba(255,255,255,0.1);\n border-radius: 6px;\n font-size: 0.8125rem;\n cursor: pointer;\n }\n .btn-secondary:hover { color: #bbb; border-color: rgba(255,255,255,0.2); }\n .msg { margin-top: 0.75rem; font-size: 0.8125rem; display: none; }\n .msg.error { color: #f87171; }\n .msg.success { color: #4ade80; }\n .msg.show { display: block; }\n .step-progress {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 0.5rem;\n margin-bottom: 1.25rem;\n }\n .progress-step {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 0.375rem;\n color: #666;\n font-size: 0.6875rem;\n line-height: 1.2;\n text-align: center;\n }\n .progress-step::before {\n content: '';\n position: absolute;\n top: 11px;\n left: calc(-50% + 16px);\n width: calc(100% - 32px);\n height: 1px;\n background: rgba(255,255,255,0.1);\n }\n .progress-step:first-child::before { display: none; }\n .progress-step span {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n border-radius: 999px;\n border: 1px solid rgba(255,255,255,0.14);\n background: #151515;\n color: #777;\n font-size: 0.6875rem;\n font-weight: 600;\n }\n .progress-step strong { font-weight: 500; }\n .progress-step.complete,\n .progress-step.current { color: #e5e5e5; }\n .progress-step.complete span {\n background: #d9f99d;\n border-color: #d9f99d;\n color: #111;\n }\n .progress-step.current span {\n background: #fff;\n border-color: #fff;\n color: #000;\n box-shadow: 0 0 0 4px rgba(255,255,255,0.08);\n }\n .verification-panel {\n padding: 1rem;\n margin-bottom: 0.875rem;\n background: rgba(255,255,255,0.04);\n border: 1px solid rgba(255,255,255,0.08);\n border-radius: 8px;\n }\n .verification-kicker {\n margin-bottom: 0.5rem;\n color: #bef264;\n font-size: 0.75rem;\n font-weight: 500;\n }\n .verification-copy {\n color: #d4d4d8;\n font-size: 0.875rem;\n line-height: 1.55;\n }\n .verification-copy strong {\n color: #fff;\n font-weight: 600;\n word-break: break-word;\n }\n .verification-note {\n margin-top: 0.75rem;\n color: #71717a;\n font-size: 0.75rem;\n line-height: 1.45;\n }\n .inline-actions {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.75rem;\n margin-top: 0.75rem;\n }\n .link-button {\n padding: 0.25rem 0;\n background: none;\n border: none;\n color: #888;\n cursor: pointer;\n font-size: 0.75rem;\n text-decoration: underline;\n text-underline-offset: 2px;\n }\n .link-button:hover { color: #bbb; }\n .link-button:disabled { cursor: wait; opacity: 0.5; }\n .divider {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n margin: 1.25rem 0;\n font-size: 0.75rem;\n color: #555;\n }\n .divider::before, .divider::after {\n content: '';\n flex: 1;\n height: 1px;\n background: rgba(255,255,255,0.08);\n }\n .upgrade-note {\n margin-bottom: 1rem;\n padding: 0.75rem;\n border: 1px solid rgba(255,255,255,0.08);\n border-radius: 8px;\n background: rgba(255,255,255,0.03);\n font-size: 0.75rem;\n line-height: 1.5;\n color: #a1a1aa;\n display: none;\n }\n .upgrade-note.show { display: block; }\n .btn-google {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.625rem;\n padding: 0.5rem;\n background: #fff;\n color: #000;\n border: none;\n border-radius: 6px;\n font-size: 0.875rem;\n font-weight: 500;\n cursor: pointer;\n }\n .btn-google:hover { background: #e5e5e5; }\n .btn-google:disabled { opacity: 0.5; cursor: wait; }\n .btn-google svg { width: 18px; height: 18px; flex-shrink: 0; }\n .google-error { margin-top: 0.5rem; font-size: 0.8125rem; color: #f87171; display: none; }\n .google-error.show { display: block; }\n .google-debug {\n display: none;\n margin-top: 0.5rem;\n font-size: 0.6875rem;\n line-height: 1.45;\n color: #777;\n word-break: break-word;\n }\n .google-debug.show { display: block; }\n .google-preflight {\n display: none;\n margin-top: 0.75rem;\n padding: 0.875rem;\n border: 1px solid rgba(255,255,255,0.12);\n border-radius: 10px;\n background: rgba(255,255,255,0.05);\n box-shadow: 0 14px 36px rgba(0,0,0,0.28);\n }\n .google-preflight.show { display: block; }\n .google-preflight-title {\n margin-bottom: 0.375rem;\n color: #fff;\n font-size: 0.8125rem;\n font-weight: 600;\n }\n .google-preflight-copy {\n color: #b4b4b8;\n font-size: 0.75rem;\n line-height: 1.55;\n }\n .google-preflight-copy + .google-preflight-copy { margin-top: 0.5rem; }\n .google-preflight-actions {\n display: flex;\n gap: 0.5rem;\n margin-top: 0.875rem;\n }\n .google-preflight-actions .btn-primary,\n .google-preflight-actions .btn-secondary {\n flex: 1;\n width: auto;\n margin-top: 0;\n }\n .local-note {\n display: none;\n max-width: 400px;\n width: 100%;\n margin-top: 1rem;\n padding: 0.625rem 0.875rem;\n font-size: 0.6875rem;\n line-height: 1.5;\n color: #666;\n border: 1px dashed rgba(255,255,255,0.08);\n border-radius: 8px;\n text-align: center;\n }\n .local-note.show { display: block; }\n .local-note strong { color: #999; font-weight: 500; }\n .local-note a { color: #888; text-decoration: none; }\n .local-note a:hover { color: #bbb; }\n${marketingStyles}\n</style>\n</head>\n<body${hasMarketing ? ' class=\"has-marketing\"' : \"\"}>\n${marketingPanelHtml}\n<div class=\"card\">\n <h1 id=\"heading\">${googleOnly ? \"Sign in\" : \"Welcome\"}</h1>\n <p class=\"subtitle\" id=\"subtitle\">${googleOnly ? \"Use your workspace Google account to continue\" : \"Create an account to get started\"}</p>\n <p\n class=\"upgrade-note\"\n id=\"upgrade-note\"\n data-upgrade-copy=\"Continue signing in to attach this app to your account and migrate local data.\"\n ></p>\n${identitySsoLoginButtonHtml()}\n${\n showGoogle\n ? `\n <button class=\"btn-google\" id=\"google-btn\" onclick=\"signInWithGoogle()\">\n <svg viewBox=\"0 0 24 24\"><path fill=\"#4285F4\" d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 0 1-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z\"/><path fill=\"#34A853\" d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"/><path fill=\"#FBBC05\" d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"/><path fill=\"#EA4335\" d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"/></svg>\n Sign in with Google\n </button>\n <p class=\"google-error\" id=\"google-err\"></p>\n <p class=\"google-debug\" id=\"google-debug\"></p>\n${googleNoticeHtml}\n${googleOnly ? \"\" : `\\n <div class=\"divider\" id=\"auth-divider\">or</div>\\n`}\n`\n : googleOnly\n ? `\n <p style=\"color:#f87171;font-size:0.875rem;text-align:center;padding:1rem 0\">\n Google sign-in is not configured. Set <code>GOOGLE_CLIENT_ID</code> and\n <code>GOOGLE_CLIENT_SECRET</code> environment variables to enable login.\n </p>\n`\n : \"\"\n}\n${\n googleOnly\n ? \"\"\n : ` <div class=\"tabs\">\n <button class=\"tab\" data-tab=\"signup\">Create account</button>\n <button class=\"tab\" data-tab=\"login\">Sign in</button>\n </div>\n\n <form id=\"signup-form\" class=\"form\">\n <label for=\"s-email\">Email</label>\n <input id=\"s-email\" type=\"email\" autocomplete=\"email\" autofocus placeholder=\"you@example.com\" required />\n <label for=\"s-pass\">Password</label>\n <input id=\"s-pass\" type=\"password\" autocomplete=\"new-password\" placeholder=\"At least 8 characters\" required minlength=\"8\" />\n <label for=\"s-pass2\">Confirm password</label>\n <input id=\"s-pass2\" type=\"password\" autocomplete=\"new-password\" placeholder=\"Confirm password\" required minlength=\"8\" />\n <button type=\"submit\">Create account</button>\n <p class=\"msg\" id=\"s-msg\"></p>\n </form>\n\n <div id=\"verification-step\" class=\"form verification-step\" aria-live=\"polite\">\n <div class=\"step-progress\" aria-label=\"Signup progress\">\n <div class=\"progress-step complete\"><span>1</span><strong>Account</strong></div>\n <div class=\"progress-step current\"><span>2</span><strong>Verify</strong></div>\n <div class=\"progress-step\"><span>3</span><strong>Start</strong></div>\n </div>\n <div class=\"verification-panel\">\n <p class=\"verification-kicker\">Verification email sent</p>\n <p class=\"verification-copy\">We sent a secure link to <strong id=\"verify-email\"></strong>. Click it, return here, and this app will finish signing you in automatically.</p>\n <p class=\"verification-note\">You can keep this tab open. If it has not refreshed after you come back, use Continue.</p>\n </div>\n <button type=\"button\" class=\"btn-primary\" id=\"verify-continue\">Continue</button>\n <div class=\"inline-actions\">\n <button type=\"button\" class=\"link-button\" id=\"resend-verification\">Resend email</button>\n <button type=\"button\" class=\"link-button\" id=\"back-to-signup\">Back</button>\n </div>\n <p class=\"msg\" id=\"verify-msg\"></p>\n </div>\n\n <form id=\"login-form\" class=\"form\">\n <label for=\"l-email\">Email</label>\n <input id=\"l-email\" type=\"email\" autocomplete=\"email\" placeholder=\"you@example.com\" required />\n <label for=\"l-pass\">Password</label>\n <input id=\"l-pass\" type=\"password\" autocomplete=\"current-password\" placeholder=\"Enter password\" required />\n <button type=\"submit\">Sign in</button>\n <p class=\"msg error\" id=\"l-msg\"></p>\n <p style=\"margin-top:0.75rem;font-size:0.75rem;text-align:right\">\n <a href=\"#\" id=\"forgot-link\" style=\"color:#888;text-decoration:underline;text-underline-offset:2px\">Forgot password?</a>\n </p>\n </form>\n\n <form id=\"forgot-form\" class=\"form\">\n <label for=\"f-email\">Email</label>\n <input id=\"f-email\" type=\"email\" autocomplete=\"email\" placeholder=\"you@example.com\" required />\n <button type=\"submit\">Send reset link</button>\n <p class=\"msg\" id=\"f-msg\"></p>\n <p style=\"margin-top:0.75rem;font-size:0.75rem;text-align:center\">\n <a href=\"#\" id=\"back-to-login\" style=\"color:#888;text-decoration:underline;text-underline-offset:2px\">Back to sign in</a>\n </p>\n </form>`\n}\n</div>\n<p class=\"local-note\" id=\"local-note\">\n Your account is stored in this app's own DB (<strong>${getConnectionLabel()}</strong>), not a third-party service.\n</p>${marketingCloseHtml}\n<script>\n function __anBasePath() {\n var configured = ${JSON.stringify(appBasePath)};\n if (configured) return configured;\n var marker = '/_agent-native';\n var idx = window.location.pathname.indexOf(marker);\n return idx > 0 ? window.location.pathname.slice(0, idx) : '';\n }\n function __anPath(path) {\n return __anBasePath() + path;\n }\n var __AN_PUBLIC_OAUTH_ORIGIN = ${JSON.stringify(publicOAuthOrigin)};\n var __AN_WORKSPACE_GATEWAY_RETURN_ORIGIN = ${JSON.stringify(workspaceGatewayReturnOrigin)};\n var __AN_GOOGLE_AUTH_MODE = ${JSON.stringify(googleAuthMode)};\n function __anConfiguredOAuthOrigin() {\n if (!__AN_PUBLIC_OAUTH_ORIGIN) return '';\n try {\n var origin = new URL(__AN_PUBLIC_OAUTH_ORIGIN).origin;\n return origin && origin !== window.location.origin ? origin : '';\n } catch(e) {\n return '';\n }\n }\n function __anAuthPath(path) {\n var origin = __anIsBuilderPreview() ? __anConfiguredOAuthOrigin() : '';\n return origin ? origin + path : __anPath(path);\n }\n function __anGoogleAuthUrlPath() {\n return __anIsBuilderPreview()\n ? __anAuthPath('/_agent-native/google/auth-url')\n : __anPath('/_agent-native/google/auth-url');\n }\n function __anBuilderPreviewReturnOrigin() {\n var candidates = [window.location.href, document.referrer || ''];\n try {\n if (window.location.ancestorOrigins) {\n for (var j = 0; j < window.location.ancestorOrigins.length; j++) {\n candidates.push(window.location.ancestorOrigins[j]);\n }\n }\n } catch(e) {}\n for (var i = 0; i < candidates.length; i++) {\n try {\n var url = new URL(candidates[i]);\n var host = url.hostname.toLowerCase();\n var isPreviewHost =\n host === 'builderio.xyz' || host.slice(-14) === '.builderio.xyz' ||\n host === 'builderio.dev' || host.slice(-14) === '.builderio.dev' ||\n host === 'builder.codes' || host.slice(-14) === '.builder.codes' ||\n host === 'builder.my' || host.slice(-11) === '.builder.my';\n if (url.protocol === 'https:' && isPreviewHost) return url.origin;\n } catch(e) {}\n }\n return '';\n }\n function __anWorkspaceGatewayReturnOrigin() {\n var previewOrigin = __anBuilderPreviewReturnOrigin();\n if (previewOrigin) return previewOrigin;\n if (__AN_WORKSPACE_GATEWAY_RETURN_ORIGIN) return __AN_WORKSPACE_GATEWAY_RETURN_ORIGIN;\n return __anIsBuilderDesktop() ? 'http://127.0.0.1:8080' : '';\n }\n function __anNormalizeWorkspaceReturnPath(ret) {\n try {\n var url = new URL(ret || '/', window.location.origin);\n var path = url.pathname || '/';\n if (path === '/dispatch/dispatch') {\n path = '/dispatch';\n } else if (path.indexOf('/dispatch/') === 0) {\n var rest = path.slice('/dispatch/'.length);\n var first = rest.split('/')[0];\n var dispatchRoutes = {\n overview: true, apps: true, metrics: true, vault: true,\n integrations: true, messaging: true, workspace: true,\n agents: true, destinations: true, identities: true,\n approvals: true, audit: true, team: true, 'thread-debug': true,\n 'new-app': true\n };\n if (first === 'dispatch') {\n path = '/dispatch' + rest.slice(first.length);\n } else if (first && !dispatchRoutes[first]) {\n path = '/' + rest;\n }\n }\n return path + url.search + url.hash;\n } catch(e) {\n return ret || '/';\n }\n }\n function __anOAuthReturnTarget(ret) {\n var path = __anNormalizeWorkspaceReturnPath(ret);\n var origin = __anWorkspaceGatewayReturnOrigin();\n return origin ? origin + path : path;\n }\n function __anSessionBridgeUrl(ret, sessionToken) {\n try {\n var url = new URL(ret || window.location.pathname + window.location.search, window.location.origin);\n url.searchParams.set('_session', sessionToken);\n return url.pathname + url.search + url.hash;\n } catch(e) {\n var sep = (ret || '/').indexOf('?') === -1 ? '?' : '&';\n return (ret || '/') + sep + '_session=' + encodeURIComponent(sessionToken);\n }\n }\n function __anFinishOAuthExchange(ret, flowId, sessionToken) {\n if (__anIsBuilderPreview()) {\n if (sessionToken) {\n __anSetOAuthDebug('OAuth exchange redeemed; applying session bridge to embedded app', flowId);\n window.location.replace(__anSessionBridgeUrl(ret, sessionToken));\n return;\n }\n __anSetOAuthDebug('OAuth exchange redeemed; reloading the embedded app', flowId);\n window.location.reload();\n return;\n }\n __anSetOAuthDebug('OAuth exchange redeemed; returning to the app', flowId);\n window.location.href = ret || '/';\n }\n function __anGetReturnPath() {\n try {\n var inner = new URLSearchParams(window.location.search).get('return');\n if (inner) return inner;\n } catch(e) {}\n return window.location.pathname + window.location.search;\n }\n var __anBuilderPreviewSeen = false;\n function __anRememberBuilderPreview() {\n __anBuilderPreviewSeen = true;\n try { sessionStorage.setItem('__an_builder_preview_seen', '1'); } catch(e) {}\n }\n function __anHasBuilderPreviewSignal() {\n try {\n var params = new URLSearchParams(window.location.search);\n if (params.has('builder.preview') || params.has('builder.frameEditing') || params.has('__builder_editing__')) return true;\n } catch(e) {}\n return false;\n }\n function __anIsBuilderPreview() {\n if (__anBuilderPreviewSeen) return true;\n if (__anHasBuilderPreviewSignal()) {\n __anRememberBuilderPreview();\n return true;\n }\n try {\n if (sessionStorage.getItem('__an_builder_preview_seen') === '1') {\n __anBuilderPreviewSeen = true;\n return true;\n }\n } catch(e) {}\n try {\n var ref = document.referrer || '';\n var fromBuilder = ref.indexOf('builder.io') !== -1 || ref.indexOf('builder.my') !== -1 || ref.indexOf('builderio.xyz') !== -1 || ref.indexOf('builderio.dev') !== -1 || ref.indexOf('builder.codes') !== -1;\n if (fromBuilder) __anRememberBuilderPreview();\n return fromBuilder;\n } catch(e) {\n return false;\n }\n }\n __anIsBuilderPreview();\n function __anIsBuilderDesktop() {\n try {\n var ua = navigator.userAgent || '';\n return ua.indexOf('Electron') !== -1 && ua.indexOf('AgentNativeDesktop') === -1;\n } catch(e) {\n return false;\n }\n }\n function __anIsAgentNativeDesktop() {\n try {\n return (navigator.userAgent || '').indexOf('AgentNativeDesktop') !== -1;\n } catch(e) {\n return false;\n }\n }\n function __anIsInFrame() {\n try {\n return window.self !== window.top;\n } catch(e) {\n return true;\n }\n }\n function __anIsElectron() {\n try {\n return (navigator.userAgent || '').indexOf('Electron') !== -1;\n } catch(e) {\n return false;\n }\n }\n function __anResolveAuthFlow() {\n if (__anIsBuilderPreview()) return __anIsInFrame() ? 'popup' : 'redirect';\n // Per-session override for ad-hoc testing outside Builder: append\n // ?authMode=popup or ?authMode=redirect to the sign-in URL.\n try {\n var qp = new URLSearchParams(window.location.search).get('authMode');\n if (qp === 'popup' || qp === 'redirect') return qp;\n } catch(e) {}\n var mode = __AN_GOOGLE_AUTH_MODE || 'auto';\n if (mode === 'popup') return 'popup';\n if (mode === 'redirect') return 'redirect';\n return __anIsAgentNativeDesktop() ? 'redirect' : 'popup';\n }\n var __anOAuthPollTimer = null;\n var __anOAuthPollCount = 0;\n function __anNewOAuthFlowId() {\n try {\n if (window.crypto && typeof window.crypto.randomUUID === 'function') {\n return window.crypto.randomUUID();\n }\n } catch(e) {}\n return 'builder-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2);\n }\n function __anFlowDebugId(flowId) {\n return flowId ? String(flowId).slice(-10) : '';\n }\n function __anSetOAuthDebug(message, flowId) {\n var text = message + (flowId ? ' (flow ' + __anFlowDebugId(flowId) + ')' : '');\n try {\n console.info('[agent-native][google-oauth] ' + text);\n } catch(e) {}\n // Only surface the debug overlay when explicitly opted in via #oauth-debug\n // hash or ?oauth_debug=1 query — otherwise it leaks raw flow IDs and\n // diagnostic strings into the user-facing sign-in screen.\n var showDebugOverlay = false;\n try {\n var loc = window.location || {};\n showDebugOverlay =\n (typeof loc.hash === 'string' && loc.hash.indexOf('oauth-debug') !== -1) ||\n (typeof loc.search === 'string' && loc.search.indexOf('oauth_debug=1') !== -1);\n } catch(e) {}\n var debug = document.getElementById('google-debug');\n if (debug) {\n debug.textContent = text;\n if (showDebugOverlay) debug.classList.add('show');\n }\n }\n function __anShowOAuthError(err, btn, message) {\n if (__anOAuthPollTimer) {\n clearInterval(__anOAuthPollTimer);\n __anOAuthPollTimer = null;\n }\n err.textContent = message;\n err.classList.add('show');\n btn.disabled = false;\n }\n function __anStartRedirectOAuth(ret, btn, err, flowId, reason) {\n var params = new URLSearchParams();\n var oauthReturn = __anIsBuilderPreview() ? __anOAuthReturnTarget(ret) : ret;\n if (oauthReturn) params.set('return', oauthReturn);\n params.set('redirect', '1');\n __anSetOAuthDebug(reason || 'Opening Google sign-in redirect', flowId);\n try {\n __anOpenOAuthUrl(__anGoogleAuthUrlPath() + '?' + params.toString());\n } catch(e) {\n __anShowOAuthError(err, btn, 'Could not start Google sign-in redirect' + (flowId ? ' for flow ' + __anFlowDebugId(flowId) : '') + ': ' + (e && e.message ? e.message : 'unknown error'));\n }\n }\n function __anWaitForOAuthExchange(flowId, ret, btn, err) {\n var started = Date.now();\n var timeoutMs = 5 * 60 * 1000;\n __anOAuthPollCount = 0;\n async function check() {\n __anOAuthPollCount++;\n try {\n var res = await fetch(__anPath('/_agent-native/auth/desktop-exchange') + '?flow_id=' + encodeURIComponent(flowId), { credentials: 'include' });\n var data = await res.json().catch(function() { return {}; });\n if (data && (data.email || data.token)) {\n if (__anOAuthPollTimer) clearInterval(__anOAuthPollTimer);\n __anOAuthPollTimer = null;\n __anFinishOAuthExchange(ret, flowId, data.token);\n return;\n }\n if (data && data.error) {\n __anSetOAuthDebug('OAuth exchange returned an error: ' + (data.message || data.error), flowId);\n __anShowOAuthError(err, btn, data.message || data.error);\n return;\n }\n if (data && data.pending && (__anOAuthPollCount === 1 || __anOAuthPollCount % 5 === 0)) {\n __anSetOAuthDebug('Waiting for the Google callback; polling attempt ' + __anOAuthPollCount, flowId);\n }\n } catch(e) {\n if (__anOAuthPollCount === 1 || __anOAuthPollCount % 5 === 0) {\n __anSetOAuthDebug('Could not reach the OAuth exchange endpoint: ' + (e && e.message ? e.message : 'network error'), flowId);\n }\n }\n if (Date.now() - started > timeoutMs) {\n __anShowOAuthError(err, btn, 'Google sign-in did not finish. Flow ' + __anFlowDebugId(flowId) + ' never reached this app. Check the Google OAuth redirect URI and server logs for [agent-native][google-oauth].');\n }\n }\n if (__anOAuthPollTimer) clearInterval(__anOAuthPollTimer);\n __anOAuthPollTimer = setInterval(check, 1000);\n setTimeout(check, 500);\n }\n function __anStartPopupOAuth(ret, btn, err) {\n var flowId = __anNewOAuthFlowId();\n var oauthReturn = __anIsBuilderPreview() ? __anOAuthReturnTarget(ret) : ret;\n var params = new URLSearchParams();\n if (oauthReturn) params.set('return', oauthReturn);\n params.set('desktop', '1');\n params.set('flow_id', flowId);\n params.set('redirect', '1');\n var url = __anGoogleAuthUrlPath() + '?' + params.toString();\n try { sessionStorage.setItem('__an_signin', '1'); } catch(e) {}\n __anSetOAuthDebug('Opening Google sign-in popup', flowId);\n try {\n var popup = window.open('', '_blank', 'width=640,height=760');\n if (!popup) {\n __anStartRedirectOAuth(ret, btn, err, flowId, 'Google popup was blocked; falling back to redirect');\n return;\n }\n try { popup.opener = null; } catch(e) {}\n try {\n popup.location.href = url;\n } catch(e) {\n try { popup.close(); } catch(closeErr) {}\n __anStartRedirectOAuth(ret, btn, err, flowId, 'Could not navigate Google popup; falling back to redirect');\n return;\n }\n __anSetOAuthDebug('Google popup opened; waiting for callback', flowId);\n } catch(e) {\n __anStartRedirectOAuth(ret, btn, err, flowId, 'Could not open Google popup; falling back to redirect');\n return;\n }\n __anWaitForOAuthExchange(flowId, ret, btn, err);\n }\n function __anStartNativeDesktopOAuth(ret, btn, err) {\n var flowId = __anNewOAuthFlowId();\n var params = new URLSearchParams();\n if (ret) params.set('return', ret);\n params.set('desktop', '1');\n params.set('flow_id', flowId);\n params.set('redirect', '1');\n var url = __anGoogleAuthUrlPath() + '?' + params.toString();\n __anSetOAuthDebug('Opening Google sign-in in system browser', flowId);\n __anOpenOAuthUrl(url);\n __anWaitForOAuthExchange(flowId, ret, btn, err);\n }\n function __anOpenOAuthUrl(url) {\n try { sessionStorage.setItem('__an_signin', '1'); } catch(e) {}\n window.location.href = url;\n }\n (function revealLocalNote() {\n var h = location.hostname;\n if (h === 'localhost' || h === '127.0.0.1' || h === '::1' || h.endsWith('.local')) {\n var n = document.getElementById('local-note');\n if (n) n.classList.add('show');\n }\n })();\n (function revealUpgradeNote() {\n var shouldShow = false;\n try {\n var params = new URLSearchParams(location.search);\n shouldShow = params.get('signin') === '1' || params.get('upgrade-from-local') === '1';\n } catch(e) {}\n if (!shouldShow) {\n try { shouldShow = localStorage.getItem('an_migrate_from_local') === '1'; } catch(e) {}\n }\n if (!shouldShow) return;\n var n = document.getElementById('upgrade-note');\n if (!n) return;\n n.textContent = n.getAttribute('data-upgrade-copy') || 'Continue signing in to migrate local data.';\n n.classList.add('show');\n })();\n${\n googleOnly\n ? \"\"\n : ` var TAB_STORAGE_KEY = 'an.onboarding.tab';\n var tabs = document.querySelectorAll('.tab');\n var forms = document.querySelectorAll('.form');\n var subtitles = { signup: 'Create an account to get started', login: 'Sign in to your account' };\n var headings = { signup: 'Welcome', login: 'Welcome back' };\n var pendingSignupEmail = '';\n var pendingSignupPassword = '';\n var verificationCheckInFlight = false;\n function setActiveTab(name, opts) {\n if (name !== 'signup' && name !== 'login') return;\n var form = document.getElementById(name + '-form');\n if (!form) return;\n var card = document.querySelector('.card');\n if (card) card.classList.remove('verifying');\n tabs.forEach(function(x) { x.classList.remove('active'); });\n forms.forEach(function(x) { x.classList.remove('active'); });\n var btn = document.querySelector('.tab[data-tab=\"' + name + '\"]');\n if (btn) btn.classList.add('active');\n form.classList.add('active');\n var sub = document.getElementById('subtitle');\n if (sub && subtitles[name]) sub.textContent = subtitles[name];\n var heading = document.getElementById('heading');\n if (heading && headings[name]) heading.textContent = headings[name];\n if (opts && opts.persist) {\n try { localStorage.setItem(TAB_STORAGE_KEY, name); } catch (e) {}\n }\n }\n function showVerificationStep(email, password) {\n pendingSignupEmail = email || '';\n pendingSignupPassword = password || '';\n tabs.forEach(function(x) { x.classList.remove('active'); });\n forms.forEach(function(x) { x.classList.remove('active'); });\n var card = document.querySelector('.card');\n if (card) card.classList.add('verifying');\n var step = document.getElementById('verification-step');\n if (step) step.classList.add('active');\n var emailNode = document.getElementById('verify-email');\n if (emailNode) emailNode.textContent = pendingSignupEmail;\n var heading = document.getElementById('heading');\n if (heading) heading.textContent = 'Check your email';\n var sub = document.getElementById('subtitle');\n if (sub) sub.textContent = 'Finish creating your account';\n var msg = document.getElementById('verify-msg');\n if (msg) {\n msg.classList.remove('show', 'error', 'success');\n msg.textContent = '';\n }\n try { localStorage.setItem(TAB_STORAGE_KEY, 'signup'); } catch (e) {}\n }\n function getVerificationMessageNode() {\n var verifyStep = document.getElementById('verification-step');\n if (verifyStep && verifyStep.classList.contains('active')) {\n return document.getElementById('verify-msg');\n }\n return document.getElementById('l-msg') || document.getElementById('verify-msg');\n }\n function isVerificationStepActive() {\n var verifyStep = document.getElementById('verification-step');\n return !!(verifyStep && verifyStep.classList.contains('active'));\n }\n function getPendingSignupEmail() {\n var signupEmail = document.getElementById('s-email');\n var loginEmail = document.getElementById('l-email');\n return (pendingSignupEmail || (signupEmail && signupEmail.value) || (loginEmail && loginEmail.value) || '').trim();\n }\n function getPendingSignupPassword() {\n var signupPassword = document.getElementById('s-pass');\n return pendingSignupPassword || (signupPassword && signupPassword.value) || '';\n }\n function movePendingSignupToLogin(message) {\n var email = getPendingSignupEmail();\n setActiveTab('login', { persist: true });\n var loginEmail = document.getElementById('l-email');\n var loginPassword = document.getElementById('l-pass');\n var msg = document.getElementById('l-msg');\n if (loginEmail && email) loginEmail.value = email;\n if (msg) {\n msg.textContent = message || 'Sign in to continue.';\n msg.classList.remove('error');\n msg.classList.add('show', 'success');\n }\n setTimeout(function() { if (loginPassword) loginPassword.focus(); }, 0);\n }\n async function signInWithPendingSignup() {\n var email = getPendingSignupEmail();\n var password = getPendingSignupPassword();\n if (!email || !password) {\n return { ok: false, needsManualSignIn: true };\n }\n var res = await fetch(__anPath('/_agent-native/auth/login'), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email: email, password: password }),\n });\n if (res.ok) {\n window.location.reload();\n return { ok: true };\n }\n var data = await res.json().catch(function() { return {}; });\n var error = (data && (data.error || data.message)) || 'Could not finish sign-in automatically.';\n return {\n ok: false,\n error: error,\n isWaitingForVerification: /not verified|verification/i.test(error),\n };\n }\n async function checkVerificationSession(fallbackText, opts) {\n opts = opts || {};\n if (verificationCheckInFlight) return;\n verificationCheckInFlight = true;\n var msg = getVerificationMessageNode();\n var continueBtn = document.getElementById('verify-continue');\n if (continueBtn && !opts.silent) {\n continueBtn.disabled = true;\n continueBtn.textContent = 'Checking...';\n }\n if (msg && !opts.silent) {\n msg.textContent = 'Checking your verification...';\n msg.classList.remove('error');\n msg.classList.add('show', 'success');\n }\n try {\n var res = await fetch(__anPath('/_agent-native/auth/session'), {\n headers: { 'Accept': 'application/json' },\n });\n var data = await res.json().catch(function() { return {}; });\n if (res.ok && data && data.email && !data.error) {\n window.location.reload();\n return;\n }\n var loginResult = await signInWithPendingSignup();\n if (loginResult.ok) return;\n if (loginResult.needsManualSignIn) {\n if (!opts.silent) {\n movePendingSignupToLogin(fallbackText || 'Enter your password after verifying your email.');\n }\n return;\n }\n if (loginResult.error && !loginResult.isWaitingForVerification) {\n if (!opts.silent) {\n movePendingSignupToLogin('We could not finish sign-in automatically. Sign in to continue.');\n }\n return;\n }\n if (msg && !opts.silent) {\n msg.textContent = fallbackText || 'Still waiting on verification. Click the link in your email, then try Continue again.';\n msg.classList.remove('success');\n msg.classList.add('show', 'error');\n }\n } catch (err) {\n if (msg && !opts.silent) {\n msg.textContent = 'Could not check verification. Please try again.';\n msg.classList.remove('success');\n msg.classList.add('show', 'error');\n }\n } finally {\n verificationCheckInFlight = false;\n if (continueBtn && !opts.silent) {\n continueBtn.disabled = false;\n continueBtn.textContent = 'Continue';\n }\n }\n }\n function maybeCompleteVerificationAfterReturn() {\n if (!isVerificationStepActive()) return;\n checkVerificationSession(null, { silent: true });\n }\n async function resendVerificationEmail() {\n var btn = document.getElementById('resend-verification');\n var msg = document.getElementById('verify-msg');\n var email = pendingSignupEmail || document.getElementById('s-email').value;\n if (!email) return;\n var original = btn ? btn.textContent : '';\n if (btn) {\n btn.disabled = true;\n btn.textContent = 'Sending...';\n }\n if (msg) msg.classList.remove('show', 'error', 'success');\n try {\n var res = await fetch(__anPath('/_agent-native/auth/ba/send-verification-email'), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email: email, callbackURL: __anGetReturnPath() }),\n });\n if (res.ok) {\n if (msg) {\n msg.textContent = 'Sent a fresh verification link.';\n msg.classList.add('show', 'success');\n }\n if (btn) btn.textContent = 'Sent';\n setTimeout(function() {\n if (btn) {\n btn.disabled = false;\n btn.textContent = original;\n }\n }, 1600);\n return;\n }\n var data = await res.json().catch(function() { return {}; });\n if (msg) {\n msg.textContent = (data && (data.message || data.error)) || 'Could not resend the verification email.';\n msg.classList.add('show', 'error');\n }\n if (btn) {\n btn.disabled = false;\n btn.textContent = original;\n }\n } catch (err) {\n if (msg) {\n msg.textContent = 'Network error. Please try again.';\n msg.classList.add('show', 'error');\n }\n if (btn) {\n btn.disabled = false;\n btn.textContent = original;\n }\n }\n }\n (function initActiveTab() {\n var initial = 'signup';\n try {\n var params = new URLSearchParams(location.search);\n var qp = params.get('tab');\n var path = location.pathname;\n while (path.length > 1 && path.charAt(path.length - 1) === '/') path = path.slice(0, -1);\n if (qp === 'login' || qp === 'signup') {\n initial = qp;\n } else if (params.has('verified')) {\n initial = 'login';\n } else if (path === '/login' || path.endsWith('/login')) {\n initial = 'login';\n } else if (path === '/signup' || path.endsWith('/signup')) {\n initial = 'signup';\n } else {\n var stored = localStorage.getItem(TAB_STORAGE_KEY);\n if (stored === 'login' || stored === 'signup') initial = stored;\n }\n } catch (e) {}\n setActiveTab(initial, { persist: false });\n try {\n if (new URLSearchParams(location.search).has('verified')) {\n var msg = document.getElementById('l-msg');\n if (msg) {\n msg.textContent = 'Email verified. Finishing sign-in...';\n msg.classList.remove('error');\n msg.classList.add('show', 'success');\n }\n checkVerificationSession('Email verified. Sign in to continue.');\n }\n } catch (e) {}\n })();\n tabs.forEach(function(t) { t.addEventListener('click', function() {\n setActiveTab(t.dataset.tab, { persist: true });\n }); });\n\n document.getElementById('signup-form').addEventListener('submit', async function(e) {\n e.preventDefault();\n var form = e.currentTarget;\n var btn = form.querySelector('button[type=\"submit\"]');\n var msg = document.getElementById('s-msg');\n msg.classList.remove('show', 'error', 'success');\n var pass = document.getElementById('s-pass').value;\n var pass2 = document.getElementById('s-pass2').value;\n if (pass !== pass2) {\n msg.textContent = 'Passwords do not match';\n msg.classList.add('show', 'error');\n return;\n }\n var originalLabel = btn.textContent;\n btn.disabled = true;\n btn.textContent = 'Creating account…';\n try {\n var email = document.getElementById('s-email').value;\n var res = await fetch(__anPath('/_agent-native/auth/register'), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n email: email,\n password: pass,\n callbackURL: __anGetReturnPath(),\n }),\n });\n var data = await res.json().catch(function() { return {}; });\n if (res.ok) {\n // If email verification is required, the server won't return a session.\n // Try logging in — if it fails (unverified), show a \"check your email\" message.\n var loginRes = await fetch(__anPath('/_agent-native/auth/login'), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email: email, password: pass }),\n });\n if (loginRes.ok) {\n msg.textContent = 'Account created — signing you in…';\n msg.classList.add('show', 'success');\n window.location.reload();\n return;\n }\n btn.disabled = false;\n btn.textContent = originalLabel;\n showVerificationStep(email, pass);\n return;\n }\n msg.textContent = data.error || 'Registration failed';\n msg.classList.add('show', 'error');\n btn.disabled = false;\n btn.textContent = originalLabel;\n } catch (err) {\n msg.textContent = 'Network error — please try again';\n msg.classList.add('show', 'error');\n btn.disabled = false;\n btn.textContent = originalLabel;\n }\n });\n\n var verifyContinue = document.getElementById('verify-continue');\n if (verifyContinue) verifyContinue.addEventListener('click', function(e) {\n e.preventDefault();\n checkVerificationSession();\n });\n window.addEventListener('focus', maybeCompleteVerificationAfterReturn);\n document.addEventListener('visibilitychange', function() {\n if (document.visibilityState === 'visible') maybeCompleteVerificationAfterReturn();\n });\n var resendBtn = document.getElementById('resend-verification');\n if (resendBtn) resendBtn.addEventListener('click', function(e) {\n e.preventDefault();\n resendVerificationEmail();\n });\n var backToSignup = document.getElementById('back-to-signup');\n if (backToSignup) backToSignup.addEventListener('click', function(e) {\n e.preventDefault();\n setActiveTab('signup', { persist: true });\n var email = document.getElementById('s-email');\n setTimeout(function() { if (email) email.focus(); }, 0);\n });\n\n var forgotLink = document.getElementById('forgot-link');\n var backToLogin = document.getElementById('back-to-login');\n if (forgotLink) forgotLink.addEventListener('click', function(e) {\n e.preventDefault();\n document.getElementById('login-form').classList.remove('active');\n document.getElementById('forgot-form').classList.add('active');\n var sub = document.getElementById('subtitle');\n if (sub) sub.textContent = 'Reset your password';\n var heading = document.getElementById('heading');\n if (heading) heading.textContent = 'Reset password';\n var fEmail = document.getElementById('f-email');\n var lEmail = document.getElementById('l-email');\n if (lEmail && lEmail.value) fEmail.value = lEmail.value;\n setTimeout(function() { fEmail.focus(); }, 0);\n });\n if (backToLogin) backToLogin.addEventListener('click', function(e) {\n e.preventDefault();\n document.getElementById('forgot-form').classList.remove('active');\n document.getElementById('login-form').classList.add('active');\n var sub = document.getElementById('subtitle');\n if (sub) sub.textContent = subtitles.login;\n var heading = document.getElementById('heading');\n if (heading) heading.textContent = headings.login;\n });\n\n var forgotForm = document.getElementById('forgot-form');\n if (forgotForm) forgotForm.addEventListener('submit', async function(e) {\n e.preventDefault();\n var btn = e.currentTarget.querySelector('button[type=\"submit\"]');\n var msg = document.getElementById('f-msg');\n msg.classList.remove('show', 'error', 'success');\n var original = btn.textContent;\n btn.disabled = true;\n btn.textContent = 'Sending…';\n try {\n var email = document.getElementById('f-email').value;\n var res = await fetch(__anPath('/_agent-native/auth/ba/request-password-reset'), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email: email }),\n });\n if (res.ok) {\n msg.textContent = 'If that email exists, a reset link is on its way.';\n msg.classList.add('show', 'success');\n btn.textContent = 'Sent';\n return;\n }\n var data = await res.json().catch(function() { return {}; });\n msg.textContent = (data && (data.message || data.error)) || 'Could not send reset email.';\n msg.classList.add('show', 'error');\n btn.disabled = false;\n btn.textContent = original;\n } catch (err) {\n msg.textContent = 'Network error — please try again';\n msg.classList.add('show', 'error');\n btn.disabled = false;\n btn.textContent = original;\n }\n });\n\n document.getElementById('login-form').addEventListener('submit', async function(e) {\n e.preventDefault();\n var form = e.currentTarget;\n var btn = form.querySelector('button[type=\"submit\"]');\n var msg = document.getElementById('l-msg');\n msg.classList.remove('show', 'success');\n msg.classList.add('error');\n var originalLabel = btn.textContent;\n btn.disabled = true;\n btn.textContent = 'Signing in…';\n try {\n var res = await fetch(__anPath('/_agent-native/auth/login'), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n email: document.getElementById('l-email').value,\n password: document.getElementById('l-pass').value,\n }),\n });\n if (res.ok) {\n window.location.reload();\n return;\n }\n var data = await res.json().catch(function() { return {}; });\n msg.textContent = data.error || 'Invalid email or password';\n msg.classList.add('show');\n btn.disabled = false;\n btn.textContent = originalLabel;\n } catch (err) {\n msg.textContent = 'Network error — please try again';\n msg.classList.add('show');\n btn.disabled = false;\n btn.textContent = originalLabel;\n }\n });\n`\n}\n${\n showGoogle\n ? `\n async function signInWithGoogle() {\n if (__anShouldShowGoogleNotice()) {\n __anShowGoogleNotice();\n return;\n }\n return __anStartGoogleSignIn();\n }\n async function __anStartGoogleSignIn() {\n var btn = document.getElementById('google-btn');\n var err = document.getElementById('google-err');\n var ret = __anGetReturnPath();\n btn.disabled = true;\n err.classList.remove('show');\n if (__anResolveAuthFlow() === 'popup') {\n __anStartPopupOAuth(ret, btn, err);\n return;\n }\n if (__anIsAgentNativeDesktop()) {\n __anStartNativeDesktopOAuth(ret, btn, err);\n return;\n }\n if (__anIsBuilderPreview()) {\n __anStartRedirectOAuth(ret, btn, err);\n return;\n }\n try {\n var authUrl = __anGoogleAuthUrlPath() + '?return=' + encodeURIComponent(ret);\n var res = await fetch(authUrl);\n var data = await res.json();\n if (data.url) {\n __anOpenOAuthUrl(data.url);\n } else {\n err.textContent = data.message || 'Google OAuth is not configured.';\n err.classList.add('show');\n btn.disabled = false;\n }\n } catch (e) {\n err.textContent = 'Failed to connect. Please try again.';\n err.classList.add('show');\n btn.disabled = false;\n }\n }`\n : \"\"\n}\n${\n googleSignInNotice\n ? `\n window.__anGoogleNoticeAccepted = false;\n function __anShouldShowGoogleNotice() {\n var notice = document.getElementById('google-preflight');\n if (!notice || window.__anGoogleNoticeAccepted) return false;\n var host = notice.getAttribute('data-host');\n return !host || window.location.hostname === host;\n }\n function __anShowGoogleNotice() {\n var notice = document.getElementById('google-preflight');\n if (!notice) return;\n notice.classList.add('show');\n var continueBtn = document.getElementById('google-preflight-continue');\n if (continueBtn) continueBtn.focus();\n }\n function __anHideGoogleNotice() {\n var notice = document.getElementById('google-preflight');\n if (notice) notice.classList.remove('show');\n }\n function __anAcceptGoogleNotice() {\n window.__anGoogleNoticeAccepted = true;\n __anHideGoogleNotice();\n __anStartGoogleSignIn();\n }`\n : `\n function __anShouldShowGoogleNotice() { return false; }`\n}\n${starfieldScript}\n${\n runLocalCommand\n ? `\n function __anToggleRunLocalCommand() {\n var panel = document.getElementById('run-local-panel');\n var button = document.getElementById('run-local-button');\n if (!panel || !button) return;\n var nextOpen = panel.hasAttribute('hidden');\n if (nextOpen) {\n panel.removeAttribute('hidden');\n } else {\n panel.setAttribute('hidden', '');\n }\n button.setAttribute('aria-expanded', String(nextOpen));\n }\n function __anCopyRunLocalCommand() {\n var panel = document.getElementById('run-local-panel');\n var button = document.getElementById('copy-run-local');\n if (!panel || !button) return;\n var command = panel.getAttribute('data-command') || '';\n var original = button.textContent || 'Copy command';\n function markCopied() {\n button.textContent = 'Copied';\n setTimeout(function() { button.textContent = original; }, 1600);\n }\n if (navigator.clipboard && navigator.clipboard.writeText) {\n navigator.clipboard.writeText(command).then(markCopied).catch(function() {});\n }\n }`\n : \"\"\n}\n</script>\n</body>\n</html>`;\n}\n\n/** @deprecated Use getOnboardingHtml() instead */\nexport const ONBOARDING_HTML = getOnboardingHtml();\n\n/**\n * HTML for the password reset page — shown when the user clicks the link in\n * their reset email. Posts `{ newPassword, token }` to Better Auth's\n * `/reset-password` endpoint, then redirects to the login page.\n */\nexport function getResetPasswordHtml(): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\">\n<title>Reset password</title>\n<link rel=\"icon\" type=\"image/svg+xml\" href=\"${withAppBasePath(\"/favicon.svg\")}\">\n<link rel=\"apple-touch-icon\" href=\"${withAppBasePath(\"/icon-180.svg\")}\">\n<style>\n *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n body { font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif; background: #0a0a0a; color: #e5e5e5; display: flex; align-items: center; justify-content: center; min-height: 100vh; padding: 1rem; }\n .card { width: 100%; max-width: 400px; padding: 2rem; background: #141414; border: 1px solid rgba(255,255,255,0.08); border-radius: 12px; }\n h1 { font-size: 1.25rem; font-weight: 600; margin-bottom: 0.25rem; color: #fff; }\n .subtitle { font-size: 0.8125rem; color: #888; margin-bottom: 1.5rem; }\n label { display: block; font-size: 0.8125rem; color: #888; margin-bottom: 0.375rem; }\n input { width: 100%; padding: 0.5rem 0.75rem; background: transparent; border: 1px solid rgba(255,255,255,0.12); border-radius: 6px; color: #e5e5e5; font-size: 0.875rem; outline: none; margin-bottom: 0.875rem; }\n input:focus { border-color: rgba(255,255,255,0.3); box-shadow: 0 0 0 1px rgba(255,255,255,0.1); }\n input::placeholder { color: #555; }\n button[type=\"submit\"] { width: 100%; margin-top: 0.25rem; padding: 0.5rem; background: #fff; color: #000; border: none; border-radius: 6px; font-size: 0.875rem; font-weight: 500; cursor: pointer; }\n button[type=\"submit\"]:hover { background: #e5e5e5; }\n button[type=\"submit\"]:disabled { opacity: 0.5; cursor: not-allowed; }\n .msg { margin-top: 0.75rem; font-size: 0.8125rem; display: none; }\n .msg.error { color: #f87171; }\n .msg.success { color: #4ade80; }\n .msg.show { display: block; }\n .back { display: inline-block; margin-top: 1rem; font-size: 0.75rem; color: #888; text-decoration: none; }\n .back:hover { color: #bbb; }\n</style>\n</head>\n<body>\n<div class=\"card\">\n <h1>Choose a new password</h1>\n <p class=\"subtitle\">Set a new password for your account.</p>\n <form id=\"reset-form\">\n <label for=\"p1\">New password</label>\n <input id=\"p1\" type=\"password\" autocomplete=\"new-password\" autofocus placeholder=\"At least 8 characters\" required minlength=\"8\" />\n <label for=\"p2\">Confirm password</label>\n <input id=\"p2\" type=\"password\" autocomplete=\"new-password\" placeholder=\"Confirm password\" required minlength=\"8\" />\n <button type=\"submit\">Save new password</button>\n <p class=\"msg\" id=\"msg\"></p>\n </form>\n <a class=\"back\" id=\"back-link\" href=\"/\">Back to sign in</a>\n</div>\n<script>\n (function() {\n // Derive the app's base path so apps mounted under a prefix\n // (e.g. /mail, /calendar) get sent home instead of to the root domain.\n var RESET_PATH = '/_agent-native/auth/reset';\n var pathname = window.location.pathname;\n var idx = pathname.indexOf(RESET_PATH);\n var basePath = (idx >= 0 ? pathname.slice(0, idx) : '') || '';\n var homeHref = basePath + '/';\n var backLink = document.getElementById('back-link');\n if (backLink) backLink.setAttribute('href', homeHref);\n var params = new URLSearchParams(location.search);\n var token = params.get('token') || '';\n var msg = document.getElementById('msg');\n if (!token) {\n msg.textContent = 'Missing or invalid reset token. Request a new reset link.';\n msg.classList.add('show', 'error');\n document.getElementById('reset-form').style.display = 'none';\n return;\n }\n document.getElementById('reset-form').addEventListener('submit', async function(e) {\n e.preventDefault();\n var btn = e.currentTarget.querySelector('button[type=\"submit\"]');\n var p1 = document.getElementById('p1').value;\n var p2 = document.getElementById('p2').value;\n msg.classList.remove('show', 'error', 'success');\n if (p1 !== p2) {\n msg.textContent = 'Passwords do not match';\n msg.classList.add('show', 'error');\n return;\n }\n var original = btn.textContent;\n btn.disabled = true;\n btn.textContent = 'Saving…';\n try {\n var res = await fetch(basePath + '/_agent-native/auth/ba/reset-password', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ newPassword: p1, token: token }),\n });\n if (res.ok) {\n msg.textContent = 'Password updated — redirecting to sign in…';\n msg.classList.add('show', 'success');\n setTimeout(function() { window.location.href = homeHref; }, 1200);\n return;\n }\n var data = await res.json().catch(function() { return {}; });\n msg.textContent = (data && (data.message || data.error)) || 'Reset failed. The link may have expired — request a new one.';\n msg.classList.add('show', 'error');\n btn.disabled = false;\n btn.textContent = original;\n } catch (err) {\n msg.textContent = 'Network error — please try again';\n msg.classList.add('show', 'error');\n btn.disabled = false;\n btn.textContent = original;\n }\n });\n })();\n</script>\n</body>\n</html>`;\n}\n"]}
1
+ {"version":3,"file":"onboarding-html.js","sourceRoot":"","sources":["../../src/server/onboarding-html.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * First-run onboarding page for agent-native apps.\n *\n * Shown when Better Auth is active and the user isn't signed in.\n * Provides a path to create or sign into an account from day one.\n *\n * After first account exists, this page acts as a normal login page.\n */\n\nimport { getPublicOAuthOrigin } from \"./oauth-public-origin.js\";\nimport {\n resolveGoogleAuthMode,\n type GoogleAuthMode,\n} from \"./google-auth-mode.js\";\nimport { getWorkspaceGatewayReturnOrigin } from \"./oauth-return-url.js\";\nimport { identitySsoLoginButtonHtml } from \"./identity-sso-store.js\";\n\nfunction hasGoogleOAuth(): boolean {\n return !!(process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET);\n}\n\nfunction getConnectionLabel(): string {\n const url = process.env.DATABASE_URL || \"\";\n if (!url) return \"SQLite (local file)\";\n if (url.startsWith(\"postgres://\") || url.startsWith(\"postgresql://\")) {\n if (url.includes(\"neon.tech\")) return \"Neon Postgres\";\n if (url.includes(\"supabase\")) return \"Supabase Postgres\";\n return \"Postgres\";\n }\n if (url.startsWith(\"file:\")) return \"SQLite (local file)\";\n if (url.startsWith(\"libsql://\") || url.includes(\"turso.io\")) return \"Turso\";\n return \"SQL database\";\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\nfunction withAppBasePath(path: string): string {\n const cleanPath = path.startsWith(\"/\") ? path : `/${path}`;\n const basePath = normalizeAppBasePath(\n process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH,\n );\n return `${basePath}${cleanPath}`;\n}\n\nexport interface OnboardingHtmlOptions {\n /**\n * Hide email/password forms and show ONLY the Google sign-in button.\n * Useful for templates (mail, calendar) where Google is required anyway.\n * If Google OAuth env vars are not configured, an error message is shown.\n */\n googleOnly?: boolean;\n /**\n * Product marketing content shown alongside the sign-in form.\n * When provided, the page uses a split layout: marketing on the left,\n * sign-in form on the right (stacked on mobile).\n */\n marketing?: {\n appName: string;\n tagline: string;\n description?: string;\n features?: string[];\n runLocalCommand?: string;\n };\n /**\n * Optional preflight copy shown before redirecting through Google sign-in.\n * Use this when a hosted app needs to warn about provider-specific consent\n * screens while leaving self-hosted deployments untouched.\n */\n googleSignInNotice?: {\n host?: string;\n title: string;\n body: string | string[];\n continueLabel?: string;\n cancelLabel?: string;\n };\n /**\n * Google sign-in flow: `'popup'`, `'redirect'`, or `'auto'` (default).\n * Falls back to `GOOGLE_AUTH_MODE` env var, then `'auto'`. Builder web\n * iframes use popup; Builder desktop preview/editor surfaces use redirect.\n */\n googleAuthMode?: GoogleAuthMode;\n}\n\nexport function getOnboardingHtml(opts: OnboardingHtmlOptions = {}): string {\n const showGoogle = hasGoogleOAuth();\n const googleOnly = !!opts.googleOnly;\n const appBasePath = normalizeAppBasePath(\n process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH,\n );\n const publicOAuthOrigin = getPublicOAuthOrigin();\n const workspaceGatewayReturnOrigin = getWorkspaceGatewayReturnOrigin();\n const googleAuthMode = resolveGoogleAuthMode(opts.googleAuthMode);\n\n const marketing = opts.marketing;\n const hasMarketing = !!marketing;\n const runLocalCommand = marketing?.runLocalCommand?.trim();\n const brandMarkSrc = withAppBasePath(\"/agent-native-icon-dark.svg\");\n const esc = (s: string) =>\n s\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\");\n const googleSignInNotice = opts.googleSignInNotice;\n const googleNoticeBodyHtml = googleSignInNotice\n ? (Array.isArray(googleSignInNotice.body)\n ? googleSignInNotice.body\n : [googleSignInNotice.body]\n )\n .filter((body) => body.trim().length > 0)\n .map(\n (body, index) =>\n `<p class=\"google-preflight-copy\"${index === 0 ? ' id=\"google-preflight-copy\"' : \"\"}>${esc(body)}</p>`,\n )\n .join(\"\\n\")\n : \"\";\n const googleNoticeHtml =\n showGoogle && googleSignInNotice\n ? `\n <div\n class=\"google-preflight\"\n id=\"google-preflight\"\n data-host=\"${esc(googleSignInNotice.host ?? \"\")}\"\n role=\"dialog\"\n aria-labelledby=\"google-preflight-title\"\n aria-describedby=\"google-preflight-copy\"\n >\n <p class=\"google-preflight-title\" id=\"google-preflight-title\">${esc(googleSignInNotice.title)}</p>\n${googleNoticeBodyHtml}\n <div class=\"google-preflight-actions\">\n <button type=\"button\" class=\"btn-primary\" id=\"google-preflight-continue\" onclick=\"__anAcceptGoogleNotice()\">${esc(googleSignInNotice.continueLabel ?? \"Continue\")}</button>\n <button type=\"button\" class=\"btn-secondary\" onclick=\"__anHideGoogleNotice()\">${esc(googleSignInNotice.cancelLabel ?? \"Cancel\")}</button>\n </div>\n </div>`\n : \"\";\n\n const marketingStyles = hasMarketing\n ? `\n body.has-marketing { padding: 0; position: relative; overflow-x: hidden; }\n #starfield {\n position: fixed;\n inset: 0;\n width: 100%;\n height: 100%;\n opacity: 0.35;\n pointer-events: none;\n z-index: 0;\n }\n @media (prefers-reduced-motion: reduce) {\n #starfield { opacity: 0.18; }\n }\n .split {\n position: relative;\n z-index: 1;\n display: flex;\n min-height: 100vh;\n width: 100%;\n max-width: 1100px;\n margin: 0 auto;\n }\n .marketing-panel {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n padding: 3rem 3.5rem;\n }\n .marketing-content { max-width: 480px; }\n .app-name {\n display: flex;\n align-items: center;\n gap: 0.625rem;\n font-size: 2rem;\n font-weight: 700;\n color: #fff;\n margin-bottom: 0.625rem;\n letter-spacing: -0.02em;\n }\n .app-name img.brand-mark {\n height: 2.21375rem;\n width: auto;\n display: block;\n flex-shrink: 0;\n }\n .app-tagline {\n font-size: 1.25rem;\n color: #a1a1aa;\n line-height: 1.6;\n margin-bottom: 2rem;\n }\n .app-desc {\n font-size: 1rem;\n color: #71717a;\n line-height: 1.6;\n margin-bottom: 2rem;\n }\n .feature-list {\n list-style: none;\n display: flex;\n flex-direction: column;\n gap: 0.875rem;\n }\n .feature-list li {\n display: flex;\n align-items: flex-start;\n gap: 0.625rem;\n font-size: 1rem;\n color: #a1a1aa;\n line-height: 1.5;\n }\n .feature-list li::before {\n content: '';\n flex-shrink: 0;\n width: 8px;\n height: 8px;\n margin-top: 6px;\n border-radius: 50%;\n background: #3f3f46;\n border: 1px solid #52525b;\n }\n .oss-link {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n font-size: 0.8125rem;\n color: #71717a;\n text-decoration: none;\n }\n .oss-link:hover { color: #a1a1aa; }\n .oss-link svg { width: 15px; height: 15px; flex-shrink: 0; }\n .marketing-actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.75rem;\n margin-top: 2rem;\n }\n .run-local-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-height: 2.25rem;\n padding: 0.5rem 0.875rem;\n background: rgba(255,255,255,0.08);\n color: #fff;\n border: 1px solid rgba(255,255,255,0.14);\n border-radius: 8px;\n font-size: 0.8125rem;\n font-weight: 500;\n cursor: pointer;\n }\n .run-local-button:hover {\n background: rgba(255,255,255,0.12);\n border-color: rgba(255,255,255,0.24);\n }\n .run-local-panel {\n max-width: 480px;\n margin-top: 0.75rem;\n padding: 0.75rem;\n background: rgba(20,20,20,0.86);\n border: 1px solid rgba(255,255,255,0.1);\n border-radius: 10px;\n box-shadow: 0 14px 36px rgba(0,0,0,0.28);\n }\n .run-local-panel[hidden] { display: none; }\n .run-local-panel code {\n display: block;\n overflow-x: auto;\n padding-bottom: 0.125rem;\n color: #e5e5e5;\n font-family: \"SFMono-Regular\", Consolas, \"Liberation Mono\", monospace;\n font-size: 0.75rem;\n line-height: 1.5;\n white-space: nowrap;\n }\n .copy-run-local {\n margin-top: 0.625rem;\n padding: 0.375rem 0.625rem;\n background: transparent;\n color: #a1a1aa;\n border: 1px solid rgba(255,255,255,0.12);\n border-radius: 6px;\n font-size: 0.75rem;\n cursor: pointer;\n }\n .copy-run-local:hover { color: #fff; border-color: rgba(255,255,255,0.22); }\n .form-panel {\n flex: 0 0 440px;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 2rem;\n }\n .form-panel .card { max-width: 400px; }\n .form-panel .local-note { max-width: 400px; }\n @media (max-width: 900px) {\n .split { flex-direction: column; min-height: auto; }\n .marketing-panel { padding: 2rem 1.5rem 1.5rem; }\n .app-name { font-size: 1.375rem; }\n .app-name img.brand-mark { height: 1.58125rem; }\n .app-tagline { font-size: 1rem; margin-bottom: 1rem; }\n .app-desc { margin-bottom: 1rem; }\n .feature-list { gap: 0.5rem; }\n .form-panel { flex: none; padding: 1.5rem 1rem; }\n }\n`\n : \"\";\n\n const marketingPanelHtml = hasMarketing\n ? `<canvas id=\"starfield\"></canvas>\n<div class=\"split\">\n <div class=\"marketing-panel\">\n <div class=\"marketing-content\">\n <h2 class=\"app-name\">\n <img class=\"brand-mark\" src=\"${esc(brandMarkSrc)}\" alt=\"\" aria-hidden=\"true\" />\n <span>${esc(marketing!.appName)}</span>\n </h2>\n <p class=\"app-tagline\">${esc(marketing!.tagline)}</p>\n${marketing!.description ? ` <p class=\"app-desc\">${esc(marketing!.description)}</p>\\n` : \"\"}${\n marketing!.features?.length\n ? ` <ul class=\"feature-list\">\\n${marketing!.features.map((f) => ` <li>${esc(f)}</li>`).join(\"\\n\")}\\n </ul>\\n`\n : \"\"\n } <div class=\"marketing-actions\">\n${runLocalCommand ? ` <button type=\"button\" class=\"run-local-button\" id=\"run-local-button\" aria-expanded=\"false\" aria-controls=\"run-local-panel\" onclick=\"__anToggleRunLocalCommand()\">Run Locally</button>\\n` : \"\"} <a class=\"oss-link\" href=\"https://github.com/BuilderIO/agent-native\" target=\"_blank\" rel=\"noreferrer\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 19c-4.3 1.4-4.3-2.5-6-3m12 5v-3.5c0-1 .1-1.4-.5-2 2.8-.3 5.5-1.4 5.5-6a4.6 4.6 0 00-1.3-3.2 4.2 4.2 0 00-.1-3.2s-1.1-.3-3.5 1.3a12.3 12.3 0 00-6.2 0C6.5 2.8 5.4 3.1 5.4 3.1a4.2 4.2 0 00-.1 3.2A4.6 4.6 0 004 9.5c0 4.6 2.7 5.7 5.5 6-.6.6-.6 1.2-.5 2V21\"/></svg>\n Open source\n </a>\n </div>\n${\n runLocalCommand\n ? ` <div class=\"run-local-panel\" id=\"run-local-panel\" hidden data-command=\"${esc(runLocalCommand)}\">\n <code>${esc(runLocalCommand)}</code>\n <button type=\"button\" class=\"copy-run-local\" id=\"copy-run-local\" onclick=\"__anCopyRunLocalCommand()\">Copy command</button>\n </div>\\n`\n : \"\"\n}\n </div>\n </div>\n <div class=\"form-panel\">`\n : \"\";\n\n const marketingCloseHtml = hasMarketing ? `\\n </div>\\n</div>` : \"\";\n\n const starfieldScript = hasMarketing\n ? `\n (function initStarfield() {\n var canvas = document.getElementById('starfield');\n if (!canvas) return;\n var gl = canvas.getContext('webgl', { alpha: false, antialias: false });\n if (!gl) return;\n\n var vs = gl.createShader(gl.VERTEX_SHADER);\n gl.shaderSource(vs, 'attribute vec2 position;void main(){gl_Position=vec4(position,0.0,1.0);}');\n gl.compileShader(vs);\n\n var fs = gl.createShader(gl.FRAGMENT_SHADER);\n gl.shaderSource(fs, [\n 'precision highp float;',\n 'uniform float iTime;uniform vec2 iResolution;',\n '#define S(a,b,t) smoothstep(a,b,t)',\n '#define NUM_LAYERS 4.',\n 'float N21(vec2 p){vec3 a=fract(vec3(p.xyx)*vec3(213.897,653.453,253.098));a+=dot(a,a.yzx+79.76);return fract((a.x+a.y)*a.z);}',\n 'vec2 GetPos(vec2 id,vec2 offs,float t){float n=N21(id+offs);float n1=fract(n*10.);float n2=fract(n*100.);float a=t+n;return offs+vec2(sin(a*n1),cos(a*n2))*.4;}',\n 'float df_line(vec2 a,vec2 b,vec2 p){vec2 pa=p-a,ba=b-a;float h=clamp(dot(pa,ba)/dot(ba,ba),0.,1.);return length(pa-ba*h);}',\n 'float line(vec2 a,vec2 b,vec2 uv){float r1=.025;float r2=.006;float d=df_line(a,b,uv);float d2=length(a-b);float fade=S(1.5,.5,d2);fade+=S(.05,.02,abs(d2-.75));return S(r1,r2,d)*fade;}',\n 'float NetLayer(vec2 st,float n,float t){',\n ' vec2 id=floor(st)+n;st=fract(st)-.5;',\n ' vec2 p0=GetPos(id,vec2(-1,-1),t);vec2 p1=GetPos(id,vec2(0,-1),t);vec2 p2=GetPos(id,vec2(1,-1),t);',\n ' vec2 p3=GetPos(id,vec2(-1,0),t);vec2 p4=GetPos(id,vec2(0,0),t);vec2 p5=GetPos(id,vec2(1,0),t);',\n ' vec2 p6=GetPos(id,vec2(-1,1),t);vec2 p7=GetPos(id,vec2(0,1),t);vec2 p8=GetPos(id,vec2(1,1),t);',\n ' float m=0.;float sparkle=0.;float d;float s;float pulse;',\n ' m+=line(p4,p0,st);d=length(st-p0);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p0.x)+fract(p0.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',\n ' m+=line(p4,p1,st);d=length(st-p1);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p1.x)+fract(p1.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',\n ' m+=line(p4,p2,st);d=length(st-p2);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p2.x)+fract(p2.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',\n ' m+=line(p4,p3,st);d=length(st-p3);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p3.x)+fract(p3.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',\n ' m+=line(p4,p4,st);d=length(st-p4);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p4.x)+fract(p4.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',\n ' m+=line(p4,p5,st);d=length(st-p5);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p5.x)+fract(p5.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',\n ' m+=line(p4,p6,st);d=length(st-p6);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p6.x)+fract(p6.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',\n ' m+=line(p4,p7,st);d=length(st-p7);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p7.x)+fract(p7.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',\n ' m+=line(p4,p8,st);d=length(st-p8);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p8.x)+fract(p8.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',\n ' m+=line(p1,p3,st);m+=line(p1,p5,st);m+=line(p7,p5,st);m+=line(p7,p3,st);',\n ' float sPhase=(sin(t+n)+sin(t*.1))*.25+.5;sPhase+=pow(sin(t*.1)*.5+.5,50.)*5.;m+=sparkle*sPhase;',\n ' return m;',\n '}',\n 'void mainImage(out vec4 fragColor,in vec2 fragCoord){',\n ' vec2 uv=(fragCoord-iResolution.xy*.5)/iResolution.y;',\n ' float t=iTime*.03;float s=sin(t);float c=cos(t);mat2 rot=mat2(c,-s,s,c);vec2 st=uv*rot;',\n ' float m=0.;',\n ' for(float i=0.;i<1.;i+=1./NUM_LAYERS){float z=fract(t+i);float size=mix(15.,1.,z);float fade=S(0.,.6,z)*S(1.,.8,z);m+=fade*NetLayer(st*size,i,iTime*0.3);}',\n ' vec3 col=vec3(0.35)*m;col*=1.-dot(uv,uv);',\n ' float tt=min(iTime,5.0);col*=S(0.,20.,tt);',\n ' col=clamp(col,0.,1.);fragColor=vec4(col,1.);',\n '}',\n 'void main(){mainImage(gl_FragColor,gl_FragCoord.xy);}'\n ].join('\\\\n'));\n gl.compileShader(fs);\n\n var prog = gl.createProgram();\n gl.attachShader(prog, vs);\n gl.attachShader(prog, fs);\n gl.linkProgram(prog);\n gl.useProgram(prog);\n\n var buf = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, buf);\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]), gl.STATIC_DRAW);\n var pos = gl.getAttribLocation(prog, 'position');\n gl.enableVertexAttribArray(pos);\n gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 0, 0);\n\n var uTime = gl.getUniformLocation(prog, 'iTime');\n var uRes = gl.getUniformLocation(prog, 'iResolution');\n var reducedMotionQuery = window.matchMedia ? window.matchMedia('(prefers-reduced-motion: reduce)') : null;\n var reducedMotion = reducedMotionQuery ? reducedMotionQuery.matches : false;\n\n function resize() {\n var w = window.innerWidth, h = window.innerHeight;\n var dpr = Math.min(window.devicePixelRatio, 1.5);\n canvas.width = w * dpr; canvas.height = h * dpr;\n gl.viewport(0, 0, canvas.width, canvas.height);\n }\n resize();\n window.addEventListener('resize', resize);\n\n var start = performance.now(), last = 0, raf = 0, reducedMotionStaticTime = 20;\n function draw(timeSeconds) {\n gl.uniform1f(uTime, timeSeconds);\n gl.uniform2f(uRes, canvas.width, canvas.height);\n gl.drawArrays(gl.TRIANGLES, 0, 6);\n }\n function render(now) {\n if (reducedMotion) {\n raf = 0;\n return;\n }\n raf = requestAnimationFrame(render);\n if (now - last < 33) return;\n last = now;\n draw((now - start) * 0.001);\n }\n function startAnimation() {\n if (!raf) raf = requestAnimationFrame(render);\n }\n function stopAnimation() {\n if (raf) {\n cancelAnimationFrame(raf);\n raf = 0;\n }\n }\n function onReducedMotionChange() {\n reducedMotion = reducedMotionQuery ? reducedMotionQuery.matches : false;\n if (reducedMotion) {\n stopAnimation();\n last = 0;\n draw(reducedMotionStaticTime);\n } else {\n startAnimation();\n }\n }\n draw(reducedMotion ? reducedMotionStaticTime : 0);\n if (reducedMotionQuery) {\n if (reducedMotionQuery.addEventListener) {\n reducedMotionQuery.addEventListener('change', onReducedMotionChange);\n } else {\n reducedMotionQuery.addListener(onReducedMotionChange);\n }\n }\n if (!reducedMotion) startAnimation();\n })();`\n : \"\";\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\">\n<title>${hasMarketing ? esc(marketing!.appName) + \" — Sign in\" : \"Welcome\"}</title>\n<link rel=\"icon\" type=\"image/svg+xml\" href=\"${withAppBasePath(\"/favicon.svg\")}\">\n<link rel=\"apple-touch-icon\" href=\"${withAppBasePath(\"/icon-180.svg\")}\">\n${\n hasMarketing\n ? `<meta name=\"description\" content=\"${esc(marketing!.tagline)}\">\n<meta property=\"og:title\" content=\"${esc(marketing!.appName)}\">\n<meta property=\"og:description\" content=\"${esc(marketing!.tagline)}\">`\n : \"\"\n}\n<style>\n *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n background: #0a0a0a;\n color: #e5e5e5;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n padding: 1rem;\n }\n .card {\n width: 100%;\n max-width: 400px;\n padding: 2rem;\n background: #141414;\n border: 1px solid rgba(255,255,255,0.08);\n border-radius: 12px;\n }\n h1 { font-size: 1.25rem; font-weight: 600; margin-bottom: 0.25rem; color: #fff; }\n .subtitle { font-size: 0.8125rem; color: #888; margin-bottom: 1.5rem; }\n .tabs {\n display: inline-flex;\n width: 100%;\n padding: 4px;\n margin-bottom: 1.5rem;\n background: rgba(255,255,255,0.06);\n border-radius: 8px;\n }\n .tab {\n flex: 1;\n padding: 0.5rem 0.75rem;\n background: none;\n border: none;\n color: #888;\n font-size: 0.8125rem;\n font-weight: 500;\n cursor: pointer;\n border-radius: 6px;\n }\n .tab.active {\n background: #1e1e1e;\n color: #fff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.3);\n }\n .tab:hover:not(.active) { color: #bbb; }\n .form { display: none; }\n .form.active { display: block; }\n .card.verifying .tabs,\n .card.verifying #google-btn,\n .card.verifying #google-err,\n .card.verifying #auth-divider,\n .card.verifying #upgrade-note {\n display: none;\n }\n label { display: block; font-size: 0.8125rem; color: #888; margin-bottom: 0.375rem; }\n input {\n width: 100%;\n padding: 0.5rem 0.75rem;\n background: transparent;\n border: 1px solid rgba(255,255,255,0.12);\n border-radius: 6px;\n color: #e5e5e5;\n font-size: 0.875rem;\n outline: none;\n margin-bottom: 0.875rem;\n }\n input:focus { border-color: rgba(255,255,255,0.3); box-shadow: 0 0 0 1px rgba(255,255,255,0.1); }\n input::placeholder { color: #555; }\n button[type=\"submit\"], .btn-primary {\n width: 100%;\n margin-top: 0.25rem;\n padding: 0.5rem;\n background: #fff;\n color: #000;\n border: none;\n border-radius: 6px;\n font-size: 0.875rem;\n font-weight: 500;\n cursor: pointer;\n }\n button[type=\"submit\"]:hover, .btn-primary:hover { background: #e5e5e5; }\n button[type=\"submit\"]:disabled { opacity: 0.5; cursor: not-allowed; }\n .btn-secondary {\n width: 100%;\n margin-top: 0.75rem;\n padding: 0.5rem;\n background: transparent;\n color: #888;\n border: 1px solid rgba(255,255,255,0.1);\n border-radius: 6px;\n font-size: 0.8125rem;\n cursor: pointer;\n }\n .btn-secondary:hover { color: #bbb; border-color: rgba(255,255,255,0.2); }\n .msg { margin-top: 0.75rem; font-size: 0.8125rem; display: none; }\n .msg.error { color: #f87171; }\n .msg.success { color: #4ade80; }\n .msg.show { display: block; }\n .step-progress {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 0.5rem;\n margin-bottom: 1.25rem;\n }\n .progress-step {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 0.375rem;\n color: #666;\n font-size: 0.6875rem;\n line-height: 1.2;\n text-align: center;\n }\n .progress-step::before {\n content: '';\n position: absolute;\n top: 11px;\n left: calc(-50% + 16px);\n width: calc(100% - 32px);\n height: 1px;\n background: rgba(255,255,255,0.1);\n }\n .progress-step:first-child::before { display: none; }\n .progress-step span {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n border-radius: 999px;\n border: 1px solid rgba(255,255,255,0.14);\n background: #151515;\n color: #777;\n font-size: 0.6875rem;\n font-weight: 600;\n }\n .progress-step strong { font-weight: 500; }\n .progress-step.complete,\n .progress-step.current { color: #e5e5e5; }\n .progress-step.complete span {\n background: #d9f99d;\n border-color: #d9f99d;\n color: #111;\n }\n .progress-step.current span {\n background: #fff;\n border-color: #fff;\n color: #000;\n box-shadow: 0 0 0 4px rgba(255,255,255,0.08);\n }\n .verification-panel {\n padding: 1rem;\n margin-bottom: 0.875rem;\n background: rgba(255,255,255,0.04);\n border: 1px solid rgba(255,255,255,0.08);\n border-radius: 8px;\n }\n .verification-kicker {\n margin-bottom: 0.5rem;\n color: #bef264;\n font-size: 0.75rem;\n font-weight: 500;\n }\n .verification-copy {\n color: #d4d4d8;\n font-size: 0.875rem;\n line-height: 1.55;\n }\n .verification-copy strong {\n color: #fff;\n font-weight: 600;\n word-break: break-word;\n }\n .verification-note {\n margin-top: 0.75rem;\n color: #71717a;\n font-size: 0.75rem;\n line-height: 1.45;\n }\n .inline-actions {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.75rem;\n margin-top: 0.75rem;\n }\n .link-button {\n padding: 0.25rem 0;\n background: none;\n border: none;\n color: #888;\n cursor: pointer;\n font-size: 0.75rem;\n text-decoration: underline;\n text-underline-offset: 2px;\n }\n .link-button:hover { color: #bbb; }\n .link-button:disabled { cursor: wait; opacity: 0.5; }\n .divider {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n margin: 1.25rem 0;\n font-size: 0.75rem;\n color: #555;\n }\n .divider::before, .divider::after {\n content: '';\n flex: 1;\n height: 1px;\n background: rgba(255,255,255,0.08);\n }\n .upgrade-note {\n margin-bottom: 1rem;\n padding: 0.75rem;\n border: 1px solid rgba(255,255,255,0.08);\n border-radius: 8px;\n background: rgba(255,255,255,0.03);\n font-size: 0.75rem;\n line-height: 1.5;\n color: #a1a1aa;\n display: none;\n }\n .upgrade-note.show { display: block; }\n .btn-google {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.625rem;\n padding: 0.5rem;\n background: #fff;\n color: #000;\n border: none;\n border-radius: 6px;\n font-size: 0.875rem;\n font-weight: 500;\n cursor: pointer;\n }\n .btn-google:hover { background: #e5e5e5; }\n .btn-google:disabled { opacity: 0.5; cursor: wait; }\n .btn-google svg { width: 18px; height: 18px; flex-shrink: 0; }\n .google-error { margin-top: 0.5rem; font-size: 0.8125rem; color: #f87171; display: none; }\n .google-error.show { display: block; }\n .google-debug {\n display: none;\n margin-top: 0.5rem;\n font-size: 0.6875rem;\n line-height: 1.45;\n color: #777;\n word-break: break-word;\n }\n .google-debug.show { display: block; }\n .google-preflight {\n display: none;\n margin-top: 0.75rem;\n padding: 0.875rem;\n border: 1px solid rgba(255,255,255,0.12);\n border-radius: 10px;\n background: rgba(255,255,255,0.05);\n box-shadow: 0 14px 36px rgba(0,0,0,0.28);\n }\n .google-preflight.show { display: block; }\n .google-preflight-title {\n margin-bottom: 0.375rem;\n color: #fff;\n font-size: 0.8125rem;\n font-weight: 600;\n }\n .google-preflight-copy {\n color: #b4b4b8;\n font-size: 0.75rem;\n line-height: 1.55;\n }\n .google-preflight-copy + .google-preflight-copy { margin-top: 0.5rem; }\n .google-preflight-actions {\n display: flex;\n gap: 0.5rem;\n margin-top: 0.875rem;\n }\n .google-preflight-actions .btn-primary,\n .google-preflight-actions .btn-secondary {\n flex: 1;\n width: auto;\n margin-top: 0;\n }\n .local-note {\n display: none;\n max-width: 400px;\n width: 100%;\n margin-top: 1rem;\n padding: 0.625rem 0.875rem;\n font-size: 0.6875rem;\n line-height: 1.5;\n color: #666;\n border: 1px dashed rgba(255,255,255,0.08);\n border-radius: 8px;\n text-align: center;\n }\n .local-note.show { display: block; }\n .local-note strong { color: #999; font-weight: 500; }\n .local-note a { color: #888; text-decoration: none; }\n .local-note a:hover { color: #bbb; }\n${marketingStyles}\n</style>\n</head>\n<body${hasMarketing ? ' class=\"has-marketing\"' : \"\"}>\n${marketingPanelHtml}\n<div class=\"card\">\n <h1 id=\"heading\">${googleOnly ? \"Sign in\" : \"Welcome\"}</h1>\n <p class=\"subtitle\" id=\"subtitle\">${googleOnly ? \"Use your workspace Google account to continue\" : \"Create an account to get started\"}</p>\n <p\n class=\"upgrade-note\"\n id=\"upgrade-note\"\n data-upgrade-copy=\"Continue signing in to attach this app to your account and migrate local data.\"\n ></p>\n${identitySsoLoginButtonHtml()}\n${\n showGoogle\n ? `\n <button class=\"btn-google\" id=\"google-btn\" onclick=\"signInWithGoogle()\">\n <svg viewBox=\"0 0 24 24\"><path fill=\"#4285F4\" d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 0 1-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z\"/><path fill=\"#34A853\" d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"/><path fill=\"#FBBC05\" d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"/><path fill=\"#EA4335\" d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"/></svg>\n Sign in with Google\n </button>\n <p class=\"google-error\" id=\"google-err\"></p>\n <p class=\"google-debug\" id=\"google-debug\"></p>\n${googleNoticeHtml}\n${googleOnly ? \"\" : `\\n <div class=\"divider\" id=\"auth-divider\">or</div>\\n`}\n`\n : googleOnly\n ? `\n <p style=\"color:#f87171;font-size:0.875rem;text-align:center;padding:1rem 0\">\n Google sign-in is not configured. Set <code>GOOGLE_CLIENT_ID</code> and\n <code>GOOGLE_CLIENT_SECRET</code> environment variables to enable login.\n </p>\n`\n : \"\"\n}\n${\n googleOnly\n ? \"\"\n : ` <div class=\"tabs\">\n <button class=\"tab\" data-tab=\"signup\">Create account</button>\n <button class=\"tab\" data-tab=\"login\">Sign in</button>\n </div>\n\n <form id=\"signup-form\" class=\"form\">\n <label for=\"s-email\">Email</label>\n <input id=\"s-email\" type=\"email\" autocomplete=\"email\" autofocus placeholder=\"you@example.com\" required />\n <label for=\"s-pass\">Password</label>\n <input id=\"s-pass\" type=\"password\" autocomplete=\"new-password\" placeholder=\"At least 8 characters\" required minlength=\"8\" />\n <label for=\"s-pass2\">Confirm password</label>\n <input id=\"s-pass2\" type=\"password\" autocomplete=\"new-password\" placeholder=\"Confirm password\" required minlength=\"8\" />\n <button type=\"submit\">Create account</button>\n <p class=\"msg\" id=\"s-msg\"></p>\n </form>\n\n <div id=\"verification-step\" class=\"form verification-step\" aria-live=\"polite\">\n <div class=\"step-progress\" aria-label=\"Signup progress\">\n <div class=\"progress-step complete\"><span>1</span><strong>Account</strong></div>\n <div class=\"progress-step current\"><span>2</span><strong>Verify</strong></div>\n <div class=\"progress-step\"><span>3</span><strong>Start</strong></div>\n </div>\n <div class=\"verification-panel\">\n <p class=\"verification-kicker\">Verification email sent</p>\n <p class=\"verification-copy\">We sent a secure link to <strong id=\"verify-email\"></strong>. Click it, return here, and this app will finish signing you in automatically.</p>\n <p class=\"verification-note\">You can keep this tab open. If it has not refreshed after you come back, use Continue.</p>\n </div>\n <button type=\"button\" class=\"btn-primary\" id=\"verify-continue\">Continue</button>\n <div class=\"inline-actions\">\n <button type=\"button\" class=\"link-button\" id=\"resend-verification\">Resend email</button>\n <button type=\"button\" class=\"link-button\" id=\"back-to-signup\">Back</button>\n </div>\n <p class=\"msg\" id=\"verify-msg\"></p>\n </div>\n\n <form id=\"login-form\" class=\"form\">\n <label for=\"l-email\">Email</label>\n <input id=\"l-email\" type=\"email\" autocomplete=\"email\" placeholder=\"you@example.com\" required />\n <label for=\"l-pass\">Password</label>\n <input id=\"l-pass\" type=\"password\" autocomplete=\"current-password\" placeholder=\"Enter password\" required />\n <button type=\"submit\">Sign in</button>\n <p class=\"msg error\" id=\"l-msg\"></p>\n <p style=\"margin-top:0.75rem;font-size:0.75rem;text-align:right\">\n <a href=\"#\" id=\"forgot-link\" style=\"color:#888;text-decoration:underline;text-underline-offset:2px\">Forgot password?</a>\n </p>\n </form>\n\n <form id=\"forgot-form\" class=\"form\">\n <label for=\"f-email\">Email</label>\n <input id=\"f-email\" type=\"email\" autocomplete=\"email\" placeholder=\"you@example.com\" required />\n <button type=\"submit\">Send reset link</button>\n <p class=\"msg\" id=\"f-msg\"></p>\n <p style=\"margin-top:0.75rem;font-size:0.75rem;text-align:center\">\n <a href=\"#\" id=\"back-to-login\" style=\"color:#888;text-decoration:underline;text-underline-offset:2px\">Back to sign in</a>\n </p>\n </form>`\n}\n</div>\n<p class=\"local-note\" id=\"local-note\">\n Your account is stored in this app's own DB (<strong>${getConnectionLabel()}</strong>), not a third-party service.\n</p>${marketingCloseHtml}\n<script>\n function __anBasePath() {\n var configured = ${JSON.stringify(appBasePath)};\n if (configured) return configured;\n var marker = '/_agent-native';\n var idx = window.location.pathname.indexOf(marker);\n return idx > 0 ? window.location.pathname.slice(0, idx) : '';\n }\n function __anPath(path) {\n return __anBasePath() + path;\n }\n var __AN_PUBLIC_OAUTH_ORIGIN = ${JSON.stringify(publicOAuthOrigin)};\n var __AN_WORKSPACE_GATEWAY_RETURN_ORIGIN = ${JSON.stringify(workspaceGatewayReturnOrigin)};\n var __AN_GOOGLE_AUTH_MODE = ${JSON.stringify(googleAuthMode)};\n function __anConfiguredOAuthOrigin() {\n if (!__AN_PUBLIC_OAUTH_ORIGIN) return '';\n try {\n var origin = new URL(__AN_PUBLIC_OAUTH_ORIGIN).origin;\n return origin && origin !== window.location.origin ? origin : '';\n } catch(e) {\n return '';\n }\n }\n function __anAuthPath(path) {\n var origin = __anIsBuilderPreview() ? __anConfiguredOAuthOrigin() : '';\n return origin ? origin + path : __anPath(path);\n }\n function __anGoogleAuthUrlPath() {\n return __anIsBuilderPreview()\n ? __anAuthPath('/_agent-native/google/auth-url')\n : __anPath('/_agent-native/google/auth-url');\n }\n function __anBuilderPreviewReturnOrigin() {\n var candidates = [window.location.href, document.referrer || ''];\n try {\n if (window.location.ancestorOrigins) {\n for (var j = 0; j < window.location.ancestorOrigins.length; j++) {\n candidates.push(window.location.ancestorOrigins[j]);\n }\n }\n } catch(e) {}\n for (var i = 0; i < candidates.length; i++) {\n try {\n var url = new URL(candidates[i]);\n var host = url.hostname.toLowerCase();\n var isPreviewHost =\n host === 'builderio.xyz' || host.slice(-14) === '.builderio.xyz' ||\n host === 'builderio.dev' || host.slice(-14) === '.builderio.dev' ||\n host === 'builder.codes' || host.slice(-14) === '.builder.codes' ||\n host === 'builder.my' || host.slice(-11) === '.builder.my';\n if (url.protocol === 'https:' && isPreviewHost) return url.origin;\n } catch(e) {}\n }\n return '';\n }\n function __anWorkspaceGatewayReturnOrigin() {\n var previewOrigin = __anBuilderPreviewReturnOrigin();\n if (previewOrigin) return previewOrigin;\n if (__AN_WORKSPACE_GATEWAY_RETURN_ORIGIN) return __AN_WORKSPACE_GATEWAY_RETURN_ORIGIN;\n return __anIsBuilderDesktop() ? 'http://127.0.0.1:8080' : '';\n }\n function __anNormalizeWorkspaceReturnPath(ret) {\n try {\n var url = new URL(ret || '/', window.location.origin);\n var path = url.pathname || '/';\n if (path === '/dispatch/dispatch') {\n path = '/dispatch';\n } else if (path.indexOf('/dispatch/') === 0) {\n var rest = path.slice('/dispatch/'.length);\n var first = rest.split('/')[0];\n var dispatchRoutes = {\n overview: true, apps: true, metrics: true, vault: true,\n integrations: true, messaging: true, workspace: true,\n agents: true, destinations: true, identities: true,\n approvals: true, audit: true, team: true, 'thread-debug': true,\n 'new-app': true\n };\n if (first === 'dispatch') {\n path = '/dispatch' + rest.slice(first.length);\n } else if (first && !dispatchRoutes[first]) {\n path = '/' + rest;\n }\n }\n return path + url.search + url.hash;\n } catch(e) {\n return ret || '/';\n }\n }\n function __anOAuthReturnTarget(ret) {\n var path = __anNormalizeWorkspaceReturnPath(ret);\n var origin = __anWorkspaceGatewayReturnOrigin();\n return origin ? origin + path : path;\n }\n function __anSessionBridgeUrl(ret, sessionToken) {\n try {\n var url = new URL(ret || window.location.pathname + window.location.search, window.location.origin);\n url.searchParams.set('_session', sessionToken);\n return url.pathname + url.search + url.hash;\n } catch(e) {\n var sep = (ret || '/').indexOf('?') === -1 ? '?' : '&';\n return (ret || '/') + sep + '_session=' + encodeURIComponent(sessionToken);\n }\n }\n function __anFinishOAuthExchange(ret, flowId, sessionToken) {\n if (__anIsBuilderPreview()) {\n if (sessionToken) {\n __anSetOAuthDebug('OAuth exchange redeemed; applying session bridge to embedded app', flowId);\n window.location.replace(__anSessionBridgeUrl(ret, sessionToken));\n return;\n }\n __anSetOAuthDebug('OAuth exchange redeemed; reloading the embedded app', flowId);\n window.location.reload();\n return;\n }\n __anSetOAuthDebug('OAuth exchange redeemed; returning to the app', flowId);\n window.location.href = ret || '/';\n }\n function __anGetReturnPath() {\n try {\n var inner = new URLSearchParams(window.location.search).get('return');\n if (inner) return inner;\n } catch(e) {}\n return window.location.pathname + window.location.search;\n }\n var __anBuilderPreviewSeen = false;\n function __anRememberBuilderPreview() {\n __anBuilderPreviewSeen = true;\n try { sessionStorage.setItem('__an_builder_preview_seen', '1'); } catch(e) {}\n }\n function __anHasBuilderPreviewSignal() {\n try {\n var params = new URLSearchParams(window.location.search);\n if (params.has('builder.preview') || params.has('builder.frameEditing') || params.has('__builder_editing__')) return true;\n } catch(e) {}\n return false;\n }\n function __anIsBuilderPreview() {\n if (__anBuilderPreviewSeen) return true;\n if (__anHasBuilderPreviewSignal()) {\n __anRememberBuilderPreview();\n return true;\n }\n try {\n if (sessionStorage.getItem('__an_builder_preview_seen') === '1') {\n __anBuilderPreviewSeen = true;\n return true;\n }\n } catch(e) {}\n try {\n var ref = document.referrer || '';\n var fromBuilder = ref.indexOf('builder.io') !== -1 || ref.indexOf('builder.my') !== -1 || ref.indexOf('builderio.xyz') !== -1 || ref.indexOf('builderio.dev') !== -1 || ref.indexOf('builder.codes') !== -1;\n if (fromBuilder) __anRememberBuilderPreview();\n return fromBuilder;\n } catch(e) {\n return false;\n }\n }\n __anIsBuilderPreview();\n function __anIsBuilderDesktop() {\n try {\n var ua = navigator.userAgent || '';\n return ua.indexOf('Electron') !== -1 && ua.indexOf('AgentNativeDesktop') === -1;\n } catch(e) {\n return false;\n }\n }\n function __anIsAgentNativeDesktop() {\n try {\n return (navigator.userAgent || '').indexOf('AgentNativeDesktop') !== -1;\n } catch(e) {\n return false;\n }\n }\n function __anIsInFrame() {\n try {\n return window.self !== window.top;\n } catch(e) {\n return true;\n }\n }\n function __anIsElectron() {\n try {\n return (navigator.userAgent || '').indexOf('Electron') !== -1;\n } catch(e) {\n return false;\n }\n }\n function __anResolveAuthFlow() {\n if (__anIsBuilderPreview()) return __anIsInFrame() ? 'popup' : 'redirect';\n // Per-session override for ad-hoc testing outside Builder: append\n // ?authMode=popup or ?authMode=redirect to the sign-in URL.\n try {\n var qp = new URLSearchParams(window.location.search).get('authMode');\n if (qp === 'popup' || qp === 'redirect') return qp;\n } catch(e) {}\n var mode = __AN_GOOGLE_AUTH_MODE || 'auto';\n if (mode === 'popup') return 'popup';\n if (mode === 'redirect') return 'redirect';\n return __anIsAgentNativeDesktop() ? 'redirect' : 'popup';\n }\n var __anOAuthPollTimer = null;\n var __anOAuthPollCount = 0;\n function __anNewOAuthFlowId() {\n try {\n if (window.crypto && typeof window.crypto.randomUUID === 'function') {\n return window.crypto.randomUUID();\n }\n } catch(e) {}\n return 'builder-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2);\n }\n function __anFlowDebugId(flowId) {\n return flowId ? String(flowId).slice(-10) : '';\n }\n function __anSetOAuthDebug(message, flowId) {\n var text = message + (flowId ? ' (flow ' + __anFlowDebugId(flowId) + ')' : '');\n try {\n console.info('[agent-native][google-oauth] ' + text);\n } catch(e) {}\n // Only surface the debug overlay when explicitly opted in via #oauth-debug\n // hash or ?oauth_debug=1 query — otherwise it leaks raw flow IDs and\n // diagnostic strings into the user-facing sign-in screen.\n var showDebugOverlay = false;\n try {\n var loc = window.location || {};\n showDebugOverlay =\n (typeof loc.hash === 'string' && loc.hash.indexOf('oauth-debug') !== -1) ||\n (typeof loc.search === 'string' && loc.search.indexOf('oauth_debug=1') !== -1);\n } catch(e) {}\n var debug = document.getElementById('google-debug');\n if (debug) {\n debug.textContent = text;\n if (showDebugOverlay) debug.classList.add('show');\n }\n }\n function __anShowOAuthError(err, btn, message) {\n if (__anOAuthPollTimer) {\n clearInterval(__anOAuthPollTimer);\n __anOAuthPollTimer = null;\n }\n err.textContent = message;\n err.classList.add('show');\n btn.disabled = false;\n }\n function __anHandlePopupOAuthFailure(ret, btn, err, flowId, redirectReason, builderFrameMessage) {\n if (__anIsBuilderPreview() && __anIsInFrame()) {\n __anShowOAuthError(err, btn, builderFrameMessage + ' Allow popups for this site and try again (flow ' + __anFlowDebugId(flowId) + ').');\n return;\n }\n __anStartRedirectOAuth(ret, btn, err, flowId, redirectReason);\n }\n function __anStartRedirectOAuth(ret, btn, err, flowId, reason) {\n var params = new URLSearchParams();\n var oauthReturn = __anIsBuilderPreview() ? __anOAuthReturnTarget(ret) : ret;\n if (oauthReturn) params.set('return', oauthReturn);\n params.set('redirect', '1');\n __anSetOAuthDebug(reason || 'Opening Google sign-in redirect', flowId);\n try {\n __anOpenOAuthUrl(__anGoogleAuthUrlPath() + '?' + params.toString());\n } catch(e) {\n __anShowOAuthError(err, btn, 'Could not start Google sign-in redirect' + (flowId ? ' for flow ' + __anFlowDebugId(flowId) : '') + ': ' + (e && e.message ? e.message : 'unknown error'));\n }\n }\n function __anWaitForOAuthExchange(flowId, ret, btn, err) {\n var started = Date.now();\n var timeoutMs = 5 * 60 * 1000;\n __anOAuthPollCount = 0;\n async function check() {\n __anOAuthPollCount++;\n try {\n var res = await fetch(__anPath('/_agent-native/auth/desktop-exchange') + '?flow_id=' + encodeURIComponent(flowId), { credentials: 'include' });\n var data = await res.json().catch(function() { return {}; });\n if (data && (data.email || data.token)) {\n if (__anOAuthPollTimer) clearInterval(__anOAuthPollTimer);\n __anOAuthPollTimer = null;\n __anFinishOAuthExchange(ret, flowId, data.token);\n return;\n }\n if (data && data.error) {\n __anSetOAuthDebug('OAuth exchange returned an error: ' + (data.message || data.error), flowId);\n __anShowOAuthError(err, btn, data.message || data.error);\n return;\n }\n if (data && data.pending && (__anOAuthPollCount === 1 || __anOAuthPollCount % 5 === 0)) {\n __anSetOAuthDebug('Waiting for the Google callback; polling attempt ' + __anOAuthPollCount, flowId);\n }\n } catch(e) {\n if (__anOAuthPollCount === 1 || __anOAuthPollCount % 5 === 0) {\n __anSetOAuthDebug('Could not reach the OAuth exchange endpoint: ' + (e && e.message ? e.message : 'network error'), flowId);\n }\n }\n if (Date.now() - started > timeoutMs) {\n __anShowOAuthError(err, btn, 'Google sign-in did not finish. Flow ' + __anFlowDebugId(flowId) + ' never reached this app. Check the Google OAuth redirect URI and server logs for [agent-native][google-oauth].');\n }\n }\n if (__anOAuthPollTimer) clearInterval(__anOAuthPollTimer);\n __anOAuthPollTimer = setInterval(check, 1000);\n setTimeout(check, 500);\n }\n function __anStartPopupOAuth(ret, btn, err) {\n var flowId = __anNewOAuthFlowId();\n var oauthReturn = __anIsBuilderPreview() ? __anOAuthReturnTarget(ret) : ret;\n var params = new URLSearchParams();\n if (oauthReturn) params.set('return', oauthReturn);\n params.set('desktop', '1');\n params.set('flow_id', flowId);\n params.set('redirect', '1');\n var url = __anGoogleAuthUrlPath() + '?' + params.toString();\n try { sessionStorage.setItem('__an_signin', '1'); } catch(e) {}\n __anSetOAuthDebug('Opening Google sign-in popup', flowId);\n try {\n var popup = window.open('', '_blank', 'width=640,height=760');\n if (!popup) {\n __anHandlePopupOAuthFailure(ret, btn, err, flowId, 'Google popup was blocked; falling back to redirect', 'Google popup was blocked.');\n return;\n }\n try { popup.opener = null; } catch(e) {}\n try {\n popup.location.href = url;\n } catch(e) {\n try { popup.close(); } catch(closeErr) {}\n __anHandlePopupOAuthFailure(ret, btn, err, flowId, 'Could not navigate Google popup; falling back to redirect', 'Could not navigate Google popup.');\n return;\n }\n __anSetOAuthDebug('Google popup opened; waiting for callback', flowId);\n } catch(e) {\n __anHandlePopupOAuthFailure(ret, btn, err, flowId, 'Could not open Google popup; falling back to redirect', 'Could not open Google popup.');\n return;\n }\n __anWaitForOAuthExchange(flowId, ret, btn, err);\n }\n function __anStartNativeDesktopOAuth(ret, btn, err) {\n var flowId = __anNewOAuthFlowId();\n var params = new URLSearchParams();\n if (ret) params.set('return', ret);\n params.set('desktop', '1');\n params.set('flow_id', flowId);\n params.set('redirect', '1');\n var url = __anGoogleAuthUrlPath() + '?' + params.toString();\n __anSetOAuthDebug('Opening Google sign-in in system browser', flowId);\n __anOpenOAuthUrl(url);\n __anWaitForOAuthExchange(flowId, ret, btn, err);\n }\n function __anOpenOAuthUrl(url) {\n try { sessionStorage.setItem('__an_signin', '1'); } catch(e) {}\n window.location.href = url;\n }\n (function revealLocalNote() {\n var h = location.hostname;\n if (h === 'localhost' || h === '127.0.0.1' || h === '::1' || h.endsWith('.local')) {\n var n = document.getElementById('local-note');\n if (n) n.classList.add('show');\n }\n })();\n (function revealUpgradeNote() {\n var shouldShow = false;\n try {\n var params = new URLSearchParams(location.search);\n shouldShow = params.get('signin') === '1' || params.get('upgrade-from-local') === '1';\n } catch(e) {}\n if (!shouldShow) {\n try { shouldShow = localStorage.getItem('an_migrate_from_local') === '1'; } catch(e) {}\n }\n if (!shouldShow) return;\n var n = document.getElementById('upgrade-note');\n if (!n) return;\n n.textContent = n.getAttribute('data-upgrade-copy') || 'Continue signing in to migrate local data.';\n n.classList.add('show');\n })();\n${\n googleOnly\n ? \"\"\n : ` var TAB_STORAGE_KEY = 'an.onboarding.tab';\n var tabs = document.querySelectorAll('.tab');\n var forms = document.querySelectorAll('.form');\n var subtitles = { signup: 'Create an account to get started', login: 'Sign in to your account' };\n var headings = { signup: 'Welcome', login: 'Welcome back' };\n var pendingSignupEmail = '';\n var pendingSignupPassword = '';\n var verificationCheckInFlight = false;\n function setActiveTab(name, opts) {\n if (name !== 'signup' && name !== 'login') return;\n var form = document.getElementById(name + '-form');\n if (!form) return;\n var card = document.querySelector('.card');\n if (card) card.classList.remove('verifying');\n tabs.forEach(function(x) { x.classList.remove('active'); });\n forms.forEach(function(x) { x.classList.remove('active'); });\n var btn = document.querySelector('.tab[data-tab=\"' + name + '\"]');\n if (btn) btn.classList.add('active');\n form.classList.add('active');\n var sub = document.getElementById('subtitle');\n if (sub && subtitles[name]) sub.textContent = subtitles[name];\n var heading = document.getElementById('heading');\n if (heading && headings[name]) heading.textContent = headings[name];\n if (opts && opts.persist) {\n try { localStorage.setItem(TAB_STORAGE_KEY, name); } catch (e) {}\n }\n }\n function showVerificationStep(email, password) {\n pendingSignupEmail = email || '';\n pendingSignupPassword = password || '';\n tabs.forEach(function(x) { x.classList.remove('active'); });\n forms.forEach(function(x) { x.classList.remove('active'); });\n var card = document.querySelector('.card');\n if (card) card.classList.add('verifying');\n var step = document.getElementById('verification-step');\n if (step) step.classList.add('active');\n var emailNode = document.getElementById('verify-email');\n if (emailNode) emailNode.textContent = pendingSignupEmail;\n var heading = document.getElementById('heading');\n if (heading) heading.textContent = 'Check your email';\n var sub = document.getElementById('subtitle');\n if (sub) sub.textContent = 'Finish creating your account';\n var msg = document.getElementById('verify-msg');\n if (msg) {\n msg.classList.remove('show', 'error', 'success');\n msg.textContent = '';\n }\n try { localStorage.setItem(TAB_STORAGE_KEY, 'signup'); } catch (e) {}\n }\n function getVerificationMessageNode() {\n var verifyStep = document.getElementById('verification-step');\n if (verifyStep && verifyStep.classList.contains('active')) {\n return document.getElementById('verify-msg');\n }\n return document.getElementById('l-msg') || document.getElementById('verify-msg');\n }\n function isVerificationStepActive() {\n var verifyStep = document.getElementById('verification-step');\n return !!(verifyStep && verifyStep.classList.contains('active'));\n }\n function getPendingSignupEmail() {\n var signupEmail = document.getElementById('s-email');\n var loginEmail = document.getElementById('l-email');\n return (pendingSignupEmail || (signupEmail && signupEmail.value) || (loginEmail && loginEmail.value) || '').trim();\n }\n function getPendingSignupPassword() {\n var signupPassword = document.getElementById('s-pass');\n return pendingSignupPassword || (signupPassword && signupPassword.value) || '';\n }\n function movePendingSignupToLogin(message) {\n var email = getPendingSignupEmail();\n setActiveTab('login', { persist: true });\n var loginEmail = document.getElementById('l-email');\n var loginPassword = document.getElementById('l-pass');\n var msg = document.getElementById('l-msg');\n if (loginEmail && email) loginEmail.value = email;\n if (msg) {\n msg.textContent = message || 'Sign in to continue.';\n msg.classList.remove('error');\n msg.classList.add('show', 'success');\n }\n setTimeout(function() { if (loginPassword) loginPassword.focus(); }, 0);\n }\n async function signInWithPendingSignup() {\n var email = getPendingSignupEmail();\n var password = getPendingSignupPassword();\n if (!email || !password) {\n return { ok: false, needsManualSignIn: true };\n }\n var res = await fetch(__anPath('/_agent-native/auth/login'), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email: email, password: password }),\n });\n if (res.ok) {\n window.location.reload();\n return { ok: true };\n }\n var data = await res.json().catch(function() { return {}; });\n var error = (data && (data.error || data.message)) || 'Could not finish sign-in automatically.';\n return {\n ok: false,\n error: error,\n isWaitingForVerification: /not verified|verification/i.test(error),\n };\n }\n async function checkVerificationSession(fallbackText, opts) {\n opts = opts || {};\n if (verificationCheckInFlight) return;\n verificationCheckInFlight = true;\n var msg = getVerificationMessageNode();\n var continueBtn = document.getElementById('verify-continue');\n if (continueBtn && !opts.silent) {\n continueBtn.disabled = true;\n continueBtn.textContent = 'Checking...';\n }\n if (msg && !opts.silent) {\n msg.textContent = 'Checking your verification...';\n msg.classList.remove('error');\n msg.classList.add('show', 'success');\n }\n try {\n var res = await fetch(__anPath('/_agent-native/auth/session'), {\n headers: { 'Accept': 'application/json' },\n });\n var data = await res.json().catch(function() { return {}; });\n if (res.ok && data && data.email && !data.error) {\n window.location.reload();\n return;\n }\n var loginResult = await signInWithPendingSignup();\n if (loginResult.ok) return;\n if (loginResult.needsManualSignIn) {\n if (!opts.silent) {\n movePendingSignupToLogin(fallbackText || 'Enter your password after verifying your email.');\n }\n return;\n }\n if (loginResult.error && !loginResult.isWaitingForVerification) {\n if (!opts.silent) {\n movePendingSignupToLogin('We could not finish sign-in automatically. Sign in to continue.');\n }\n return;\n }\n if (msg && !opts.silent) {\n msg.textContent = fallbackText || 'Still waiting on verification. Click the link in your email, then try Continue again.';\n msg.classList.remove('success');\n msg.classList.add('show', 'error');\n }\n } catch (err) {\n if (msg && !opts.silent) {\n msg.textContent = 'Could not check verification. Please try again.';\n msg.classList.remove('success');\n msg.classList.add('show', 'error');\n }\n } finally {\n verificationCheckInFlight = false;\n if (continueBtn && !opts.silent) {\n continueBtn.disabled = false;\n continueBtn.textContent = 'Continue';\n }\n }\n }\n function maybeCompleteVerificationAfterReturn() {\n if (!isVerificationStepActive()) return;\n checkVerificationSession(null, { silent: true });\n }\n async function resendVerificationEmail() {\n var btn = document.getElementById('resend-verification');\n var msg = document.getElementById('verify-msg');\n var email = pendingSignupEmail || document.getElementById('s-email').value;\n if (!email) return;\n var original = btn ? btn.textContent : '';\n if (btn) {\n btn.disabled = true;\n btn.textContent = 'Sending...';\n }\n if (msg) msg.classList.remove('show', 'error', 'success');\n try {\n var res = await fetch(__anPath('/_agent-native/auth/ba/send-verification-email'), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email: email, callbackURL: __anGetReturnPath() }),\n });\n if (res.ok) {\n if (msg) {\n msg.textContent = 'Sent a fresh verification link.';\n msg.classList.add('show', 'success');\n }\n if (btn) btn.textContent = 'Sent';\n setTimeout(function() {\n if (btn) {\n btn.disabled = false;\n btn.textContent = original;\n }\n }, 1600);\n return;\n }\n var data = await res.json().catch(function() { return {}; });\n if (msg) {\n msg.textContent = (data && (data.message || data.error)) || 'Could not resend the verification email.';\n msg.classList.add('show', 'error');\n }\n if (btn) {\n btn.disabled = false;\n btn.textContent = original;\n }\n } catch (err) {\n if (msg) {\n msg.textContent = 'Network error. Please try again.';\n msg.classList.add('show', 'error');\n }\n if (btn) {\n btn.disabled = false;\n btn.textContent = original;\n }\n }\n }\n (function initActiveTab() {\n var initial = 'signup';\n try {\n var params = new URLSearchParams(location.search);\n var qp = params.get('tab');\n var path = location.pathname;\n while (path.length > 1 && path.charAt(path.length - 1) === '/') path = path.slice(0, -1);\n if (qp === 'login' || qp === 'signup') {\n initial = qp;\n } else if (params.has('verified')) {\n initial = 'login';\n } else if (path === '/login' || path.endsWith('/login')) {\n initial = 'login';\n } else if (path === '/signup' || path.endsWith('/signup')) {\n initial = 'signup';\n } else {\n var stored = localStorage.getItem(TAB_STORAGE_KEY);\n if (stored === 'login' || stored === 'signup') initial = stored;\n }\n } catch (e) {}\n setActiveTab(initial, { persist: false });\n try {\n if (new URLSearchParams(location.search).has('verified')) {\n var msg = document.getElementById('l-msg');\n if (msg) {\n msg.textContent = 'Email verified. Finishing sign-in...';\n msg.classList.remove('error');\n msg.classList.add('show', 'success');\n }\n checkVerificationSession('Email verified. Sign in to continue.');\n }\n } catch (e) {}\n })();\n tabs.forEach(function(t) { t.addEventListener('click', function() {\n setActiveTab(t.dataset.tab, { persist: true });\n }); });\n\n document.getElementById('signup-form').addEventListener('submit', async function(e) {\n e.preventDefault();\n var form = e.currentTarget;\n var btn = form.querySelector('button[type=\"submit\"]');\n var msg = document.getElementById('s-msg');\n msg.classList.remove('show', 'error', 'success');\n var pass = document.getElementById('s-pass').value;\n var pass2 = document.getElementById('s-pass2').value;\n if (pass !== pass2) {\n msg.textContent = 'Passwords do not match';\n msg.classList.add('show', 'error');\n return;\n }\n var originalLabel = btn.textContent;\n btn.disabled = true;\n btn.textContent = 'Creating account…';\n try {\n var email = document.getElementById('s-email').value;\n var res = await fetch(__anPath('/_agent-native/auth/register'), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n email: email,\n password: pass,\n callbackURL: __anGetReturnPath(),\n }),\n });\n var data = await res.json().catch(function() { return {}; });\n if (res.ok) {\n // If email verification is required, the server won't return a session.\n // Try logging in — if it fails (unverified), show a \"check your email\" message.\n var loginRes = await fetch(__anPath('/_agent-native/auth/login'), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email: email, password: pass }),\n });\n if (loginRes.ok) {\n msg.textContent = 'Account created — signing you in…';\n msg.classList.add('show', 'success');\n window.location.reload();\n return;\n }\n btn.disabled = false;\n btn.textContent = originalLabel;\n showVerificationStep(email, pass);\n return;\n }\n msg.textContent = data.error || 'Registration failed';\n msg.classList.add('show', 'error');\n btn.disabled = false;\n btn.textContent = originalLabel;\n } catch (err) {\n msg.textContent = 'Network error — please try again';\n msg.classList.add('show', 'error');\n btn.disabled = false;\n btn.textContent = originalLabel;\n }\n });\n\n var verifyContinue = document.getElementById('verify-continue');\n if (verifyContinue) verifyContinue.addEventListener('click', function(e) {\n e.preventDefault();\n checkVerificationSession();\n });\n window.addEventListener('focus', maybeCompleteVerificationAfterReturn);\n document.addEventListener('visibilitychange', function() {\n if (document.visibilityState === 'visible') maybeCompleteVerificationAfterReturn();\n });\n var resendBtn = document.getElementById('resend-verification');\n if (resendBtn) resendBtn.addEventListener('click', function(e) {\n e.preventDefault();\n resendVerificationEmail();\n });\n var backToSignup = document.getElementById('back-to-signup');\n if (backToSignup) backToSignup.addEventListener('click', function(e) {\n e.preventDefault();\n setActiveTab('signup', { persist: true });\n var email = document.getElementById('s-email');\n setTimeout(function() { if (email) email.focus(); }, 0);\n });\n\n var forgotLink = document.getElementById('forgot-link');\n var backToLogin = document.getElementById('back-to-login');\n if (forgotLink) forgotLink.addEventListener('click', function(e) {\n e.preventDefault();\n document.getElementById('login-form').classList.remove('active');\n document.getElementById('forgot-form').classList.add('active');\n var sub = document.getElementById('subtitle');\n if (sub) sub.textContent = 'Reset your password';\n var heading = document.getElementById('heading');\n if (heading) heading.textContent = 'Reset password';\n var fEmail = document.getElementById('f-email');\n var lEmail = document.getElementById('l-email');\n if (lEmail && lEmail.value) fEmail.value = lEmail.value;\n setTimeout(function() { fEmail.focus(); }, 0);\n });\n if (backToLogin) backToLogin.addEventListener('click', function(e) {\n e.preventDefault();\n document.getElementById('forgot-form').classList.remove('active');\n document.getElementById('login-form').classList.add('active');\n var sub = document.getElementById('subtitle');\n if (sub) sub.textContent = subtitles.login;\n var heading = document.getElementById('heading');\n if (heading) heading.textContent = headings.login;\n });\n\n var forgotForm = document.getElementById('forgot-form');\n if (forgotForm) forgotForm.addEventListener('submit', async function(e) {\n e.preventDefault();\n var btn = e.currentTarget.querySelector('button[type=\"submit\"]');\n var msg = document.getElementById('f-msg');\n msg.classList.remove('show', 'error', 'success');\n var original = btn.textContent;\n btn.disabled = true;\n btn.textContent = 'Sending…';\n try {\n var email = document.getElementById('f-email').value;\n var res = await fetch(__anPath('/_agent-native/auth/ba/request-password-reset'), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email: email }),\n });\n if (res.ok) {\n msg.textContent = 'If that email exists, a reset link is on its way.';\n msg.classList.add('show', 'success');\n btn.textContent = 'Sent';\n return;\n }\n var data = await res.json().catch(function() { return {}; });\n msg.textContent = (data && (data.message || data.error)) || 'Could not send reset email.';\n msg.classList.add('show', 'error');\n btn.disabled = false;\n btn.textContent = original;\n } catch (err) {\n msg.textContent = 'Network error — please try again';\n msg.classList.add('show', 'error');\n btn.disabled = false;\n btn.textContent = original;\n }\n });\n\n document.getElementById('login-form').addEventListener('submit', async function(e) {\n e.preventDefault();\n var form = e.currentTarget;\n var btn = form.querySelector('button[type=\"submit\"]');\n var msg = document.getElementById('l-msg');\n msg.classList.remove('show', 'success');\n msg.classList.add('error');\n var originalLabel = btn.textContent;\n btn.disabled = true;\n btn.textContent = 'Signing in…';\n try {\n var res = await fetch(__anPath('/_agent-native/auth/login'), {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n email: document.getElementById('l-email').value,\n password: document.getElementById('l-pass').value,\n }),\n });\n if (res.ok) {\n window.location.reload();\n return;\n }\n var data = await res.json().catch(function() { return {}; });\n msg.textContent = data.error || 'Invalid email or password';\n msg.classList.add('show');\n btn.disabled = false;\n btn.textContent = originalLabel;\n } catch (err) {\n msg.textContent = 'Network error — please try again';\n msg.classList.add('show');\n btn.disabled = false;\n btn.textContent = originalLabel;\n }\n });\n`\n}\n${\n showGoogle\n ? `\n async function signInWithGoogle() {\n if (__anShouldShowGoogleNotice()) {\n __anShowGoogleNotice();\n return;\n }\n return __anStartGoogleSignIn();\n }\n async function __anStartGoogleSignIn() {\n var btn = document.getElementById('google-btn');\n var err = document.getElementById('google-err');\n var ret = __anGetReturnPath();\n btn.disabled = true;\n err.classList.remove('show');\n if (__anResolveAuthFlow() === 'popup') {\n __anStartPopupOAuth(ret, btn, err);\n return;\n }\n if (__anIsAgentNativeDesktop()) {\n __anStartNativeDesktopOAuth(ret, btn, err);\n return;\n }\n if (__anIsBuilderPreview()) {\n var flowId = __anNewOAuthFlowId();\n __anStartRedirectOAuth(ret, btn, err, flowId, 'Opening Google sign-in redirect from Builder preview');\n return;\n }\n try {\n var authUrl = __anGoogleAuthUrlPath() + '?return=' + encodeURIComponent(ret);\n var res = await fetch(authUrl);\n var data = await res.json();\n if (data.url) {\n __anOpenOAuthUrl(data.url);\n } else {\n err.textContent = data.message || 'Google OAuth is not configured.';\n err.classList.add('show');\n btn.disabled = false;\n }\n } catch (e) {\n err.textContent = 'Failed to connect. Please try again.';\n err.classList.add('show');\n btn.disabled = false;\n }\n }`\n : \"\"\n}\n${\n googleSignInNotice\n ? `\n window.__anGoogleNoticeAccepted = false;\n function __anShouldShowGoogleNotice() {\n var notice = document.getElementById('google-preflight');\n if (!notice || window.__anGoogleNoticeAccepted) return false;\n var host = notice.getAttribute('data-host');\n return !host || window.location.hostname === host;\n }\n function __anShowGoogleNotice() {\n var notice = document.getElementById('google-preflight');\n if (!notice) return;\n notice.classList.add('show');\n var continueBtn = document.getElementById('google-preflight-continue');\n if (continueBtn) continueBtn.focus();\n }\n function __anHideGoogleNotice() {\n var notice = document.getElementById('google-preflight');\n if (notice) notice.classList.remove('show');\n }\n function __anAcceptGoogleNotice() {\n window.__anGoogleNoticeAccepted = true;\n __anHideGoogleNotice();\n __anStartGoogleSignIn();\n }`\n : `\n function __anShouldShowGoogleNotice() { return false; }`\n}\n${starfieldScript}\n${\n runLocalCommand\n ? `\n function __anToggleRunLocalCommand() {\n var panel = document.getElementById('run-local-panel');\n var button = document.getElementById('run-local-button');\n if (!panel || !button) return;\n var nextOpen = panel.hasAttribute('hidden');\n if (nextOpen) {\n panel.removeAttribute('hidden');\n } else {\n panel.setAttribute('hidden', '');\n }\n button.setAttribute('aria-expanded', String(nextOpen));\n }\n function __anCopyRunLocalCommand() {\n var panel = document.getElementById('run-local-panel');\n var button = document.getElementById('copy-run-local');\n if (!panel || !button) return;\n var command = panel.getAttribute('data-command') || '';\n var original = button.textContent || 'Copy command';\n function markCopied() {\n button.textContent = 'Copied';\n setTimeout(function() { button.textContent = original; }, 1600);\n }\n if (navigator.clipboard && navigator.clipboard.writeText) {\n navigator.clipboard.writeText(command).then(markCopied).catch(function() {});\n }\n }`\n : \"\"\n}\n</script>\n</body>\n</html>`;\n}\n\n/** @deprecated Use getOnboardingHtml() instead */\nexport const ONBOARDING_HTML = getOnboardingHtml();\n\n/**\n * HTML for the password reset page — shown when the user clicks the link in\n * their reset email. Posts `{ newPassword, token }` to Better Auth's\n * `/reset-password` endpoint, then redirects to the login page.\n */\nexport function getResetPasswordHtml(): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\">\n<title>Reset password</title>\n<link rel=\"icon\" type=\"image/svg+xml\" href=\"${withAppBasePath(\"/favicon.svg\")}\">\n<link rel=\"apple-touch-icon\" href=\"${withAppBasePath(\"/icon-180.svg\")}\">\n<style>\n *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n body { font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif; background: #0a0a0a; color: #e5e5e5; display: flex; align-items: center; justify-content: center; min-height: 100vh; padding: 1rem; }\n .card { width: 100%; max-width: 400px; padding: 2rem; background: #141414; border: 1px solid rgba(255,255,255,0.08); border-radius: 12px; }\n h1 { font-size: 1.25rem; font-weight: 600; margin-bottom: 0.25rem; color: #fff; }\n .subtitle { font-size: 0.8125rem; color: #888; margin-bottom: 1.5rem; }\n label { display: block; font-size: 0.8125rem; color: #888; margin-bottom: 0.375rem; }\n input { width: 100%; padding: 0.5rem 0.75rem; background: transparent; border: 1px solid rgba(255,255,255,0.12); border-radius: 6px; color: #e5e5e5; font-size: 0.875rem; outline: none; margin-bottom: 0.875rem; }\n input:focus { border-color: rgba(255,255,255,0.3); box-shadow: 0 0 0 1px rgba(255,255,255,0.1); }\n input::placeholder { color: #555; }\n button[type=\"submit\"] { width: 100%; margin-top: 0.25rem; padding: 0.5rem; background: #fff; color: #000; border: none; border-radius: 6px; font-size: 0.875rem; font-weight: 500; cursor: pointer; }\n button[type=\"submit\"]:hover { background: #e5e5e5; }\n button[type=\"submit\"]:disabled { opacity: 0.5; cursor: not-allowed; }\n .msg { margin-top: 0.75rem; font-size: 0.8125rem; display: none; }\n .msg.error { color: #f87171; }\n .msg.success { color: #4ade80; }\n .msg.show { display: block; }\n .back { display: inline-block; margin-top: 1rem; font-size: 0.75rem; color: #888; text-decoration: none; }\n .back:hover { color: #bbb; }\n</style>\n</head>\n<body>\n<div class=\"card\">\n <h1>Choose a new password</h1>\n <p class=\"subtitle\">Set a new password for your account.</p>\n <form id=\"reset-form\">\n <label for=\"p1\">New password</label>\n <input id=\"p1\" type=\"password\" autocomplete=\"new-password\" autofocus placeholder=\"At least 8 characters\" required minlength=\"8\" />\n <label for=\"p2\">Confirm password</label>\n <input id=\"p2\" type=\"password\" autocomplete=\"new-password\" placeholder=\"Confirm password\" required minlength=\"8\" />\n <button type=\"submit\">Save new password</button>\n <p class=\"msg\" id=\"msg\"></p>\n </form>\n <a class=\"back\" id=\"back-link\" href=\"/\">Back to sign in</a>\n</div>\n<script>\n (function() {\n // Derive the app's base path so apps mounted under a prefix\n // (e.g. /mail, /calendar) get sent home instead of to the root domain.\n var RESET_PATH = '/_agent-native/auth/reset';\n var pathname = window.location.pathname;\n var idx = pathname.indexOf(RESET_PATH);\n var basePath = (idx >= 0 ? pathname.slice(0, idx) : '') || '';\n var homeHref = basePath + '/';\n var backLink = document.getElementById('back-link');\n if (backLink) backLink.setAttribute('href', homeHref);\n var params = new URLSearchParams(location.search);\n var token = params.get('token') || '';\n var msg = document.getElementById('msg');\n if (!token) {\n msg.textContent = 'Missing or invalid reset token. Request a new reset link.';\n msg.classList.add('show', 'error');\n document.getElementById('reset-form').style.display = 'none';\n return;\n }\n document.getElementById('reset-form').addEventListener('submit', async function(e) {\n e.preventDefault();\n var btn = e.currentTarget.querySelector('button[type=\"submit\"]');\n var p1 = document.getElementById('p1').value;\n var p2 = document.getElementById('p2').value;\n msg.classList.remove('show', 'error', 'success');\n if (p1 !== p2) {\n msg.textContent = 'Passwords do not match';\n msg.classList.add('show', 'error');\n return;\n }\n var original = btn.textContent;\n btn.disabled = true;\n btn.textContent = 'Saving…';\n try {\n var res = await fetch(basePath + '/_agent-native/auth/ba/reset-password', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ newPassword: p1, token: token }),\n });\n if (res.ok) {\n msg.textContent = 'Password updated — redirecting to sign in…';\n msg.classList.add('show', 'success');\n setTimeout(function() { window.location.href = homeHref; }, 1200);\n return;\n }\n var data = await res.json().catch(function() { return {}; });\n msg.textContent = (data && (data.message || data.error)) || 'Reset failed. The link may have expired — request a new one.';\n msg.classList.add('show', 'error');\n btn.disabled = false;\n btn.textContent = original;\n } catch (err) {\n msg.textContent = 'Network error — please try again';\n msg.classList.add('show', 'error');\n btn.disabled = false;\n btn.textContent = original;\n }\n });\n })();\n</script>\n</body>\n</html>`;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.20.5",
3
+ "version": "0.20.7",
4
4
  "type": "module",
5
5
  "description": "Framework for agent-native application development — where AI agents and UI share state via files",
6
6
  "license": "MIT",