import puppeteer from 'puppeteer';
import type { Page } from 'puppeteer';
import type { BrowserState, ConsoleLog, NetworkRequest } from './types.js';
export const browserState: BrowserState = {
browser: null,
page: null,
consoleLogs: [],
networkRequests: [],
headless: true, // Por padrão headless, mas pode ser alterado
};
export async function initBrowser(
headless: boolean = true,
width: number = 1920,
height: number = 1080
): Promise<Page> {
// IMPORTANTE: Nunca fechar o browser se ele já estiver aberto
// Isso mantém a sessão ativa (cookies, localStorage, login, etc.)
// Se o usuário quiser mudar o modo headless, deve fechar manualmente primeiro
if (!browserState.browser) {
browserState.headless = headless;
browserState.browser = await puppeteer.launch({
headless: headless,
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-web-security',
'--disable-features=IsolateOrigins,site-per-process',
`--window-size=${width},${height}`, // Define tamanho da janela do browser
],
defaultViewport: {
width,
height,
},
});
}
if (!browserState.page) {
// Usa a página padrão que o browser já criou (evita duplicar abas)
const pages = await browserState.browser.pages();
browserState.page = pages[0];
// Configurar viewport (tamanho da área de renderização)
await browserState.page.setViewport({ width, height });
// Capturar console logs
browserState.page.on('console', (msg) => {
const log: ConsoleLog = {
type: msg.type(),
text: msg.text(),
timestamp: new Date().toISOString(),
};
browserState.consoleLogs.push(log);
});
// Capturar erros de página
browserState.page.on('pageerror', (error) => {
const log: ConsoleLog = {
type: 'error',
text: error.message,
stack: error.stack,
timestamp: new Date().toISOString(),
};
browserState.consoleLogs.push(log);
});
// Monitorar requisições de rede
browserState.page.on('request', (request) => {
const networkRequest: NetworkRequest = {
type: 'request',
url: request.url(),
method: request.method(),
resourceType: request.resourceType(),
timestamp: new Date().toISOString(),
};
browserState.networkRequests.push(networkRequest);
});
browserState.page.on('response', (response) => {
const networkRequest: NetworkRequest = {
type: 'response',
url: response.url(),
status: response.status(),
statusText: response.statusText(),
timestamp: new Date().toISOString(),
};
browserState.networkRequests.push(networkRequest);
});
}
return browserState.page;
}
export function clearConsoleLogs(): void {
browserState.consoleLogs = [];
}
export function clearNetworkRequests(): void {
browserState.networkRequests = [];
}
export function getBrowserStatus(): {
isOpen: boolean;
headless: boolean;
currentUrl: string | null;
pageTitle: string | null;
} {
return {
isOpen: browserState.browser !== null && browserState.page !== null,
headless: browserState.headless,
currentUrl: browserState.page ? browserState.page.url() : null,
pageTitle: null, // Será preenchido de forma assíncrona se necessário
};
}
export async function closeBrowser(): Promise<void> {
if (browserState.browser) {
await browserState.browser.close();
browserState.browser = null;
browserState.page = null;
}
}