import { Observable } from 'rxjs'; /** * Configuration for creating a worker transport. * * IMPORTANT: Angular CLI's esbuild bundler only detects web workers when * `new Worker(new URL(...))` appears directly in application source code. * For pre-transpiled workers, use `workerUrl` instead. */ interface WorkerTransportConfig { /** * Factory function that creates a new Worker or SharedWorker instance. * The `new Worker(...)` or `new SharedWorker(...)` call MUST be in your app code * (not a library) for Angular CLI to bundle the worker correctly. * * @example * ```typescript * workerFactory: () => new Worker(new URL('./echo.worker.ts', import.meta.url), { type: 'module' }) * ``` */ workerFactory?: () => Worker | SharedWorker; /** * URL to a pre-transpiled worker file. * Use this when workers are built separately (e.g., with Vite) and distributed * as static assets. Resolves against the document's base URI. * * @example * ```typescript * workerUrl: 'assets/workers/echo.worker.js' * // or with full URL * workerUrl: new URL('workers/echo.worker.js', import.meta.url).href * ``` */ workerUrl?: string | URL; /** * Execution mode for the worker. * * - `'worker'` (default) — Dedicated Web Worker. Each tab has its own worker instance. * - `'shared'` — Shared Web Worker. Multiple tabs share the same worker instances. */ mode?: 'worker' | 'shared'; /** * Name for the SharedWorker. Required when `mode: 'shared'` to ensure multiple * tabs connect to the same worker instance. If `maxInstances > 1`, names are * suffixed with the instance index (e.g. `api-1`, `api-2`). */ sharedWorkerName?: string; /** Maximum number of worker instances in the pool (default: 1) */ maxInstances?: number; /** * Transfer strategy for `postMessage` payloads. * * - `'none'` (default) — payloads are always structured-cloned, preserving * the caller's access to the original data after post. * - `'auto'` — shallowly walks the payload and passes every detected * `Transferable` (ArrayBuffer, MessagePort, ImageBitmap, OffscreenCanvas, * ReadableStream, WritableStream, TransformStream) in the transfer list * of `postMessage`. Large buffers move zero-copy; their `byteLength` * becomes `0` in the main thread after post. * * The `'manual'` value is reserved for a future API where callers supply * their own transfer list per request. It currently behaves like `'none'`. */ transferDetection?: 'auto' | 'manual' | 'none'; /** * Per-request timeout in milliseconds. If the worker does not respond * within this window, `execute()` errors with `WorkerHttpTimeoutError` * and a cancel message is posted to the worker. Set to `0` or * non-finite to disable the timeout entirely. Default: `30000` (30 s). */ requestTimeout?: number; /** * Interval in milliseconds for sending heartbeat pings to Web Workers. * If `<= 0` or omitted, heartbeat monitoring is disabled. * @default 0 */ heartbeatInterval?: number; /** * Timeout in milliseconds to wait for a heartbeat pong before declaring the worker crashed/OOM. * @default 2000 */ heartbeatTimeout?: number; /** * Optional handshake message posted to every worker as soon as it is * created, BEFORE any request. Useful to ship runtime configuration * (e.g. interceptor specs) that the worker uses to build its pipeline. * * The shape is opaque to the transport — the worker is responsible for * recognising and acting on it. */ initMessage?: { type: string; [key: string]: unknown; }; /** * Enable Safari streams polyfill for transferable ReadableStream/TransformStream * support. When `true`, the transport lazy-loads the ponyfill on Safari 16-17 * to enable stream transfer via postMessage. * * @default false */ streamsPolyfill?: boolean; } /** * Message sent from main thread to worker. */ interface WorkerMessage { type: 'request' | 'cancel' | 'ping'; requestId: string; payload?: TPayload; transferables?: Transferable[]; } /** * Successful response from worker to main thread. */ interface WorkerResponse { type: 'response' | 'pong'; requestId: string; result: TResult; transferables?: Transferable[]; } /** * Error response from worker to main thread. */ interface WorkerErrorResponse { type: 'error'; requestId: string; error: { message: string; name: string; stack?: string; status?: number; statusText?: string; }; } /** * Per-request options accepted by `WorkerTransport.execute()`. * * - `signal` — external `AbortSignal`. When it fires, the transport posts a * `cancel` message to the worker and rejects the Observable with * `WorkerHttpAbortError`. * - `timeout` — overrides the transport-level `requestTimeout` for this single * call. `0` or non-finite disables the timeout for this request. */ interface WorkerExecuteOptions { signal?: AbortSignal; timeout?: number; } /** * Typed transport interface for communicating with a web worker. * Observable-based: unsubscribing sends a cancel message to the worker. */ interface WorkerTransport { /** Send a request to the worker and get an Observable response */ execute(request: TRequest, options?: WorkerExecuteOptions): Observable; /** Terminate all workers and release resources */ terminate(): void; /** Whether the transport has active workers */ readonly isActive: boolean; /** Number of currently active worker instances */ readonly activeInstances: number; /** Observable exposing the status of the worker pool health */ readonly status$: Observable<'healthy' | 'degraded' | 'unsupported'>; } /** * Creates a typed, Observable-based transport for communicating with a web worker. */ declare function createWorkerTransport(config: WorkerTransportConfig): WorkerTransport; /** * Thrown by `createWorkerTransport` when a request exceeds its configured * `requestTimeout`. Consumers can `instanceof`-check this error to distinguish * timeout rejections from transport/worker errors. * * @example * ```typescript * transport.execute(req).subscribe({ * error: (err) => { * if (err instanceof WorkerHttpTimeoutError) { * // dedicated timeout handling * } * }, * }); * ``` */ declare class WorkerHttpTimeoutError extends Error { readonly name = "WorkerHttpTimeoutError"; readonly timeoutMs: number; constructor(timeoutMs: number); } /** * Thrown by `createWorkerTransport` when a request is aborted via an external * `AbortSignal` passed to `execute(request, { signal })`. * * Distinct from `WorkerHttpTimeoutError` (which fires when the per-request * `timeout` elapses) and from a silent unsubscribe (which sends a `cancel` * message but does not surface an error to the subscriber, since RxJS already * tore down the stream). * * @example * ```typescript * const ac = new AbortController(); * transport.execute(req, { signal: ac.signal }).subscribe({ * error: (err) => { * if (err instanceof WorkerHttpAbortError) { * // user-driven cancellation; usually safe to ignore in UI * } * }, * }); * ac.abort('user navigated away'); * ``` */ declare class WorkerHttpAbortError extends Error { readonly name = "WorkerHttpAbortError"; /** The reason passed to `AbortController.abort(reason)`, if any. */ readonly reason: unknown; constructor(reason?: unknown); } /** * Scans a payload one level deep and collects every `Transferable` instance * (ArrayBuffer, MessagePort, ImageBitmap, OffscreenCanvas, ReadableStream, * WritableStream, TransformStream) found in its own enumerable properties. * * Used by `createWorkerTransport` when `transferDetection === 'auto'` to build * the second argument of `worker.postMessage(data, transfer)` so large buffers * move zero-copy instead of being structured-cloned. * * Design notes: * - Only one level deep by design: deep traversal has quadratic cost on heavy * graphs and makes the transfer list surprising. Real payloads that care * about zero-copy put the buffer at the top level. * - Duplicates are filtered — the same buffer referenced twice is transferred * only once (required by the structured-clone algorithm). * - Returns an empty array for primitives, plain serializable values, or when * no transferable is found; `postMessage` accepts `[]` safely. */ declare function detectTransferables(payload: unknown): Transferable[]; /** * Common interface for communication ports. * Unifies Worker and SharedWorker (MessagePort). */ interface TransportPort { postMessage(message: any, transfer?: Transferable[]): void; addEventListener(type: string, listener: any): void; removeEventListener(type: string, listener: any): void; terminate?(): void; start?(): void; } /** * Wraps a Worker or SharedWorker into a unified TransportPort interface. */ declare function wrapWorker(worker: Worker | SharedWorker): TransportPort; export { WorkerHttpAbortError, WorkerHttpTimeoutError, createWorkerTransport, detectTransferables, wrapWorker }; export type { TransportPort, WorkerErrorResponse, WorkerExecuteOptions, WorkerMessage, WorkerResponse, WorkerTransport, WorkerTransportConfig };