import { ProjectWorker, type ProjectWorkerOptions } from "./project-worker.js"; import type { RenderSSRRequest, WorkerPoolConfig, WorkerRequest, WorkerResponse } from "./worker-types.js"; /** @internal Construction seam for deterministic lifecycle tests. */ export interface WorkerPoolDependencies { /** * Test/integration seam for constructing the managed worker. Production uses * ProjectWorker directly. */ createWorker?: (options: ProjectWorkerOptions) => ProjectWorker; /** Test seam for deterministic host-memory pressure behavior. */ getHeapUsedPercent?: () => number; /** Test seam for the extension contract resolved only on SSR admission. */ resolveIsolatedSsrRendererProvider?: () => unknown; } export declare class WorkerPool { private pool; private workerShutdowns; private readonly config; private readonly createWorker; private readonly getHeapUsedPercent; private readonly resolveIsolatedSsrRendererProvider; private shuttingDown; private shutdownPromise; private cleanupInterval; private healthCheckInterval; constructor(config?: Partial, dependencies?: WorkerPoolDependencies); /** * Get or create a worker for the given project. * * This is a low-level lookup without an admission lease. Production request * paths should use `execute` or `executeStream` so acquisition and work * registration are atomic with respect to eviction. */ getOrCreateWorker(projectId: string, readPaths: string[]): ProjectWorker; private getOrCreateWorkerForAdmission; /** * Execute a request in a project worker. Convenience method that * combines getOrCreateWorker + execute. */ execute(projectId: string, readPaths: string[], request: WorkerRequest): Promise; /** * Atomically admit and execute a streaming request. * * The pool admission is held until the worker protocol completes, or until * the consumer cancels or encounters an error. Already-buffered chunks remain * readable independently after protocol completion releases the admission. * This closes the get-or-create/execute gap for streaming callers. */ executeStream(projectId: string, readPaths: string[], request: RenderSSRRequest): ReadableStream; /** * Evict a specific project's worker. */ evictWorker(projectId: string): void; /** * Retire every worker belonging to one logical execution scope. * * Generation ownership is matched using the complete versioned, framed * identity, never a raw scope prefix. Busy generations finish their current * requests before eviction. */ evictWorkerScope(scopeId: string): void; /** Get pool statistics for monitoring. */ getStats(): { poolSize: number; maxPoolSize: number; workers: Record; }; /** * Get aggregate metrics suitable for Prometheus exposition. */ getMetrics(): { /** Current number of active workers */ workerPoolSize: number; /** Configured maximum worker count */ workerPoolCapacity: number; /** Total requests processed across all workers */ totalRequestsProcessed: number; /** Number of workers with pending requests (busy) */ busyWorkers: number; /** Number of crashed workers (cleaned up at next health check) */ crashedWorkers: number; }; /** * Shutdown the pool and wait for every managed worker to become quiescent. * Concurrent calls share one completion promise. */ shutdown(): Promise; private startCleanup; private startHealthChecks; private evictIdleWorkers; private ensureCapacityForAdmission; private validateRequestModulePaths; private admitRequest; private shouldRecycle; private recycleReason; private isTerminal; private isBusy; private completeRequest; private markPreparedModuleCapacityReached; private requestRetirement; private tryFinalizeRetirement; private settleRetirement; private handleWorkerIdle; private terminateEntry; private drainWorkerShutdowns; private createOverloadError; private checkHealth; /** * Best-effort idle-worker retirement under host-process heap pressure. * * This can drop pool references but cannot guarantee that retained ESM state * or top-level allocations are reclaimed. It is operational pressure relief, * not a per-worker memory limit. */ private evictUnderMemoryPressure; } /** What one isolation surface was asked for versus what it resolved to. */ export interface IsolationSurfacePosture { /** The operator set both the master switch and this surface's flag. */ requested: boolean; /** The resolved gate this surface's callers actually consult. */ effective: boolean; } /** * The resolved isolation configuration, as an operator would need to read it. * * `requested` and `effective` are separate fields so posture remains explicit * if a runtime capability changes. A host-execution grant never makes requested * API isolation ineffective: unsupported runtimes keep the gate enabled and * fail closed. `inForce` answers whether any surface is isolated at all. */ export interface IsolationPosture { /** WORKER_ISOLATION_ENABLED. On its own it enables no surface. */ master: boolean; api: IsolationSurfacePosture; data: IsolationSurfacePosture; ssr: IsolationSurfacePosture; /** * Whether this runtime can prepare isolated API route source at all * (security/sandbox/isolation-capability.ts). When false with * `api.effective` true, API routes fail closed rather than execute. */ apiPreparationSupported: boolean; /** VERYFRONT_HOST_ALLOW_PROJECT_EXECUTION. */ hostExecutionGranted: boolean; /** True when at least one surface actually resolved to isolated execution. */ inForce: boolean; } /** * The resolved isolation configuration, for the startup log. * * The boolean accessors below each answer for one surface and cannot tell an * operator that the configuration as a whole resolved to nothing. Resolves the * flags on first call, exactly as those accessors do. * * Do not publish this snapshot on an unauthenticated response such as * `/_health`: it tells an anonymous caller which realm tenant code runs in. */ export declare function getIsolationPosture(): IsolationPosture; /** * Whether worker isolation is enabled for API routes. * * Requires both WORKER_ISOLATION_ENABLED=1 and WORKER_ISOLATION_API=1. The * master switch alone enables no surface; see `getIsolationPosture`. */ export declare function isWorkerIsolationEnabled(): boolean; /** * The one place that decides which realm a project API route executes in. * * `routing/api/handler.ts` and both sites in `routing/api/route-executor.ts` * used to recompute this independently, which is why patching only the handler * moved the failure instead of removing it. */ export declare function isHostRealmApiExecution(allowHostProjectCodeExecution: boolean): boolean; /** * Whether worker isolation is enabled for data fetchers (getServerData). * Controlled by WORKER_ISOLATION_DATA=1 (requires WORKER_ISOLATION_ENABLED=1). */ export declare function isDataIsolationEnabled(): boolean; /** * Whether worker isolation is enabled for SSR rendering. * Controlled by WORKER_ISOLATION_SSR=1 (requires WORKER_ISOLATION_ENABLED=1). */ export declare function isSSRIsolationEnabled(): boolean; export declare function getWorkerPool(): WorkerPool; /** * Retire an existing worker scope without constructing the lazy singleton. * * Rendering/data owners call this when their source-generation cache is * invalidated or disposed. Active requests finish before retirement. */ export declare function evictWorkerScopeIfPresent(scopeId: string): void; /** * Reset the singleton and cached flags — for testing only. * * Callers must await the returned promise before changing worker-related host * configuration or starting another test so the detached pool is quiescent. */ export declare function __resetPoolForTests(): Promise; //# sourceMappingURL=worker-pool.d.ts.map