/** * @license * Copyright 2025 Steven Roussey * SPDX-License-Identifier: Apache-2.0 */ /** Service token for the platform-specific WorkerServer instance. */ export declare const WORKER_SERVER: import("../di").ServiceToken; /** * Construction-time options for {@link WorkerServerBase}. * * All fields are optional and safe to omit — defaults match the previous * hard-coded values. * * Reachable only via `new WorkerServerBase(...)` directly (used by tests * that exercise eviction-path behaviour with a tiny cap). The platform- * specific `WorkerServer` subclasses (`Worker.bun.ts`, `Worker.node.ts`, * `Worker.browser.ts`) currently have zero-arg constructors and use the * defaults; `new WorkerServer({ pendingAbortHardCap: ... })` will NOT * compile against those subclasses. To override in production either * bypass the subclass or extend it with a forwarding constructor. */ export interface WorkerServerBaseOptions { /** * Maximum number of pending-abort markers retained in memory. Once the * `pendingAborts` map exceeds this cap, the oldest-by-timestamp half is * evicted in one pass — a memory safety-net for pathological abort bursts * that outrun the per-id TTL timers. Defaults to `10_000`. * * Exposed as an option primarily as a test seam: tests that exercise the * overflow eviction path can use a tiny cap (e.g. `100`) and insert ~110 * entries in milliseconds instead of pushing 10,010 entries through * vitest's fake-timer heap. */ readonly pendingAbortHardCap?: number; } /** * WorkerServerBase is a class that handles messages from the main thread to the worker. * It is used to register functions that can be called from the main thread. * It also handles the transfer of transferables to the main thread. */ export declare class WorkerServerBase { constructor(options?: WorkerServerBaseOptions); private static readonly PENDING_ABORT_TTL_MS; private static readonly PENDING_ABORT_HARD_CAP; /** * Per-instance hard cap on `pendingAborts` map size. Initialised from the * constructor option (defaults to {@link PENDING_ABORT_HARD_CAP}). */ private readonly pendingAbortHardCap; private functions; private streamFunctions; private runFunctions; private previewFunctions; private requestControllers; private completedRequests; private pendingAborts; /** * Per-id TTL-cleanup timer handles, keyed by request id. The contract: * - Exactly one timer per live entry in `pendingAborts`. `recordPendingAbort` * clears any prior timer for the same id before scheduling a new one, so * a re-recorded abort always gets a full fresh TTL (previously the stale * timer would still fire and delete the renewed entry early). * - `consumePendingAbort` clears and removes the timer when it consumes * (or treats as expired) a pending marker, so a consumed id never has * a stale timer queued. * - The hard-cap eviction path in `recordPendingAbort` also clears the * timer for each evicted id, bounding timer-handle memory together * with `pendingAborts` itself. * - The TTL-fire callback removes its own entry by id. */ private pendingAbortTimers; private postResult; private postError; private postStreamChunk; /** * Send the ready message to the main thread, advertising which functions are * registered in each category. Call this after all functions have been registered * so WorkerManager can skip unnecessary roundtrips for unregistered calls. */ sendReady(): void; registerFunction(name: string, fn: (...args: any[]) => Promise): void; /** * Register a preview function for lightweight preview execution. * Preview functions receive (input, model) and return a fast preview * without progress tracking or abort signals. * * @param name - The function name (e.g., task type identifier) * @param fn - Async function: (input, model) => Promise */ registerPreviewFunction(name: string, fn: (input: any, model: any) => Promise): void; /** * Register an async generator function for streaming execution. * When called via the worker protocol with `stream: true`, the server * iterates the generator and sends each yielded value as a `stream_chunk` * message, followed by a `complete` message when the generator finishes. * * @param name - The function name (e.g., task type identifier) * @param fn - Async generator function: (input, model, signal) => AsyncIterable */ registerStreamFunction(name: string, fn: (...args: any[]) => AsyncIterable): void; /** * Register a Promise+emit run function for the new run-fn shape. The function * receives an `emit` callback that posts events as `stream_chunk` messages on * the worker port and resolves with no value when complete. Use this in place * of {@link registerStreamFunction} for newly-ported provider run-fns. */ registerRunFunction(name: string, fn: (input: unknown, model: unknown, signal: AbortSignal, emit: (event: unknown) => void, outputSchema?: unknown, sessionId?: string) => Promise): void; handleMessage(event: { type: string; data: any; }): Promise; handleAbort(id: string): Promise; /** * If a prior `abort` arrived for `id` before the call started, and that * abort is still within the TTL window, abort the supplied controller * immediately and drop the pending marker. Returns `true` when an abort * was consumed so callers may exit fast. Expired markers are silently * dropped (returns `false`). * * Always clears the per-id TTL timer from {@link pendingAbortTimers} * before returning, regardless of whether the marker was live or * expired — once a marker is consumed (or proven stale) its timer is * stale too and should not fire later. */ private consumePendingAbort; /** * Records `id` as having received an abort that has not yet been matched * to a controller. Stores a wall-clock timestamp so entries are evicted * by TTL (see {@link PENDING_ABORT_TTL_MS}) rather than by insertion * order — a noisy/malicious client spamming aborts can no longer evict * a legitimate pending abort before its matching `call` arrives. * * Cleanup strategy (amortised O(1) per call, no inline sweep): * - A per-id `setTimeout` (tracked in {@link pendingAbortTimers}, * keyed by id) drops this entry once TTL elapses. If `id` already * had a queued timer from a prior `recordPendingAbort`, that timer * is `clearTimeout`'d first so the renewed marker gets a full * fresh TTL rather than inheriting the stale +TTL of the original. * - {@link consumePendingAbort} re-checks the timestamp at consume * time and also clears the per-id timer so it can't fire later * against an unrelated id. * - If the map exceeds {@link pendingAbortHardCap}, the oldest half * is evicted in one pass; each evicted id also has its timer * cleared, so timer-handle memory is bounded together with the * data map. */ private recordPendingAbort; /** * Handle a preview call. Returns undefined (non-error) if the preview * function is not registered, since not all task types expose a preview fn. */ handlePreviewCall(id: string, functionName: string, [input, model]: [any, any]): Promise; handleCall(id: string, functionName: string, [input, model]: [any, any]): Promise; /** * Handle a streaming call. If a stream function is registered for the given name, * iterate it and send each yielded event as a `stream_chunk` message. If only a * regular function is registered, run it and wrap the result as a single `finish` * stream event (graceful fallback for providers that don't implement streaming). */ handleStreamCall(id: string, functionName: string, [input, model]: [any, any]): Promise; /** * Handle a Promise+emit run call. Resolves to `undefined` when the run-fn * settles; emitted events are forwarded as `stream_chunk` messages. This is * the new run-fn shape that replaces async-generator stream functions. */ handleRunCall(id: string, functionName: string, [input, model, outputSchema, sessionId]: [any, any, any, any]): Promise; /** * Schedule cleanup of a completed request ID. Uses a 5-second delay to * handle late-arriving abort messages, and caps the completed set size at * {@link COMPLETED_REQUESTS_HARD_CAP} entries to prevent unbounded growth. As in * {@link recordPendingAbort}, the eviction list is snapshotted via * `Array.from` before deletion to avoid iterating-while-deleting. */ private scheduleCompletedRequestCleanup; } //# sourceMappingURL=WorkerServerBase.d.ts.map