Skip to main content
Glama
browser.ts2.92 kB
import puppeteer, { Browser } from 'puppeteer'; import { Result, ok, err, browserNotLaunched, browserCrashed } from './errors.js'; /** * Browser state - module-level singleton */ interface BrowserState { browser: Browser | null; isLaunching: boolean; } const state: BrowserState = { browser: null, isLaunching: false, }; /** * Get browser configuration from environment */ function getConfig() { return { headless: process.env.HEADLESS !== 'false', timeout: parseInt(process.env.TIMEOUT ?? '30000', 10), }; } /** * Launch the browser if not already running * @returns Result with the browser instance */ export async function launchBrowser(): Promise<Result<Browser>> { if (state.browser && state.browser.connected) { return ok(state.browser); } if (state.isLaunching) { // Wait for existing launch to complete await waitForBrowser(); if (state.browser && state.browser.connected) { return ok(state.browser); } return err(browserNotLaunched()); } state.isLaunching = true; try { const config = getConfig(); state.browser = await puppeteer.launch({ headless: config.headless, args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-gpu', ], }); // Handle browser disconnect state.browser.on('disconnected', () => { state.browser = null; }); state.isLaunching = false; return ok(state.browser); } catch (error) { state.isLaunching = false; const message = error instanceof Error ? error.message : String(error); return err(browserCrashed(`Failed to launch browser: ${message}`)); } } /** * Wait for browser to finish launching */ async function waitForBrowser(): Promise<void> { const maxWait = 30000; const startTime = Date.now(); while (state.isLaunching && Date.now() - startTime < maxWait) { await sleep(100); } } /** * Sleep for specified milliseconds */ function sleep(ms: number): Promise<void> { return new Promise(resolve => setTimeout(resolve, ms)); } /** * Get the browser instance, launching if needed * @returns Result with the browser instance */ export async function getBrowser(): Promise<Result<Browser>> { if (state.browser && state.browser.connected) { return ok(state.browser); } return launchBrowser(); } /** * Check if browser is connected */ export function isBrowserConnected(): boolean { return state.browser !== null && state.browser.connected; } /** * Close the browser */ export async function closeBrowser(): Promise<void> { if (state.browser) { try { await state.browser.close(); } catch { // Ignore close errors - browser may already be gone } state.browser = null; } } /** * Get the default timeout from config */ export function getDefaultTimeout(): number { return getConfig().timeout; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/andytango/puppeteer-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server