import type { Browser, LaunchOptions, Page } from "puppeteer-core"; import { getStream } from "puppeteer-stream"; import type { Nullable } from "../types/index.js"; /** * Returns true if graceful shutdown is in progress. */ export declare function isGracefulShutdown(): boolean; /** * Sets the graceful shutdown flag. Call this at the start of shutdown, before terminating streams, so that page close errors are suppressed. */ export declare function setGracefulShutdown(value: boolean): void; /** * Login status information returned by getLoginStatus(). */ export interface LoginStatus { active: boolean; startTime: Nullable; url: Nullable; } /** * Computes the current system status and emits it to SSE subscribers. Called when browser state changes significantly or when streams are added/removed. */ export declare function emitCurrentSystemStatus(): Promise; /** * Registers a page as managed by PrismCast. This should be called immediately after creating a page via browser.newPage(). Registered pages are tracked for stale * page cleanup, while unregistered pages (manually opened, site popups, etc.) are left alone. * * Each registered page receives a unique ID that persists for the page's lifetime. This ID is used for comparison and staleness tracking, avoiding potential * issues with Page object reference identity. * @param page - The Puppeteer Page to register. */ export declare function registerManagedPage(page: Page): void; /** * Unregisters a page from PrismCast's management. This should be called when a page is being closed intentionally (during stream cleanup). Unregistering prevents the * stale page cleanup from racing with intentional page closure. * @param page - The Puppeteer Page to unregister. */ export declare function unregisterManagedPage(page: Page): void; /** * Ensures the data directory exists, creating it if necessary. This should be called during application startup before any operations that depend on the data * directory (like browser launch or extension preparation). * * The data directory stores: * - Chrome profile data (cookies, local storage, session state) * - Extension files (when running as a packaged executable) */ export declare function ensureDataDirectory(): Promise; /** * Ensures a clean slate for browser launch by terminating any stale Chrome processes and removing orphaned profile lock files. Chrome locks its profile directory * while running, and if a previous instance crashed without releasing the lock, we cannot launch a new browser with the same profile. This function uses pkill to * find and terminate any Chrome processes whose command line contains our profile directory path, then polls pgrep to verify the processes have actually exited. * After process cleanup, it removes stale lock files (SingletonLock, SingletonCookie, SingletonSocket) and DevToolsActivePort from the profile directory. * * The termination strategy escalates from SIGTERM to SIGKILL. SIGTERM is sent first, giving Chrome up to 5 seconds to flush its profile databases (LevelDB, * extension state, session storage) and exit cleanly. If Chrome does not exit, SIGKILL is sent as a fallback. This escalation is critical when called from the * process exit handler — Chrome may be running normally (e.g., after a capture probe timeout), and an immediate SIGKILL would corrupt its profile databases, * poisoning the Docker volume for subsequent container restarts. * * The file cleanup is essential for Docker deployments. Container restarts destroy Chrome processes without giving them a chance to release profile locks, but the * lock files persist in the mounted volume. Without removing them, Chrome cannot start in the new container, causing a crash loop. * * This is called at startup before launching the browser and after closeBrowser() during shutdown. It's safe to call even when no stale processes or files exist. */ export declare function killStaleChrome(): void; /** * Locates the Google Chrome executable on the system. The CHROME_BIN environment variable takes precedence, allowing operators to specify a non-standard * installation. Otherwise, we search common installation paths across macOS, Linux, and Windows. * * @returns Path to the Chrome executable. * @throws If no Chrome installation is found. */ export declare function getExecutablePath(): string; /** * Assembles the configuration options for launching Chrome with Puppeteer. These options are critical for reliable streaming: * * - Chrome flags configure the browser for unattended video playback without user interaction * - Ignored default args prevent Puppeteer from disabling features we need (extensions, audio, component updates) * - A persistent user data directory retains cookies and login state across restarts * - Pipe mode provides a faster, more reliable connection than WebSocket * @returns Puppeteer launch options. */ export declare function buildLaunchOptions(): LaunchOptions; /** * Provides access to the shared browser instance, launching one if needed. The browser is a shared resource used by all streaming sessions. This function handles: * * - Returning the existing browser if it's still connected * - Launching a new browser if none exists or the previous one disconnected * - Serializing concurrent callers so only one launch occurs at a time * - Waiting for the puppeteer-stream extension to initialize * - Setting up disconnect handlers for crash recovery * @returns The browser instance. * @throws If the browser cannot be launched. */ export declare function getCurrentBrowser(): Promise; /** * Returns the Chrome version string captured when the browser launched, or null if the browser is not connected. * @returns The Chrome version string (e.g., "Chrome/144.0.7559.110") or null. */ export declare function getChromeVersion(): Nullable; /** * Checks if the browser is currently connected and usable. This is a synchronous check that can be used before attempting browser operations. * @returns True if the browser is connected and ready for use, false otherwise. */ export declare function isBrowserConnected(): boolean; /** * Resizes the browser window to the effective viewport and minimizes it. This function combines viewport sizing with minimization to ensure the window is * properly sized before being minimized. The resize uses the effective viewport from getEffectiveViewport(), which accounts for display size constraints and * preset degradation. * * To avoid issues with creating temporary pages (which can cause the window to restore on macOS), we prefer using an existing page if one is available. Only if * no pages exist do we create a temporary page. */ export declare function minimizeBrowserWindow(): Promise; /** * Gets all open browser pages (tabs). This is used by the health check endpoint to report page count and by stale page cleanup to find orphaned pages. * @returns Array of pages, or empty array if the browser is not connected. */ export declare function getBrowserPages(): Promise; /** * Closes the browser and cleans up resources. This is called during graceful shutdown to ensure Chrome exits cleanly. After this call, the browser reference is * cleared and any subsequent stream requests will launch a fresh browser. * * The function uses a two-stage approach to ensure Chrome actually exits: * 1. Try browser.close() with a 5-second timeout (DevTools Protocol graceful close) * 2. Run killStaleChrome() to catch anything Stage 1 missed, using SIGTERM→SIGKILL escalation to give Chrome a chance to flush its profile databases */ export declare function closeBrowser(): Promise; /** * Starts login mode by opening a new browser tab with the specified URL and un-minimizing the browser window. The user can then authenticate with their TV * provider in the visible browser. * * Login mode blocks new stream requests until it ends (via endLoginMode, tab close detection, or timeout). * @param url - The URL to navigate to for authentication. * @returns Object indicating success or failure with optional error message. */ export declare function startLoginMode(url: string): Promise<{ error?: string; success: boolean; }>; /** * Ends login mode by closing the login tab (if still open) and re-minimizing the browser window. This function is idempotent - it's safe to call multiple times * or when login mode is not active. * * Called by: * - User clicking "Done" in the web UI (POST /auth/done) * - Tab close detection (user closes the tab manually) * - 15-minute timeout * - Browser disconnect handler (cleanup) */ export declare function endLoginMode(): Promise; /** * Returns whether login mode is currently active. Used by the stream handler to block new stream requests during login. * @returns True if login mode is active, false otherwise. */ export declare function isLoginModeActive(): boolean; /** * Returns the current login status including whether active, the URL being used, and when login started. Used by the /auth/status API endpoint. * @returns Login status object. */ export declare function getLoginStatus(): LoginStatus; /** * Returns the active login page if login mode is currently active. Used by the profile test flow to evaluate CSS selectors against the live page DOM. * @returns The login page, or null if login mode is not active. */ export declare function getLoginPage(): Nullable; /** * Cleans up browser pages that are not associated with active streams. This function runs periodically to catch any pages that were not properly closed during * stream termination. * * The cleanup uses a multi-stage filtering process: * 1. Only consider pages we created (in managedPageIds) * 2. Exclude pages associated with active streams * 3. Apply a grace period before closing (to handle race conditions) * 4. Preserve at least one page to keep the browser alive */ export declare function cleanupStalePages(): Promise; /** * Starts the periodic stale page cleanup interval. This should be called once during server startup, after the browser is initialized. The interval runs * indefinitely until stopStalePageCleanup() is called (typically during graceful shutdown). */ export declare function startStalePageCleanup(): void; /** * Stops the stale page cleanup interval. This should be called during graceful shutdown to prevent the cleanup from running after we've started shutting down * the browser and streams. */ export declare function stopStalePageCleanup(): void; /** * Starts the periodic browser restart eligibility check. This should be called once during server startup, after the browser is initialized. The interval runs * indefinitely until stopBrowserRestartChecking() is called (typically during graceful shutdown). */ export declare function startBrowserRestartChecking(): void; /** * Stops the browser restart checking interval and cancels any pending quiet timer. This should be called during graceful shutdown to prevent a restart from * racing with server shutdown. */ export declare function stopBrowserRestartChecking(): void; /** * Extracts the Puppeteer Stream extension files when running as a packaged executable. This copies the extension files from within the packaged binary to the * filesystem where Chrome can load them. * * When running from source (not packaged), this function does nothing - puppeteer-stream can load the extension directly from node_modules. * @throws If extension extraction fails. */ export declare function prepareExtension(): Promise; export { getStream };