import { chromium } from 'playwright' import { runtimeConfig } from '../../config/runtime.js' import { buildChromiumLaunchOptions as buildChromiumLaunchOptionsBase, resolveBrowserLaunchOptions as resolveBrowserLaunchOptionsBase, } from './session-browser-config.js' import { CHROME_PATH } from './session-service-config.js' type BrowserLike = { on: (event: 'disconnected', listener: () => void) => void close: () => Promise newContext: (options?: Record) => Promise } type SessionServiceErrorOptions = { statusCode?: number errorCode?: string } let browserPromise: Promise | null = null export class SessionServiceError extends Error { statusCode: number errorCode: string constructor(message: string, { statusCode = 500, errorCode = 'session_error' }: SessionServiceErrorOptions = {}) { super(message) this.name = 'SessionServiceError' this.statusCode = statusCode this.errorCode = errorCode } } export async function warmupTencentBrowser() { const browserLaunch = resolveBrowserLaunchOptions() if (!browserLaunch.prewarm) { return { warmed: false, reason: 'disabled', browserLaunch, } } await ensureBrowser() return { warmed: true, reason: 'ready', browserLaunch, } } export async function ensureBrowser(): Promise { if (!browserPromise) { const launchOptions = resolveBrowserLaunchOptions() browserPromise = (chromium.launch(buildChromiumLaunchOptions(launchOptions)) as Promise) .then((browser) => { browser.on('disconnected', () => { browserPromise = null }) return browser }) .catch((error) => { browserPromise = null throw error }) } return browserPromise } export function resolveBrowserLaunchOptions() { return resolveBrowserLaunchOptionsBase({ browserConfig: runtimeConfig.browser, chromePath: CHROME_PATH, }) } export async function closeBrowserIfIdle({ activeSessionCount = 0 }: { activeSessionCount?: number } = {}): Promise { if (activeSessionCount > 0 || !browserPromise) { return } if (resolveBrowserLaunchOptions().keepAlive) { return } try { const browser = await browserPromise await browser.close() } catch { // ignore browser close failures } finally { browserPromise = null } } function buildChromiumLaunchOptions(launchOptions: ReturnType) { return buildChromiumLaunchOptionsBase(launchOptions, { chromePath: CHROME_PATH }) }