Files
2026-05-27 23:47:53 +01:00

2.6 KiB

internals

Purpose

internals.ts holds the small internal types and helpers worker-pool.ts needs but that don't make sense to surface in the public API: the PoolSlot bookkeeping shape, the QueuedTask entry used while tasks wait for a free worker, and the slotConfig helper that materialises a WorkerConfig for a slot from the WorkerPoolConfig.

Splitting these out keeps the main pool file under the 300-line ceiling and makes the internal shapes independently importable from a sibling helper file or future selector.

Features

  • PoolSlot — per-slot mutable record: name, restarts, pendingCount.
  • QueuedTask — pending submit waiting for a worker: type, payload, options, resolve, reject.
  • slotConfig(poolConfig, name, defaultTimeoutMs) — builds a complete WorkerConfig while respecting exactOptionalPropertyTypes (no undefined-valued keys leak through).

Usage: Basic Example

import { slotConfig } from "@suaveplan/web-workers";

const cfg = slotConfig(
    { url: WORKER_URL, size: 4, taskTimeout: 10_000 },
    "pool-0-abc",
    30_000
);
// cfg === { name: "pool-0-abc", url: WORKER_URL, timeout: 10_000 }

Usage: Advanced Example

import { slotConfig } from "@suaveplan/web-workers";

const cfg = slotConfig(
    {
        url: WORKER_URL,
        size: 2,
        type: "module",
        maxPendingRequests: 64,
        circuitBreaker: { failureThreshold: 3, resetMs: 30_000 },
    },
    "pool-1-xyz",
    30_000
);
// cfg.type === "module"
// cfg.maxPendingRequests === 64
// cfg.circuitBreaker is the same object reference

API Reference

  • interface PoolSlot { readonly name: string; restarts: number; pendingCount: number }.
  • interface QueuedTask { type, payload, options, resolve, reject }.
  • slotConfig(poolConfig: WorkerPoolConfig, name: string, defaultTimeoutMs: number): WorkerConfig.

Implementation Notes

slotConfig builds the target object incrementally rather than via conditional-spread syntax (...(x !== undefined ? { x } : {})) because the spread version flagged uncovered branches in istanbul that couldn't be exercised once the spread expanded to an empty object. The incremental if (x !== undefined) cfg.x = x form has the same semantics under exactOptionalPropertyTypes (the key is absent rather than undefined-valued) but every branch is reachable from a single test that exercises the optional config field. The cast -readonly [K in keyof WorkerConfig]: WorkerConfig[K] is used to allow incremental assignment of readonly fields on the local variable, then the value is widened back to WorkerConfig at return.