import type { PwBrowser, PwContext } from './playwright-loader.js'; export interface BrowserSessionManagerOptions { readonly projectRoot: string; readonly sessionId: string; } export interface WebTextResult { readonly text: string; readonly truncated: boolean; readonly droppedBytes: number; } export interface WebSnapResult { readonly snapshot: string; readonly droppedNodes: number; readonly depthCapped: boolean; readonly nodeCapped: boolean; readonly truncated: boolean; readonly droppedBytes: number; } export interface WebMetricsResult { readonly available: boolean; readonly reason: string | null; readonly values: Readonly> | null; } /** One dispatch whose storage state could not be persisted at teardown. */ export interface StateWriteFailure { readonly dispatchId: string; readonly reason: string; } /** * Resolve with `work`, or reject once the step has taken longer than the step * budget. The late settlement of `work` is consumed here, so a step that * finishes after its deadline cannot become an unhandled rejection. */ export declare function boundedTeardownStep(work: Promise, label: string): Promise; export interface CloseAllResult { /** Contexts closed during this call. */ readonly closedContexts: number; /** Never silent: teardown still proceeds, but the caller can report this. */ readonly stateWriteFailures: readonly StateWriteFailure[]; } export declare class BrowserSessionManager { private readonly browser; private readonly projectRoot; private readonly sessionId; private readonly sessions; constructor(browser: PwBrowser, options: BrowserSessionManagerOptions); /** * The context for a dispatch, created on first use and reused afterwards. * * `profile` names a user-level login profile (`peaks web login --profile`) to * build the context from. When given it REPLACES the dispatch's own state: a * context holds one storage state, so "start from the profile" and "start from * the per-dispatch state" are alternatives, not layers. * * The profile is **READ-ONLY**. This module reads it into the context and * never writes, refreshes or trims it — write-back is an undecided design * question (it would keep a login fresh without re-running `login`, and it * would also let an automated browse silently rewrite a user-level credential * file), so this slice does not decide it. `closeAll` still persists the * dispatch's OWN `pw-profiles//storageState.json`; nothing under * `~/.peaks/web-profiles/` is ever created or modified from here. * * The name is validated HERE and not only in the CLI, because it arrives off * the wire: `resolveProfileName` is the SAME resolver `login` uses (folds to * lower case, refuses a traversing name, a leading dot, a device name), and * the read is anchored with `assertUnder`. A profile that does not exist is a * NAMED failure — falling through to an unauthenticated context would answer * "open this with my profile" with a logged-out browser and no signal. */ contextFor(dispatchId: string, rawProfile?: string): Promise; open(dispatchId: string, url: string, profile?: string): Promise<{ url: string; title: string; }>; text(dispatchId: string, selector?: string): Promise; /** * Primary path is `locator.ariaSnapshotJSON()` (Playwright 1.63, our exact * pin). We do NOT re-derive the tree from the YAML form: parsing YAML by * indentation is the fragile option, and under an exact pin the JSON API is * always present (tech-doc §4.1/§4.2). A missing API is an explicit error * rather than a silent degradation. */ snap(dispatchId: string, selector?: string): Promise; click(dispatchId: string, selector: string): Promise<{ result: string; }>; /** * Screenshot to an absolute path under `web/`. Always an explicit `path`: * never the Playwright default, and never a Buffer we write ourselves * (tech-doc §7.2 rule 3). */ shot(dispatchId: string, selector?: string): Promise<{ path: string; bytes: number; }>; /** * Core Web Vitals for the dispatch's page. Returns `available: false` with a * reason — never fabricated zeros — when there is no observation window * (orchestrator decision C4), and never echoes the page's object back: only * the three contract keys, only finite numbers (R2). */ metrics(dispatchId: string): Promise; /** * Persist each dispatch's storage state, then close every context exactly * once. A state file that cannot be written must not block shutdown — but it * must be reported: a silent skip here kills S4's persistence with no signal * anywhere (R1). */ closeAll(): Promise; private pageFor; }