/** * Read the Firebase ID token the dashboard persisted after login. * * The frontend uses `browserLocalPersistence`, which the Firebase JS SDK * implements on `localStorage` under a `firebase:authUser::[DEFAULT]` * key whose JSON value carries `stsTokenManager.accessToken`. We scan for any * such key (so we never hard-code the project apiKey) and fall back to the * IndexedDB persistence layout (`firebaseLocalStorageDb` / * `firebaseLocalStorage`) in case a build switches persistence. Returns the * token string, or null when the user has not finished logging in yet. * * The CDP-launched Chrome reuses a PERSISTENT profile dir across runs, so a * stale `firebase:authUser:*` entry from an earlier (now-expired, ~1h TTL) * session is often still sitting in storage the instant the page loads — * before the developer has clicked anything. Returning that immediately * makes the poll "succeed" on tick one, closing the tab before the developer * can sign in, and the captured token then fails backend verification. So * every candidate's JWT `exp` claim is checked here (in-page, where `atob` is * available) and stale ones are skipped — the loop keeps polling until a * genuinely fresh token shows up from an interactive sign-in. * * Evaluated in-page with `awaitPromise` so the async IndexedDB branch resolves. */ export declare const EXTRACT_TOKEN_JS = "(async () => {\n\tconst isFresh = (token) => {\n\t\ttry {\n\t\t\tconst payload = JSON.parse(\n\t\t\t\tatob(token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/'))\n\t\t\t)\n\t\t\t// No exp claim to check \u2014 don't block a token we can't evaluate.\n\t\t\tif (typeof payload.exp !== 'number') return true\n\t\t\t// 60s buffer so a token that's about to expire isn't treated as fresh.\n\t\t\treturn payload.exp * 1000 > Date.now() + 60000\n\t\t} catch (e) {\n\t\t\treturn true\n\t\t}\n\t}\n\ttry {\n\t\tfor (let i = 0; i < localStorage.length; i++) {\n\t\t\tconst k = localStorage.key(i)\n\t\t\tif (k && k.indexOf('firebase:authUser:') === 0) {\n\t\t\t\tconst v = JSON.parse(localStorage.getItem(k) || 'null')\n\t\t\t\tconst t = v && v.stsTokenManager && v.stsTokenManager.accessToken\n\t\t\t\tif (t && isFresh(t)) return t\n\t\t\t}\n\t\t}\n\t} catch (e) {}\n\ttry {\n\t\treturn await new Promise((resolve) => {\n\t\t\tconst req = indexedDB.open('firebaseLocalStorageDb')\n\t\t\treq.onerror = () => resolve(null)\n\t\t\treq.onsuccess = () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst db = req.result\n\t\t\t\t\tif (!db.objectStoreNames.contains('firebaseLocalStorage')) {\n\t\t\t\t\t\tresolve(null); return\n\t\t\t\t\t}\n\t\t\t\t\tconst store = db\n\t\t\t\t\t\t.transaction('firebaseLocalStorage', 'readonly')\n\t\t\t\t\t\t.objectStore('firebaseLocalStorage')\n\t\t\t\t\tconst all = store.getAll()\n\t\t\t\t\tall.onerror = () => resolve(null)\n\t\t\t\t\tall.onsuccess = () => {\n\t\t\t\t\t\tfor (const row of (all.result || [])) {\n\t\t\t\t\t\t\tconst m = row && row.value && row.value.stsTokenManager\n\t\t\t\t\t\t\tif (m && m.accessToken && isFresh(m.accessToken)) {\n\t\t\t\t\t\t\t\tresolve(m.accessToken); return\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresolve(null)\n\t\t\t\t\t}\n\t\t\t\t} catch (e) { resolve(null) }\n\t\t\t}\n\t\t})\n\t} catch (e) { return null }\n})()"; export interface CdpLoginResult { token: string; /** True when we launched (and then closed) a dedicated Chrome just for * login; false when we attached to an already-running browser and only * closed the tab we opened. */ closedBrowser: boolean; } export interface LocalDashboardBrowser { mode: 'dedicated' | 'attach'; port: number; } /** * Accept only the two loopback Chrome modes used for legacy dashboard login. * Config files are user-editable, so validate at runtime rather than trusting * the TypeScript shape. Remote Builder, container, custom-CDP, and URL inputs * are deliberately unsupported here. */ export declare function localDashboardBrowser(value: unknown): LocalDashboardBrowser; /** * Open the dashboard login page in a local Chrome via loopback CDP, wait for * the developer to finish signing in, read the resulting Firebase ID token * from page storage, then clean up. This never uses a Builder, container, * custom-CDP, or shared browser. If we launch a dedicated Chrome, we close the * whole browser afterward; if we attach to an existing local Chrome, we close * only the tab we opened. */ export declare function captureFirebaseTokenViaCdp(opts: { loginUrl?: string; timeoutMs?: number; pollMs?: number; }): Promise;