/** * Persistent-worker regex evaluator with per-batch timeout (mmnto-ai/totem#1641). * * Spawns one Node worker thread on construction, serializes batches onto * it, and enforces a main-thread timeout. If a pattern catastrophic- * backtracks inside the worker, the main-thread timer fires, calls * `worker.terminate()`, and respawns a fresh worker for the next batch. * Every evaluation resolves with one of three outcomes — `ok` (matched * indices + elapsed + softWarning flag), `timeout` (the worker was * terminated), or `error` (the pattern was syntactically invalid; the * worker is still alive). The caller decides strict vs lenient handling. * * Invariants: * - At most one `Worker` alive per evaluator instance. * - `pending` never holds stale entries past a batch's terminal state. * - Batches are serialized (one in-flight at a time) — no multiplexing. * - Telemetry is emitted on every terminal outcome via the * `onTelemetry` callback the caller supplies; if absent, telemetry * is silently dropped (safe — the evaluator itself never fails on * telemetry-sink failure). */ import type { RegexTelemetry } from './telemetry.js'; export interface RegexEvaluatorConfig { /** Hard timeout per batch (ms). Exceeded batches terminate the worker. */ timeoutMs: number; /** Soft-warning threshold (ms). Sub-timeout but slow; sets the flag on telemetry. */ softWarningMs: number; } export interface EvaluateInput { ruleHash: string; pattern: string; flags: string; lines: readonly string[]; } export type EvaluateResult = { kind: 'ok'; matchedIndices: number[]; elapsedMs: number; softWarningTriggered: boolean; } | { kind: 'timeout'; elapsedMs: number; } | { kind: 'error'; message: string; elapsedMs: number; }; export declare class RegexEvaluator { private worker; private readonly pending; private readonly config; private readonly onTelemetry; private queue; private disposed; /** * Coalesces concurrent respawn requests (mmnto-ai/totem#1641 Shield review * round-1). Without this, a timeout event firing at roughly the same * moment as a worker `error` event can call `spawnWorker()` twice, * leaking a thread. `evaluate()` also awaits this promise before * `postMessage` so a batch scheduled during a respawn waits for the * new worker instead of silently dropping against a null handle. */ private respawnPromise; /** * Worker-online gate (mmnto-ai/totem#1641, CI round-1 fix). The Node * `Worker` constructor returns before the thread is actually running * (thread-spawn takes ~30-50ms). If `evaluate()` starts its timeout * timer before the worker is online, a slow CI box can trip a * spurious timeout on the first batch. Gate postMessage on this * promise so cold-start cost never counts against the budget. */ private workerReady; /** * Consecutive-respawn counter (Shield review round-1). If the worker * keeps dying at spawn time (missing worker.js, syntax error in the * worker script, etc.), unbounded respawn becomes a CPU-pegging loop. * The counter increments on each respawn, resets on every successful * evaluation, and flips `permanentlyFailed` once the budget is spent. */ private consecutiveRespawns; private permanentlyFailed; private static readonly MAX_CONSECUTIVE_RESPAWNS; constructor(config?: Partial, onTelemetry?: (record: RegexTelemetry) => void); evaluate(input: EvaluateInput & { redactedPath?: string; }): Promise; dispose(): Promise; private evaluateOnce; private spawnWorker; private respawnWorker; private handleMessage; private rejectAllPendingAsCrash; private emitTelemetry; } //# sourceMappingURL=evaluator.d.ts.map